diff --git a/.gitignore b/.gitignore index 7e47b68..1efbe81 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dist *.iml +flowplayer.swc diff --git a/README.md b/README.md index 0e3ba00..7dd3b74 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ - # Flowplayer Flash @@ -22,6 +21,8 @@ This is Flowplayer Flash. Flowplayer 5 for HTML5 will be out soon. Follow [these instructions](http://flowplayer.org/documentation/developer/development-environment.html). +Addtionally for versions above 3.2.16, check out the [Flash builder](https://github.com/flowplayer/flash-build/) in the same tree as the Flash sources. + ## License The Flowplayer Free version is released under the diff --git a/core/LICENSE_UNLIMITED.txt b/core/LICENSE_UNLIMITED.txt index 6b26d22..60bb839 100644 --- a/core/LICENSE_UNLIMITED.txt +++ b/core/LICENSE_UNLIMITED.txt @@ -1,3 +1,3 @@ Flowplayer Unlimited license terms are available in this page: -http://flowplayer.org/download/licenses/license_unlimited.htm \ No newline at end of file +http://flowplayer.org/license/unlimited.html \ No newline at end of file diff --git a/core/README.txt b/core/README.txt index 1375e00..62e9422 100644 --- a/core/README.txt +++ b/core/README.txt @@ -1,7 +1,36 @@ Version history: +3.2.17 +------ +- #75 set the child display list different when a gradient is set. +- The clip property 'bufferLength' now accepts decimal values, for example bufferLength: 0.2 +- #121 XSS fix: Only load plugins and external config from the same domain as the player swf is loaded from +- Made it possible to tab out of the player and into the HTML page using the keyboard alone. +- Change links in the context menu and in the logos to point to http://flash.flowplayer.org +- Pausing a live stream now leaves the video frame visible #81 +- Audio plugin is not loaded nor used when the the provider is set excplicitly in the clip to a non-audio value, for + example to 'http' +- Allow playing another instream clip while already playing one. Issue #131 +- Fixed memory leaks related to repeatedly starting playback with the play() API method. #163 + 3.2.16 ------ +- new clip event onMetadataChange, dispatched for example when switching bitrate + +Fixes: + +- Shows logo in accelerated mode #20 +- mid-rolls freeze if multiple providers are used #42 +- onFire fired twice on replay #52 +- rtmp + hw accel + instream clips lose video, or aspect ratio #44 +- URL name parts containing semi-colons (;) should pass validation through linkUrl usage #53 +- cuepoints fired multiple times with the bitrateselect plugin #50 +- fix for dispatching onBegin in certain situations +- if onStart has been dispatched already prevent dispatching many onBegin events + + +3.2.15 +------ - #15 fixes for #627, handle the display init on startup. - #615 dispatch begin if in paused mode too early. - #629 if start has been dispatched already prevent dispatching many begin events. @@ -10,11 +39,11 @@ Version history: - #52 when replaying flag start has dispatched on the current clip. - #44 fixes for #627 check if the stagevideo dimensions and positioning has changed to update the stage video mask with. - unbinding and binding stage video events caused issues with instream playlists therefore has to be kept binded. - unbinded stage video events during seeking to prevent the mask repositioning. +- unbinded stage video events during seeking to prevent the mask repositioning. - #53 update url filter to accomodate for pretty urls with semi colons. - #50 if we have metadata already set it is being updated during seeks and switching, dispatch metadata change events instead. -3.2.15 +3.2.14 ------ - #614 when the clip ends if the next clip in the provider has a different provider close the provider stream. - #627 only detach / attach the display on start events which causes issues in buffering events after a seek in stagevideo. diff --git a/core/build.properties b/core/build.properties deleted file mode 100644 index 2ef5d3a..0000000 --- a/core/build.properties +++ /dev/null @@ -1,65 +0,0 @@ - -# you need to adjust following to point to your Flex SDK -flexdir=/Users/Api/flex_sdk_4.5.0.19786 - -# change following to point to .exe files when running on Windows -mxmlc_bin= ${flexbindir}/mxmlc -compc_bin= ${flexbindir}/compc -asdoc_bin= /Users/Api/flex_sdk_3/bin/asdoc - -devkit-dir=../lib/devkit -plugins.dir=../plugins -lib.dir=../lib - -site.dir=/Users/api/hyde/site -js.deploy.dir=${site.dir}/deploy/js -deploy.dir=${site.dir}/content/swf - -#plugin.buildfiles=rtmp/build.xml -# - -# 3.2.16 -plugin.buildfiles=rtmp/build.xml,controls/build.xml,controls/build-tube.xml,controls/build-air.xml,controls/build-skinless.xml, \ - sharing/build.xml,viralvideos/build.xml,bitrateselect/build.xml,bwcheck/build.xml,bwcheck/build-httpstreaming.xml \ - httpstreaming/build.xml,menu/build.xml,pseudostreaming/build.xml -# -#plugin.buildfiles=analytics/build.xml,audio/build.xml,bwcheck/build.xml,bwcheck/build-httpstreaming.xml \ -# captions/build.xml,content/build.xml,controls/build.xml,controls/build-tube.xml,controls/build-air.xml,controls/build-skinless.xml, \ -# f4m/build.xml,httpstreaming/build.xml,pseudostreaming/build.xml,rtmp/build.xml,securestreaming/build.xml, \ -# sharing/build.xml,slowmotion/build.xml,smil/build.xml,viralvideos/build.xml, \ -# bitrateselect/build.xml,menu/build.xml,cluster/build.xml -# all plugins -allplugins.buildfiles=analytics/build.xml,audio/build.xml,bwcheck/build.xml,bwcheck/build-httpstreaming.xml \ - captions/build.xml,content/build.xml,controls/build.xml,controls/build-tube.xml,controls/build-air.xml,controls/build-skinless.xml, \ - f4m/build.xml,httpstreaming/build.xml,pseudostreaming/build.xml,rtmp/build.xml,securestreaming/build.xml, \ - sharing/build.xml,slowmotion/build.xml,smil/build.xml,viralvideos/build.xml,securedrm/build.xml, \ - bitrateselect/build.xml,menu/build.xml,cluster/build.xml - -jsplugins.buildfiles=controls/build.xml,embed/build.xml,ipad/build.xml,playlist/build.xml,bitrateselect/build.xml - -cloudfront.version=1.0 -adsense.version=flowplayer.org-1.6.1 - -# for plugins that can be built inside the player -plugin-classes=${plugins.dir}/controls/src/actionscript ${lib.dir}/common/src/actionscript -#plugin-classes=${plugins.dir}/controls/src/actionscript ${plugins.dir}/pseudostreaming/src/actionscript \ -# ${plugins.dir}/rtmp/src/actionscript \ -# ${lib.dir}/common/src/actionscript - -plugin-swc=${plugins.dir}/controls/src/flash ${plugins.dir}/pseudostreaming/lib - -controls-dir=${plugins.dir}/controls -compiler.defines= - -# following can usually be left as they are -flexbindir=${flexdir}/bin -flexlibsdir=${flexdir}/frameworks/libs -flashplayer_bin= -framerate=24 -bgcolor=0xFFFFFF -width=500 -height=350 - -# Flash Player targets -flash.use.10.1=true -flash.target.player=10.2.0 diff --git a/core/build.xml b/core/build.xml deleted file mode 100644 index a25281a..0000000 --- a/core/build.xml +++ /dev/null @@ -1,573 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core/lib/corelib/src/com/adobe/serialization/json/JSON.as b/core/lib/corelib/src/com/adobe/serialization/json/JSONforFP.as similarity index 99% rename from core/lib/corelib/src/com/adobe/serialization/json/JSON.as rename to core/lib/corelib/src/com/adobe/serialization/json/JSONforFP.as index 1d2477e..eb2c331 100644 --- a/core/lib/corelib/src/com/adobe/serialization/json/JSON.as +++ b/core/lib/corelib/src/com/adobe/serialization/json/JSONforFP.as @@ -47,7 +47,7 @@ package com.adobe.serialization.json { * var myObject:Object = JSON.decode( jsonString ); * */ - public class JSON { + public class JSONforFP { /** diff --git a/core/lib/goasp/src_go/org/goasap/items/LinearGo.as b/core/lib/goasp/src_go/org/goasap/items/LinearGo.as index ceaa859..6d350c9 100755 --- a/core/lib/goasp/src_go/org/goasap/items/LinearGo.as +++ b/core/lib/goasp/src_go/org/goasap/items/LinearGo.as @@ -20,13 +20,14 @@ * THE SOFTWARE. */ package org.goasap.items { - import flash.utils.getTimer; + + import flash.utils.getTimer; import org.goasap.GoEngine; import org.goasap.errors.EasingFormatError; import org.goasap.events.GoEvent; import org.goasap.interfaces.IPlayable; - import org.goasap.managers.LinearGoRepeater; + import org.goasap.managers.LinearGoRepeater; /** * Dispatched during an animation's first update after the delay @@ -262,13 +263,14 @@ package org.goasap.items { } public function set easing(type:Function):void { if (_state==STOPPED) { - try { + //try { if (type(1,1,1,1) is Number) { _easing = type; return; } - } catch (e:Error) {} - throw new EasingFormatError(); + //} catch (e:Error) {} + //#163 don't throw an error just because. + //throw new EasingFormatError(); } } @@ -496,18 +498,25 @@ package org.goasap.items { defaultDelay = 0; if (isNaN(defaultDuration)) defaultDuration = 1; - try { this.easing = defaultEasing; } - catch (e1:EasingFormatError) { defaultEasing = easeOut; } + /*try { this.easing = defaultEasing; } + catch (e1:EasingFormatError) { defaultEasing = easeOut; } */ + + //#163 set default easing + this.easing = easeOut; // set params if (!isNaN(delay)) _delay = delay; else _delay = defaultDelay; if (!isNaN(duration)) _duration = duration; else _duration = defaultDuration; - try { this.easing = easing; } + /*try { this.easing = easing; } catch (e2:EasingFormatError) { if (easing!=null) { throw e2; } // user passed invalid easing function this.easing = defaultEasing; - } + }*/ + //if (easing && easing) + //#163 set easing if enabled on the argument, not needed for normal Flowplayer animations. + if (easing!=null) this.easing = easing; + if (extraEasingParams) _extraEaseParams = extraEasingParams; if (useRelative) this.useRelative = true; if (useRounding) this.useRounding = true; diff --git a/core/lib/licensekey/licensekey.swc b/core/lib/licensekey/licensekey.swc index 59ed3ab..60f500a 100644 Binary files a/core/lib/licensekey/licensekey.swc and b/core/lib/licensekey/licensekey.swc differ diff --git a/core/manifest.xml b/core/manifest.xml deleted file mode 100644 index 67fce13..0000000 --- a/core/manifest.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/release.xml b/core/release.xml deleted file mode 100644 index 02ecf46..0000000 --- a/core/release.xml +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <a href="http://flowplayer-releases.s3.amazonaws.com/flowplayer/flowplayer.zip">flowplayer.zip</a> <br /> - - <a href="http://flowplayer-releases.s3.amazonaws.com/flowplayer/flowplayer.commercial.zip">flowplayer.commercial.zip</a> <br /> - - <a href="http://flowplayer-releases.s3.amazonaws.com/flowplayer/flowplayer-src.zip">flowplayer-src.zip</a> <br /> - - - - - - -<br /> -<a href="http://flowplayer-releases.s3.amazonaws.com/latest.zip">latest.zip: All latest dev-version swf files in one zip</a> <br /> - <br /> - Build time: ${build.time} GMT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core/src/actionscript-commercial/org/flowplayer/view/ContextMenuBuilder.as b/core/src/actionscript-commercial/org/flowplayer/view/ContextMenuBuilder.as index bd0a43c..7c7f93f 100644 --- a/core/src/actionscript-commercial/org/flowplayer/view/ContextMenuBuilder.as +++ b/core/src/actionscript-commercial/org/flowplayer/view/ContextMenuBuilder.as @@ -106,7 +106,7 @@ package org.flowplayer.view { private function buildMenu(menu:ContextMenu):ContextMenu { addItem(menu, new ContextMenuItem("About " +VersionInfo.versionInfo()+ "...", false, true), function(event:ContextMenuEvent):void { - navigateToURL(new URLRequest("http://flowplayer.org"), "_self"); + navigateToURL(new URLRequest("http://flash.flowplayer.org"), "_self"); }); // 1-3 Required by the GPL license // 1 copyright notice diff --git a/core/src/actionscript-commercial/org/flowplayer/view/LicenseKey.as b/core/src/actionscript-commercial/org/flowplayer/view/LicenseKey.as index b6e59b0..6ba9a70 100644 --- a/core/src/actionscript-commercial/org/flowplayer/view/LicenseKey.as +++ b/core/src/actionscript-commercial/org/flowplayer/view/LicenseKey.as @@ -31,7 +31,7 @@ package org.flowplayer.view { public static function validate(swfUrl:String, version:Array, configuredKeys:Object, externalInterfaceAvailable:Boolean):Boolean { trace("using validator " + FlowplayerLicenseKey.id); - return FlowplayerLicenseKey.validate(swfUrl, version, configuredKeys, externalInterfaceAvailable); + return FlowplayerLicenseKey.validate(swfUrl, version, configuredKeys, (CONFIG::secondaryDomains).split(" "), externalInterfaceAvailable); } } diff --git a/core/src/actionscript-commercial/org/flowplayer/view/LogoView.as b/core/src/actionscript-commercial/org/flowplayer/view/LogoView.as index 6c62674..f7e5003 100644 --- a/core/src/actionscript-commercial/org/flowplayer/view/LogoView.as +++ b/core/src/actionscript-commercial/org/flowplayer/view/LogoView.as @@ -286,14 +286,18 @@ package org.flowplayer.view { private function startTimer():void { _hideTimer = new Timer(_model.displayTime * 1000, 1); - _hideTimer.addEventListener(TimerEvent.TIMER_COMPLETE, - function(event:TimerEvent):void { - log.debug("display time complete"); - hide(_model.fadeSpeed); - _hideTimer.stop(); - }); + _hideTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onHideComplete); _hideTimer.start(); } + + private function onHideComplete(event:TimerEvent):void + { + log.debug("display time complete"); + hide(_model.fadeSpeed); + _hideTimer.reset(); + _hideTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onHideComplete); + _hideTimer = null; + } CONFIG::freeVersion public function setModel(model:Logo):void { @@ -306,7 +310,7 @@ package org.flowplayer.view { _model.top = "20"; _model.right = "20"; _model.opacity = 0.3; - _model.linkUrl = "http://flowplayer.org"; + _model.linkUrl = "http://flash.flowplayer.org"; log.debug("initial model dimensions " + _model.dimensions); } diff --git a/core/src/actionscript-commercial/org/flowplayer/view/PlayButtonOverlayView.as b/core/src/actionscript-commercial/org/flowplayer/view/PlayButtonOverlayView.as index 73c8fbd..3dc6539 100644 --- a/core/src/actionscript-commercial/org/flowplayer/view/PlayButtonOverlayView.as +++ b/core/src/actionscript-commercial/org/flowplayer/view/PlayButtonOverlayView.as @@ -57,6 +57,7 @@ package org.flowplayer.view { private var _play:PlayButtonOverlay; private var _rotation:RotatingAnimation; private var _playDetectTimer:Timer; + private var _startTime:Number; public function PlayButtonOverlayView(resizeToTextWidth:Boolean, play:PlayButtonOverlay, pluginRegistry:PluginRegistry) { _resizeToTextWidth = resizeToTextWidth; @@ -464,10 +465,10 @@ package org.flowplayer.view { private function bufferUntilStarted(event:ClipEvent = null):void { if (event && event.isDefaultPrevented()) return; startBuffering(); - createPlaybackStartedCallback(stopBuffering); + createPlaybackStartedCallback(); } - private function createPlaybackStartedCallback(callback:Function):void { + private function createPlaybackStartedCallback():void { log.debug("detectPlayback()"); if (! _player.isPlaying()) { @@ -479,24 +480,30 @@ package org.flowplayer.view { return; } - var time:Number = _player.status.time; + _startTime = _player.status.time; _playDetectTimer = new Timer(200); - _playDetectTimer.addEventListener(TimerEvent.TIMER, - function(event:TimerEvent):void { - var currentTime:Number = _player.status.time; - log.debug("on detectPlayback() currentTime " + currentTime + ", time " + time); - - if (Math.abs(currentTime - time) > 0.2) { - _playDetectTimer.stop(); - log.debug("playback started"); - callback(); - } else { - log.debug("not started yet, currentTime " + currentTime + ", time " + time); - } - }); + _playDetectTimer.addEventListener(TimerEvent.TIMER,onPlayDetect); log.debug("doStart(), starting timer"); _playDetectTimer.start(); } + + //#163 move play detect timer to external listener and clear when done. + private function onPlayDetect(event:TimerEvent):void + { + var currentTime:Number = _player.status.time; + log.debug("on detectPlayback() currentTime " + currentTime + ", time " + _startTime); + + if (Math.abs(currentTime - _startTime) > 0.2) { + stopBuffering(); + _playDetectTimer.stop(); + _playDetectTimer.removeEventListener(TimerEvent.TIMER,onPlayDetect); + _playDetectTimer = null; + _startTime = NaN; + log.debug("playback started"); + } else { + log.debug("not started yet, currentTime " + currentTime + ", time " + _startTime); + } + } } } diff --git a/core/src/actionscript/org/flowplayer/config/ConfigParser.as b/core/src/actionscript/org/flowplayer/config/ConfigParser.as index 7a7c292..9086c59 100644 --- a/core/src/actionscript/org/flowplayer/config/ConfigParser.as +++ b/core/src/actionscript/org/flowplayer/config/ConfigParser.as @@ -21,7 +21,7 @@ package org.flowplayer.config { import org.flowplayer.controller.ResourceLoader; import org.flowplayer.flow_internal; import org.flowplayer.util.Log; - import com.adobe.serialization.json.JSON; + import com.adobe.serialization.json.JSONforFP; use namespace flow_internal; @@ -33,12 +33,12 @@ package org.flowplayer.config { flow_internal static function parse(config:String):Object { //#590 add full package reference to work with Flex 4.6 - return com.adobe.serialization.json.JSON.decode(config); + return com.adobe.serialization.json.JSONforFP.decode(config); } flow_internal static function parseConfig(config:Object, builtInConfig:Object, playerSwfUrl:String, controlsVersion:String, audioVersion:String):Config { if (!config) return new Config({}, builtInConfig, playerSwfUrl, controlsVersion, audioVersion); - var configObj:Object = config is String ? com.adobe.serialization.json.JSON.decode(config as String) : config; + var configObj:Object = config is String ? com.adobe.serialization.json.JSONforFP.decode(config as String) : config; return new Config(configObj, builtInConfig, playerSwfUrl, controlsVersion, audioVersion); } diff --git a/core/src/actionscript/org/flowplayer/controller/AbstractDurationTrackingController.as b/core/src/actionscript/org/flowplayer/controller/AbstractDurationTrackingController.as index 80c8dff..005d178 100644 --- a/core/src/actionscript/org/flowplayer/controller/AbstractDurationTrackingController.as +++ b/core/src/actionscript/org/flowplayer/controller/AbstractDurationTrackingController.as @@ -84,13 +84,20 @@ package org.flowplayer.controller { private function createDurationTracker(clip:Clip):void { if (durationTracker) { - durationTracker.stop(); + clearDurationTracker(); } durationTracker = new PlayTimeTracker(clip, this); durationTracker.addEventListener(TimerEvent.TIMER_COMPLETE, durationReached); durationTracker.start(); } + private function clearDurationTracker():void + { + durationTracker.stop(); + durationTracker.removeEventListener(TimerEvent.TIMER_COMPLETE, durationReached); + durationTracker = null; + } + public function get time():Number { if (!durationTracker) return 0; var time:Number = durationTracker.time; @@ -166,8 +173,8 @@ package org.flowplayer.controller { private function stop(event:ClipEvent, closeStream:Boolean, silent:Boolean = false):void { log.debug("stop " + durationTracker); if (durationTracker) { - durationTracker.stop(); durationTracker.time = 0; + clearDurationTracker(); } doStop(silent ? null : event, closeStream); } diff --git a/core/src/actionscript/org/flowplayer/controller/InStreamTracker.as b/core/src/actionscript/org/flowplayer/controller/InStreamTracker.as index 7cabf2e..cdfee19 100644 --- a/core/src/actionscript/org/flowplayer/controller/InStreamTracker.as +++ b/core/src/actionscript/org/flowplayer/controller/InStreamTracker.as @@ -64,6 +64,7 @@ package org.flowplayer.controller { log.debug("stop()"); if (_timer && _timer.running) { _timer.stop(); + _timer.removeEventListener(TimerEvent.TIMER, onTimer); } } diff --git a/core/src/actionscript/org/flowplayer/controller/NetStreamCallbacks.as b/core/src/actionscript/org/flowplayer/controller/NetStreamCallbacks.as index 27ca5f1..79163e4 100644 --- a/core/src/actionscript/org/flowplayer/controller/NetStreamCallbacks.as +++ b/core/src/actionscript/org/flowplayer/controller/NetStreamCallbacks.as @@ -36,6 +36,6 @@ package org.flowplayer.controller { function RtmpSampleAccess(obj:Object):void; - function onTextData(obj:Object):void; + function onTextData(info:Object):void; } } diff --git a/core/src/actionscript/org/flowplayer/controller/NetStreamClient.as b/core/src/actionscript/org/flowplayer/controller/NetStreamClient.as index acecf3f..1955bd3 100644 --- a/core/src/actionscript/org/flowplayer/controller/NetStreamClient.as +++ b/core/src/actionscript/org/flowplayer/controller/NetStreamClient.as @@ -47,10 +47,7 @@ package org.flowplayer.controller { } public function onMetaData(infoObject:Object):void { - - log.info("onMetaData, current clip " + _clip); - - log.debug("onMetaData, data for clip " + _clip + ":"); + log.debug("onMetaData(), data for clip " + _clip + ":"); var metaData:Object = new Object(); for (var key:String in infoObject) { if (key == "duration" && _clip && _clip.metaData && _clip.metaData.duration) { @@ -138,8 +135,12 @@ package org.flowplayer.controller { _clip.dispatchNetStreamEvent("RtmpSampleAccess", infoObject); } - public function onTextData(infoObject:Object):void { - _clip.dispatchNetStreamEvent("onTextData", infoObject); + public function onTextData(info:Object):void { + var eventInfo:Object = {}; + for (var prop:String in info) { + eventInfo[prop] = info[prop]; + } + _clip.dispatchNetStreamEvent("onTextData", eventInfo); } public function onPlayStatus(...rest):void { diff --git a/core/src/actionscript/org/flowplayer/controller/NetStreamControllingStreamProvider.as b/core/src/actionscript/org/flowplayer/controller/NetStreamControllingStreamProvider.as index 1203ac3..dcee556 100644 --- a/core/src/actionscript/org/flowplayer/controller/NetStreamControllingStreamProvider.as +++ b/core/src/actionscript/org/flowplayer/controller/NetStreamControllingStreamProvider.as @@ -17,34 +17,29 @@ */ package org.flowplayer.controller { - import org.flowplayer.controller.StreamProvider; - import org.flowplayer.controller.TimeProvider; - import org.flowplayer.controller.VolumeController; + import flash.display.DisplayObject; + import flash.errors.IOError; + import flash.events.NetStatusEvent; + import flash.events.TimerEvent; + import flash.media.Video; + import flash.net.NetConnection; + import flash.net.NetStream; + import flash.utils.Dictionary; + import flash.utils.Timer; + import org.flowplayer.model.Clip; import org.flowplayer.model.ClipError; import org.flowplayer.model.ClipEvent; import org.flowplayer.model.ClipEventType; - import org.flowplayer.model.EventType; import org.flowplayer.model.Playlist; - import org.flowplayer.model.PluginEventType; import org.flowplayer.model.PluginModel; import org.flowplayer.model.ProviderModel; import org.flowplayer.util.Assert; import org.flowplayer.util.Log; import org.flowplayer.view.Flowplayer; - import flash.utils.Dictionary; - import flash.display.DisplayObject; - import flash.errors.IOError; - import flash.events.NetStatusEvent; - import flash.events.TimerEvent; - import flash.media.Video; - import flash.net.NetConnection; - import flash.net.NetStream; - import flash.utils.Timer; - CONFIG::FLASH_10_1 { - import org.flowplayer.view.StageVideoWrapper; + import org.flowplayer.view.StageVideoWrapper; } /** @@ -64,7 +59,7 @@ package org.flowplayer.controller { private var _pauseAfterStart:Boolean; private var _volumeController:VolumeController; private var _seekTargetWaitTimer:Timer; - private var _seekTarget:Number; + private var _seekTarget:Number = 0; private var _model:ProviderModel; private var _connectionProvider:ConnectionProvider; private var _clipUrlResolverHelper:ClipURLResolverHelper; @@ -122,7 +117,7 @@ package org.flowplayer.controller { } private function _load(clip:Clip, pauseAfterStart:Boolean, attempts:int = 3):void { - Assert.notNull(clip, "load(clip): clip cannot be null"); + Assert.notNull(clip, "load(clip): clip cannot be null"); _paused = false; _stopping = false; _attempts = attempts; @@ -211,6 +206,7 @@ package org.flowplayer.controller { * @inheritDoc */ public final function resume(event:ClipEvent):void { + log.debug("resume"); _paused = false; _stopping = false; doResume(_netStream, event); @@ -545,13 +541,14 @@ package org.flowplayer.controller { } protected function doSwitchStream(event:ClipEvent, netStream:NetStream, clip:Clip, netStreamPlayOptions:Object = null):void { + import flash.net.NetStreamPlayOptions; + //fix for #279, switch and pause if the current clip is currently in a paused state //#404 implement netstreamplayoptions for http streams, resets the stream or start loading a new stream. //implement switch support for flash9 players that do not support dynamic switching if (CONFIG::FLASH_10_1) { if (netStreamPlayOptions) { pauseAfterStart = paused; - import flash.net.NetStreamPlayOptions; if (netStreamPlayOptions is NetStreamPlayOptions) { log.debug("doSwitchStream() calling play2()"); //#461 when we have a clip base url set, we need the complete clip url sent to play2 for http streams. @@ -788,6 +785,7 @@ package org.flowplayer.controller { // dispatchPlayEvent(ClipEventType.STOP); } else if (event.info.code == "NetStream.Seek.Notify") { + if (! silentSeek) { startSeekTargetWait(); } else { @@ -834,14 +832,23 @@ package org.flowplayer.controller { if (_seekTarget < 0) return; if (_seekTargetWaitTimer && _seekTargetWaitTimer.running) return; log.debug("starting seek target wait timer"); + + if (_seekTargetWaitTimer) { + _seekTargetWaitTimer.reset(); + _seekTargetWaitTimer.removeEventListener(TimerEvent.TIMER, onSeekTargetWait); + _seekTargetWaitTimer = null; + } + _seekTargetWaitTimer = new Timer(200); _seekTargetWaitTimer.addEventListener(TimerEvent.TIMER, onSeekTargetWait); _seekTargetWaitTimer.start(); } private function onSeekTargetWait(event:TimerEvent):void { - if (time >= _seekTarget) { - _seekTargetWaitTimer.stop(); + //#104 if the updated time is a fraction less than the seek target time ie for HDS, use a bitwise rounding so the seek time can stop. + if ((time|0) >= (_seekTarget|0)) { + _seekTargetWaitTimer.reset(); + _seekTargetWaitTimer.removeEventListener(TimerEvent.TIMER, onSeekTargetWait); log.debug("dispatching onSeek"); dispatchPlayEvent(ClipEventType.SEEK, _seekTarget); _seekTarget = -1; @@ -875,28 +882,27 @@ package org.flowplayer.controller { _startedClip = null; log.debug("doStop(), closing netStream and connection"); - if (clip.getContent() is Video) { - Video(clip.getContent()).clear(); - } - try { netStream.close(); + _netStream.removeEventListener(NetStatusEvent.NET_STATUS, _onNetStatus); _netStream = null; } catch (e:Error) { } if (_connection) { _connection.close(); + _connection.removeEventListener(NetStatusEvent.NET_STATUS, _onNetStatus); _connection = null; } dispatchPlayEvent(ClipEventType.BUFFER_STOP); } - private function _createNetStream():void { - _netStream = createNetStream(_connection) || new NetStream(_connection); + private function _createNetStream():void { + _netStream = createNetStream(_connection) || new NetStream(_connection); netStream.client = new NetStreamClient(clip, _player.config, _streamCallbacks); _netStream.bufferTime = clip.bufferLength; + log.debug("using buffer time of " + _netStream.bufferTime); _volumeController.netStream = _netStream; clip.setNetStream(_netStream); _netStream.addEventListener(NetStatusEvent.NET_STATUS, _onNetStatus); diff --git a/core/src/actionscript/org/flowplayer/controller/ParallelRTMPConnectionProvider.as b/core/src/actionscript/org/flowplayer/controller/ParallelRTMPConnectionProvider.as index 9755092..4757e1f 100644 --- a/core/src/actionscript/org/flowplayer/controller/ParallelRTMPConnectionProvider.as +++ b/core/src/actionscript/org/flowplayer/controller/ParallelRTMPConnectionProvider.as @@ -90,10 +90,11 @@ package org.flowplayer.controller { doConnect(_rtmpConnector, _proxyType, objectEncoding, connArgs); // RTMPT connect is started after 250 ms + //#163 weak reference var delay:Timer = new Timer(_failOverDelay, 1); delay.addEventListener(TimerEvent.TIMER, function(event:TimerEvent):void { doConnect(_rtmptConnector, _proxyType, objectEncoding, connArgs); - }); + }, false, 0 , true); delay.start(); } else { diff --git a/core/src/actionscript/org/flowplayer/controller/ParallelRTMPConnector.as b/core/src/actionscript/org/flowplayer/controller/ParallelRTMPConnector.as index b9c89a0..b47f99f 100644 --- a/core/src/actionscript/org/flowplayer/controller/ParallelRTMPConnector.as +++ b/core/src/actionscript/org/flowplayer/controller/ParallelRTMPConnector.as @@ -57,7 +57,8 @@ package org.flowplayer.controller { if (_connectionClient) { _connection.client = _connectionClient; } - _connection.addEventListener(NetStatusEvent.NET_STATUS, _onConnectionStatus); + //#163 weak reference to listener + _connection.addEventListener(NetStatusEvent.NET_STATUS, _onConnectionStatus, false, 0 , true); log.debug("netConnectionUrl is " + _url); if (connectionArgs && connectionArgs.length > 0) { diff --git a/core/src/actionscript/org/flowplayer/controller/PlayListController.as b/core/src/actionscript/org/flowplayer/controller/PlayListController.as index 62084fe..9321e6f 100644 --- a/core/src/actionscript/org/flowplayer/controller/PlayListController.as +++ b/core/src/actionscript/org/flowplayer/controller/PlayListController.as @@ -67,6 +67,7 @@ package org.flowplayer.controller { flow_internal function setPlaylist(clips:Array):void { if (getState() != State.WAITING) { close(false); + clearStream(); } _playList.replaceClips2(clips); } @@ -328,8 +329,20 @@ package org.flowplayer.controller { } } + //#163 detach netstream on the current clip + private function clearStream():void + { + if (_playList.current && _playList.current.getContent() && _playList.current.getContent().hasOwnProperty("attachNetStream")) { + Object(_playList.current.getContent()).attachNetStream(null); + } + } + private function replacePlaylistAndPlay(clips:Object):void { - stop(); + + //#163 stop the connection and stream + _state.stop(true, true); + clearStream(); + if (clips is Clip) { _playList.replaceClips(clips as Clip); } else { diff --git a/core/src/actionscript/org/flowplayer/controller/PlayState.as b/core/src/actionscript/org/flowplayer/controller/PlayState.as index a437331..4a29cc6 100644 --- a/core/src/actionscript/org/flowplayer/controller/PlayState.as +++ b/core/src/actionscript/org/flowplayer/controller/PlayState.as @@ -129,11 +129,11 @@ package org.flowplayer.controller { log.debug("stop() called"); if (silent) { - getMediaController().onEvent(null, [closeStreamAndConnection]); + getMediaController().onEvent(ClipEventType.STOP, [closeStreamAndConnection, true]); if (closeStreamAndConnection && playList.current.parent != null) { playList.setInStreamClip(null); - getMediaController().onEvent(null, [true]); + getMediaController().onEvent(ClipEventType.STOP, [true, true]); } } else { diff --git a/core/src/actionscript/org/flowplayer/controller/PlayTimeTracker.as b/core/src/actionscript/org/flowplayer/controller/PlayTimeTracker.as index 78341eb..6c5a5b0 100644 --- a/core/src/actionscript/org/flowplayer/controller/PlayTimeTracker.as +++ b/core/src/actionscript/org/flowplayer/controller/PlayTimeTracker.as @@ -28,7 +28,6 @@ package org.flowplayer.controller { private var _onLastSecondDispatched:Boolean; private var _controller:MediaController; private var _endDetectTimer:Timer; - private var _wasPaused:Boolean = false; private var _lastTimeDetected:Number; public function PlayTimeTracker(clip:Clip, controller:MediaController) { @@ -52,7 +51,9 @@ package org.flowplayer.controller { public function stop():void { if (!_progressTimer) return; _storedTime = time; - _progressTimer.stop(); + _progressTimer.reset(); + _progressTimer.removeEventListener(TimerEvent.TIMER, checkProgress); + _progressTimer = null; log.debug("stopped at time " + _storedTime); } @@ -119,6 +120,7 @@ package org.flowplayer.controller { } public function get durationReached():Boolean { + if (_clip.live) return false; if (_clip.durationFromMetadata > _clip.duration) { return time >= _clip.duration; } @@ -128,27 +130,29 @@ package org.flowplayer.controller { private function startEndTimer(clip:Clip):void { bindEndListeners(); - _endDetectTimer.addEventListener(TimerEvent.TIMER, - function(event:TimerEvent):void { - log.debug("last time detected == " + _lastTimeDetected); - if(time == _lastTimeDetected && _endDetectTimer.running || durationReached) { - log.debug("clip has reached his end, timer stopped"); - _endDetectTimer.reset(); - completelyPlayed(); - } - _lastTimeDetected = time; - } - ); + _endDetectTimer.addEventListener(TimerEvent.TIMER, onEndTime); log.debug("starting end detect timer"); _endDetectTimer.start(); } + + private function onEndTime(event:TimerEvent):void + { + log.debug("last time detected == " + _lastTimeDetected); + if(time == _lastTimeDetected && _endDetectTimer.running || durationReached) { + log.debug("clip has reached his end, timer stopped"); + _endDetectTimer.reset(); + completelyPlayed(); + } + _lastTimeDetected = time; + } private function completelyPlayed():void { if(_endDetectTimer.running) { unbindEndListeners(); _endDetectTimer.reset(); + _endDetectTimer.removeEventListener(TimerEvent.TIMER, onEndTime); _endDetectTimer = null; } @@ -181,6 +185,8 @@ package org.flowplayer.controller { log.debug("this cuepoint already fired"); } } + + points = null; } private function collectCuepoints(clip:Clip, timeRounded:Number):Array { diff --git a/core/src/actionscript/org/flowplayer/controller/VolumeController.as b/core/src/actionscript/org/flowplayer/controller/VolumeController.as index 484c28e..e2f3404 100644 --- a/core/src/actionscript/org/flowplayer/controller/VolumeController.as +++ b/core/src/actionscript/org/flowplayer/controller/VolumeController.as @@ -104,6 +104,7 @@ package org.flowplayer.controller { dispatchEvent(PlayerEvent.volume(this.volume)); if (!_storeDelayTimer.running) { log.info("starting delay timer"); + _storeDelayTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerDelayComplete); _storeDelayTimer.start(); } } @@ -123,6 +124,7 @@ package org.flowplayer.controller { private function storeVolume(muted:Boolean = false):void { log.info("persisting volume level"); _storeDelayTimer.stop(); + _storeDelayTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onTimerDelayComplete); _storedVolume.volume = _soundTransform.volume; _storedVolume.muted = muted; _storedVolume.persist(); diff --git a/core/src/actionscript/org/flowplayer/model/Clip.as b/core/src/actionscript/org/flowplayer/model/Clip.as index 171275c..41d0e56 100644 --- a/core/src/actionscript/org/flowplayer/model/Clip.as +++ b/core/src/actionscript/org/flowplayer/model/Clip.as @@ -61,7 +61,7 @@ package org.flowplayer.model { private var _content:DisplayObject; private var _originalWidth:int; private var _originalHeight:int; - private var _bufferLength:int; + private var _bufferLength:Number; private var _backBufferLength:int; private var _played:Boolean; private var _provider:String; @@ -643,11 +643,11 @@ package org.flowplayer.model { } [Value] - public function get bufferLength():int { + public function get bufferLength():Number { return _bufferLength; } - public function set bufferLength(bufferLength:int):void { + public function set bufferLength(bufferLength:Number):void { _bufferLength = bufferLength; } @@ -670,6 +670,7 @@ package org.flowplayer.model { [Value] public function get provider():String { + if (_clipObject && _clipObject.hasOwnProperty("provider")) return _clipObject.provider; if (type == ClipType.AUDIO && _provider == "http") return "audio"; if (_url && _url.toLowerCase().indexOf("rtmp") == 0 && _provider == "http") return "rtmp"; if (parent) return _provider + "Instream"; diff --git a/core/src/actionscript/org/flowplayer/model/ClipEventSupport.as b/core/src/actionscript/org/flowplayer/model/ClipEventSupport.as index 0349557..e4f07e0 100644 --- a/core/src/actionscript/org/flowplayer/model/ClipEventSupport.as +++ b/core/src/actionscript/org/flowplayer/model/ClipEventSupport.as @@ -23,8 +23,8 @@ package org.flowplayer.model { * @author api */ public class ClipEventSupport extends ClipEventDispatcher { - private var _clips:Array; - private var _commonClip:Clip; + protected var _clips:Array; + protected var _commonClip:Clip; public function ClipEventSupport(commonClip:Clip, clips:Array = null) { _commonClip = commonClip; diff --git a/core/src/actionscript/org/flowplayer/model/Playlist.as b/core/src/actionscript/org/flowplayer/model/Playlist.as index 2b41662..0814c20 100644 --- a/core/src/actionscript/org/flowplayer/model/Playlist.as +++ b/core/src/actionscript/org/flowplayer/model/Playlist.as @@ -17,8 +17,11 @@ */ package org.flowplayer.model { + + import org.flowplayer.flow_internal; + use namespace flow_internal; /** * @author anssi @@ -27,28 +30,28 @@ package org.flowplayer.model { private var _currentPos:Number; private var _inStreamClip:Clip; - private var _commonClip:Clip; - private var _clips:Array; public function Playlist(commonClip:Clip = null) { if (commonClip == null) { commonClip = new NullClip(); } - super(commonClip); - _commonClip = commonClip; + + //#163 inherit clips and common clip + super(commonClip, new Array()); _commonClip.setParentPlaylist(this); initialize(); } - private function initialize(newClips:Array = null):void { - _clips = new Array(); + private function initialize(newClips:Array = null):void { + //#163 reuse clips and initialize + if (_clips) _clips.length = 0; _inStreamClip = null; if (newClips) { for (var i:Number = 0; i < newClips.length; i++) { doAddClip(newClips[i]); } } - super.setClips(_clips); + _currentPos = 0; log.debug("initialized, current clip is " + current); } @@ -73,21 +76,26 @@ package org.flowplayer.model { for (var i:Number = 0; i < clips.length; i++) { doAddClip(clips[i], -1, false); } - super.setClips(_clips); } - + private function doReplace(newClips:Array, silent:Boolean = false):void { var oldClips:Array = _clips.concat([]); - initialize(newClips); + + initialize(newClips); + if (! silent) { dispatchPlaylistReplace(oldClips); } + + oldClips.length = 0; + oldClips = null; } flow_internal function dispatchPlaylistReplace(oldClips:Array = null):void { log.debug("dispatchPlaylistReplace"); var oldClipsEventHelper:ClipEventSupport = new ClipEventSupport(_commonClip, oldClips || []); - doDispatchEvent(new ClipEvent(ClipEventType.PLAYLIST_REPLACE, oldClipsEventHelper), true); } + doDispatchEvent(new ClipEvent(ClipEventType.PLAYLIST_REPLACE, oldClipsEventHelper), true); + } /** @@ -98,7 +106,6 @@ package org.flowplayer.model { * @see ClipEventType#CLIP_ADD */ public function addClip(clip:Clip, pos:int = -1, silent:Boolean = false):void { - var index:Number = positionOf(pos); if (clip.position >= 0 || clip.position == -1 || clip.position == -2) { addChildClip(clip, pos); return; @@ -114,7 +121,6 @@ package org.flowplayer.model { log.debug("addClip(), moving to next clip"); next(); } - super.setClips(_clips); } if (! silent) { doDispatchEvent(new ClipEvent(ClipEventType.CLIP_ADD, pos >= 0 ? pos : clips.length - 1), true); @@ -136,6 +142,7 @@ package org.flowplayer.model { if (pos == -1) { pos = clips.length - 1; } + var parent:Clip = clips[pos]; parent.addChild(clip); if (clip.position == 0) { @@ -151,28 +158,31 @@ package org.flowplayer.model { } private function doAddClip(clip:Clip, pos:int = -1, dispatchEvents:Boolean = true):void { - log.debug("doAddClip() " + clip); + //log.debug("doAddClip() " + clip); clip.setParentPlaylist(this); - var currentInPos:Clip; + + + //#163 reposition order of clip add + + if (clip != _commonClip) { + clip.onAll(_commonClip.onClipEvent); + log.debug("adding listener to all before events, common clip listens to other clips"); + clip.onBeforeAll(_commonClip.onBeforeClipEvent); + } + if (pos == -1) { _clips.push(clip); } else { - currentInPos = clips[pos]; - _clips.splice(_clips.indexOf(currentInPos.preroll || currentInPos), 0, clip); + _clips.splice(_clips.indexOf(_clips[pos].preroll || _clips[pos]), 0, clip); } + var nested:Array = clip.playlist; for (var i:int = 0; i < nested.length; i++) { - var nestedClip:Clip = nested[i] as Clip; - addChildClip(nestedClip, pos, dispatchEvents); + addChildClip(nested[i], pos, dispatchEvents); } - log.debug("clips now " + _clips); + //log.debug("clips now " + _clips); - if (clip != _commonClip) { - clip.onAll(_commonClip.onClipEvent); - log.debug("adding listener to all before events, common clip listens to other clips"); - clip.onBeforeAll(_commonClip.onBeforeClipEvent); - } } /** @@ -217,7 +227,6 @@ package org.flowplayer.model { public function setInStreamClip(clip:Clip):void { log.debug("setInstremClip to " + clip); - if (clip && _inStreamClip) throw new Error("Already playing an instream clip"); _inStreamClip = clip; } diff --git a/core/src/actionscript/org/flowplayer/util/PropertyBinder.as b/core/src/actionscript/org/flowplayer/util/PropertyBinder.as index 0cd80a1..8e9e120 100644 --- a/core/src/actionscript/org/flowplayer/util/PropertyBinder.as +++ b/core/src/actionscript/org/flowplayer/util/PropertyBinder.as @@ -17,11 +17,13 @@ */ package org.flowplayer.util { - import flash.utils.describeType; + +import flash.utils.describeType; import flash.utils.getQualifiedClassName; import org.flowplayer.util.Log; + import flash.system.System; /** * PropertyBinder is used to populate object's properties by copying values * from other objects. The target object should be an instance of a class that contains @@ -42,7 +44,7 @@ package org.flowplayer.util { * @param extraProps a property name for all properties for which the target does not provide an accessor or a setter function */ public function PropertyBinder(object:Object, extraProps:String = null) { - log.info("created for " + getQualifiedClassName(object)); + //log.info("created for " + getQualifiedClassName(object)); _object = object; _extraProps = extraProps; _objectDesc = describeType(_object); @@ -57,7 +59,10 @@ package org.flowplayer.util { copyProperty(prop, source[prop]); } } - log.debug("done with " + getQualifiedClassName(_object)); + + //#163 cleanup xml object + System.disposeXML(_objectDesc); + //log.debug("done with " + getQualifiedClassName(_object)); return _object; } diff --git a/core/src/actionscript/org/flowplayer/view/AnimationEngine.as b/core/src/actionscript/org/flowplayer/view/AnimationEngine.as index ab40a1d..78bf7f5 100644 --- a/core/src/actionscript/org/flowplayer/view/AnimationEngine.as +++ b/core/src/actionscript/org/flowplayer/view/AnimationEngine.as @@ -263,7 +263,7 @@ package org.flowplayer.view { } else { log.info("previous fadeout was canceled, will not remove " + view + " from panel"); } - }); + }, false, 0, true); } else if (view.parent != _panel) { _panel.addView(view, null, plugin); } @@ -337,12 +337,12 @@ package org.flowplayer.view { playable.addEventListener(GoEvent.COMPLETE, function(event:GoEvent):void { onComplete(view, playable, completeCallback); - }); + }, false, 0, true); if (updateCallback != null) { playable.addEventListener(GoEvent.UPDATE, function(event:GoEvent):void { updateCallback(view); - }); + }, false, 0, true); } playable.start(); diff --git a/core/src/actionscript/org/flowplayer/view/ClipResizer.as b/core/src/actionscript/org/flowplayer/view/ClipResizer.as index 397ca7f..3c182df 100644 --- a/core/src/actionscript/org/flowplayer/view/ClipResizer.as +++ b/core/src/actionscript/org/flowplayer/view/ClipResizer.as @@ -69,11 +69,7 @@ package org.flowplayer.view { public function resizeClipTo(clip:Clip, mediaSize:MediaSize, force:Boolean = false):void { log.debug("resizeClipTo, clip " + clip); - if ( _resizerTimer ) { - log.debug("Killing old resize timer"); - _resizerTimer.reset(); - _resizerTimer = null; - } + var resizer:MediaResizer = resizers[clip]; if (! resizer) { @@ -92,16 +88,26 @@ package org.flowplayer.view { screen.resized(clip); } }; + + if ( resizer.hasOrigSize() ) { log.debug("we have a size, resizing now !"); resizingFunc(); } else { + + if ( _resizerTimer ) { + log.debug("Killing old resize timer"); + _resizerTimer.reset(); + _resizerTimer.removeEventListener(TimerEvent.TIMER, resizingFunc); + _resizerTimer = null; + } + // delayed one log.warn("we don't have a size now, delaying the resize"); _resizerTimer = new Timer(500, 5); _resizerTimer.addEventListener(TimerEvent.TIMER, resizingFunc); - _resizerTimer.start(); + //_resizerTimer.start(); } } diff --git a/core/src/actionscript/org/flowplayer/view/Flowplayer.as b/core/src/actionscript/org/flowplayer/view/Flowplayer.as index 100621f..8edeb5a 100644 --- a/core/src/actionscript/org/flowplayer/view/Flowplayer.as +++ b/core/src/actionscript/org/flowplayer/view/Flowplayer.as @@ -162,6 +162,7 @@ package org.flowplayer.view { addCallback("setKeyboardShortcutsEnabled", setKeyboardShortcutsEnabled); addCallback("isKeyboardShortcutsEnabled", isKeyboardShortcutsEnabled); addCallback("validateKey", validateKey); + addCallback("checkKeyInDomain", checkKeyInDomain); addCallback("bufferAnimate", bufferAnimate); @@ -380,10 +381,15 @@ package org.flowplayer.view { }; } - private function validateKey(key:Object, pageDomain:Boolean):Boolean { - var LicenseKey:Class = Class(getDefinitionByName("org.flowplayer.view.LicenseKey")); - return LicenseKey["validate"](_canvas.loaderInfo.url, version, key, pageDomain); - } + private function validateKey(key:Object, pageDomain:Boolean):Boolean { + var LicenseKey:Class = Class(getDefinitionByName("org.flowplayer.view.LicenseKey")); + return LicenseKey["validate"](_canvas.loaderInfo.url, version, key, pageDomain); + } + + private function checkKeyInDomain(key:Object, domain:String):Boolean { + var LicenseKey:Class = Class(getDefinitionByName("org.flowplayer.view.LicenseKey")); + return LicenseKey["validate"](domain, version, key, false); + } } } diff --git a/core/src/actionscript/org/flowplayer/view/FlowplayerBase.as b/core/src/actionscript/org/flowplayer/view/FlowplayerBase.as index cf4382e..359f84f 100644 --- a/core/src/actionscript/org/flowplayer/view/FlowplayerBase.as +++ b/core/src/actionscript/org/flowplayer/view/FlowplayerBase.as @@ -708,16 +708,17 @@ package org.flowplayer.view { if (name == "onCuePoint") { var cuepoint:Cuepoint = Cuepoint.createDynamic(infoObj["time"], "embedded"); for (var prop:String in infoObj) { - log.debug(prop + ": " + infoObj[prop]); +// log.debug(prop + ": " + infoObj[prop]); if (prop == "parameters") { for (var param:String in infoObj.parameters) { log.debug(param + ": " + infoObj.parameters[param]); - cuepoint.addParameter(param, infoObj.parameters[param]); + cuepoint.addParameter(param.replace(/[^a-z0-9]+/gi, ""), infoObj.parameters[param]); } } else { cuepoint[prop] = infoObj[prop]; } } + log.debug("Dispatching cuepoint", cuepoint); playlist.current.dispatch(ClipEventType.forName(name), cuepoint); return; } diff --git a/core/src/actionscript/org/flowplayer/view/Focus.as b/core/src/actionscript/org/flowplayer/view/Focus.as new file mode 100755 index 0000000..7865869 --- /dev/null +++ b/core/src/actionscript/org/flowplayer/view/Focus.as @@ -0,0 +1,195 @@ +/* +* Copyright (c) 2008 Michael A. Jordan +* Copyright (c) 2009 Adobe Systems, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + +This code is based on Adobe's SWFFocus class. +The original SWFFocus class is designed to resolve the accessibility issue in browsers other than Internet Explorer +when users can't access player controls by keyboard alone. This accessibility issue can be viewed in 2 parts: + +1. User can't access player's controls, tabbing skips over the player. +2. Once user has a focus on player's controls, he can tab through player's controls, but he is 'trapped' inside the player and can't +shift focus back to the html page elements. + +Task #1 is not working in several browsers including Chrome and Opera on Windows. This issue is resolved by javascript code and does not require changes +in the AS. + +Task #2 is resolved by this class and is using the same idea as Adobe's SWFFocus class uses - it injects javascript code into html page embedding the player. +The code monitors objects receiving the focus and once the user has made a full circle (the first object received a focus again) it injects the javascript +that shifts focus to the designated "next" html element on the page embedding the player. + +Code modified by: Gita Ligure +GLigure@Books24x7.com +November 12th, 2013 + +*/ +package org.flowplayer.view +{ + import flash.display.DisplayObject; + import flash.display.InteractiveObject; + import flash.display.Stage; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.FocusEvent; + import flash.events.KeyboardEvent; + import flash.external.ExternalInterface; + import flash.system.Capabilities; + import flash.ui.Keyboard; + import flash.utils.setTimeout; + + import org.flowplayer.util.Log; + + public class Focus extends EventDispatcher + { + private var log:Log = new Log(this); + + private static var _availability:Boolean = ExternalInterface.available; + private static var _dispatcher:EventDispatcher = new EventDispatcher(); + private static var _instance:Focus = new Focus( SingletonLock ); + private static var _initialized:Boolean = false; + private var _stage:Stage; + + private var _firstRoundTabbing:Boolean = true; + private var _ignoreNextEvents:Boolean = false; + + private var _firstTabbedObject:InteractiveObject; + + private var _idNext:String; + + /** + * + * Constructor + */ + public function Focus( lock:Class ) + { + if ( lock != SingletonLock ) + { + throw new Error( "Invalid Singleton access. Use Focus.init." ); + } + } + + /** + * + * Initiates swffocus object, and sets callbacks + */ + public static function init(stageRef:Stage):void + { + var swffocus:Focus = _instance; + if (stageRef && swffocus._stage != stageRef && !_initialized) + { + swffocus._stage = stageRef; + _initialized = swffocus._initialize(); + } + } + + /** + * @private + * Set event handles and inject JavaScript code + */ + private function _initialize():Boolean + { + log.info("Initializing Focus "); + if (_availability && Capabilities.playerType.toLowerCase() == "plugin" && !Focus._initialized) + { + try { + ExternalInterface.addCallback("setNextFocusId", _instance.setNextFocusId); + } catch (e:Error) { + log.debug("Focus._initialize(): Unable to add JS callback."); + } + _stage.addEventListener(FocusEvent.FOCUS_IN, stage_focusInHandler, false, 0, true); + _stage.addEventListener(FocusEvent.FOCUS_OUT, stage_focusOutHandler, false, 0, true); + } + return true; + } + + /** + * @private compares with a stored first object tabbed into + * and if they match, calls javascript to set focus to a next + * html element on the page + */ + private function stage_focusOutHandler(e:FocusEvent):void + { + if (_ignoreNextEvents != true) + { + if (!_firstRoundTabbing) + { + if (_firstTabbedObject && e.relatedObject) + { + if (_firstTabbedObject.name == e.relatedObject.name) // make sure objects not null + { + log.info("IT'S A MATCH First object Stored: " + _firstTabbedObject.name + " related object " + e.relatedObject.name); + // reset for next round + _firstTabbedObject = null; + _firstRoundTabbing = true; + _ignoreNextEvents = true; + + if (_idNext) + { + log.info("Should set focus on element " + _idNext); + ExternalInterface.call("function(){var elem = document.getElementById('" +_idNext + "'); if (elem) elem.focus();}"); + } + } + } + } + else + { + _firstRoundTabbing = false; + } + } + else + _ignoreNextEvents = false; + } + + /** + * @private stores the first target focus; + */ + private function stage_focusInHandler(e:FocusEvent):void + { + if (_ignoreNextEvents != true) + { + if (_firstRoundTabbing) + { + log.info("Will store " + e.target + " as a first Tabbed object "); + if (e.currentTarget) _firstTabbedObject = InteractiveObject(e.target); + } + } + + } + + /** + * + * Callback function for JavaScript, used to set IDs of next and previous + * elements in the HTML tab order. + * + */ + public function setNextFocusId(idNext:String):void + { + if (idNext) + _idNext = idNext; + } + + } + +} + + +/** + * This is a private class declared outside of the package + * that is only accessible to classes inside of the Focus.as + * file. Because of that, no outside code is able to get a + * reference to this class to pass to the constructor, which + * enables us to prevent outside instantiation. + */ +class SingletonLock +{ +} // end class diff --git a/core/src/actionscript/org/flowplayer/view/Launcher.as b/core/src/actionscript/org/flowplayer/view/Launcher.as index a98c1ca..b4989f7 100644 --- a/core/src/actionscript/org/flowplayer/view/Launcher.as +++ b/core/src/actionscript/org/flowplayer/view/Launcher.as @@ -16,64 +16,57 @@ * along with Flowplayer. If not, see . */ package org.flowplayer.view { + import flash.display.BlendMode; + import flash.display.DisplayObject; + import flash.display.DisplayObjectContainer; + import flash.display.Sprite; + import flash.events.Event; + import flash.events.MouseEvent; + import flash.events.TimerEvent; + import flash.net.URLRequest; + import flash.net.navigateToURL; + import flash.system.Capabilities; + import flash.system.Security; + import flash.text.TextField; + import flash.text.TextFieldAutoSize; + import flash.utils.Timer; + import flash.utils.Dictionary; + import org.flowplayer.config.Config; - import org.flowplayer.config.ConfigParser; - import org.flowplayer.config.ExternalInterfaceHelper; - import org.flowplayer.config.VersionInfo; - import org.flowplayer.controller.PlayListController; - import org.flowplayer.controller.ResourceLoader; - import org.flowplayer.controller.ResourceLoaderImpl; + import org.flowplayer.config.ConfigParser; + import org.flowplayer.config.ExternalInterfaceHelper; + import org.flowplayer.config.VersionInfo; + import org.flowplayer.controller.PlayListController; + import org.flowplayer.controller.ResourceLoader; + import org.flowplayer.controller.ResourceLoaderImpl; import org.flowplayer.flow_internal; - import org.flowplayer.model.Callable; - import org.flowplayer.model.Clip; - import org.flowplayer.model.ClipEvent; + import org.flowplayer.model.Callable; + import org.flowplayer.model.Clip; + import org.flowplayer.model.ClipEvent; import org.flowplayer.model.ClipEventType; import org.flowplayer.model.DisplayPluginModel; - import org.flowplayer.model.DisplayProperties; - import org.flowplayer.model.DisplayPropertiesImpl; + import org.flowplayer.model.DisplayProperties; import org.flowplayer.model.ErrorCode; + import org.flowplayer.model.Loadable; + import org.flowplayer.model.Logo; + import org.flowplayer.model.PlayButtonOverlay; + import org.flowplayer.model.PlayerError; + import org.flowplayer.model.PlayerEvent; + import org.flowplayer.model.Playlist; + import org.flowplayer.model.Plugin; + import org.flowplayer.model.PluginEvent; + import org.flowplayer.model.PluginModel; + import org.flowplayer.model.ProviderModel; + import org.flowplayer.model.State; + import org.flowplayer.util.Arrange; import org.flowplayer.model.EventDispatcher; - import org.flowplayer.model.Loadable; - import org.flowplayer.model.Logo; - import org.flowplayer.model.PlayButtonOverlay; - import org.flowplayer.model.PlayerError; - import org.flowplayer.model.PlayerEvent; - import org.flowplayer.model.Playlist; - import org.flowplayer.model.Plugin; - import org.flowplayer.model.PluginError; - import org.flowplayer.model.PluginEvent; - import org.flowplayer.model.PluginModel; - import org.flowplayer.model.ProviderModel; - import org.flowplayer.model.State; - import org.flowplayer.util.Arrange; - import org.flowplayer.util.Log; - import org.flowplayer.util.TextUtil; - import org.flowplayer.util.URLUtil; - import org.flowplayer.view.Panel; - import org.flowplayer.view.PluginLoader; - import org.flowplayer.view.Screen; - import org.flowplayer.view.KeyboardHandler; - import org.osflash.thunderbolt.Logger; - - import flash.display.DisplayObject; - import flash.display.DisplayObjectContainer; - import flash.display.Sprite; - import flash.display.BlendMode; - - import flash.events.Event; - import flash.events.MouseEvent; - import flash.events.TimerEvent; - import flash.net.URLRequest; - import flash.net.navigateToURL; - import flash.system.Capabilities; - import flash.system.Security; - import flash.text.TextField; - import flash.text.TextFieldAutoSize; - - import flash.utils.*; + import org.flowplayer.util.Log; + import org.flowplayer.util.TextUtil; + import org.flowplayer.util.URLUtil; + import org.osflash.thunderbolt.Logger; CONFIG::FLASH_10_1 { - import flash.media.StageVideo; + import flash.media.StageVideo; } use namespace flow_internal; @@ -99,18 +92,25 @@ package org.flowplayer.view { private var _clickCount:int; private var _clickTimer:Timer = new Timer(200, 1); private var _clickEvent:MouseEvent; + private var _fullscreenDelay:Timer; + private var _screenMask:Sprite; [Frame(factoryClass="org.flowplayer.view.Preloader")] public function Launcher() { - addEventListener(Event.ADDED_TO_STAGE, function(e:Event):void { - URLUtil.loaderInfo = loaderInfo; - trace("Launcher added to stage"); - callAndHandleError(createFlashVarsConfig, PlayerError.INIT_FAILED); - }); + //#163 add and remove stage add listener + addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); super("#canvas", this); } + private function onAddedToStage(e:Event):void + { + URLUtil.loaderInfo = loaderInfo; + trace("Launcher added to stage"); + callAndHandleError(createFlashVarsConfig, PlayerError.INIT_FAILED); + removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); + } + private function initPhase1():void { if (_flowplayer) { @@ -130,8 +130,9 @@ package org.flowplayer.view { loader = createNewLoader(); rootStyle = _config.canvas.style; + //#163 combine resize events stage.addEventListener(Event.RESIZE, onStageResize); - stage.addEventListener(Event.RESIZE, arrangeScreen); + //stage.addEventListener(Event.RESIZE, arrangeScreen); setSize(Arrange.parentWidth, Arrange.parentHeight); @@ -213,6 +214,7 @@ package org.flowplayer.view { log.debug("no loadable plugins, calling initPhase4"); initPhase4(); } + Focus.init(stage); } private function initPhase4(event:Event = null):void { @@ -251,16 +253,18 @@ package org.flowplayer.view { //#508 disabling the stagevideo screen mask, canvas is visible without it. private function createScreenMask():void { blendMode = BlendMode.LAYER; + + var squareEdgeSize:int = Math.max(stage.stageWidth, stage.stageHeight); _screenMask = new Sprite(); - _screenMask.graphics.beginFill(0xff0000); - _screenMask.graphics.drawRect(0, 0, 1, 1); + _screenMask.graphics.beginFill(0x000000, 1); + _screenMask.graphics.drawRect(0, 0, squareEdgeSize, squareEdgeSize); + _screenMask.graphics.endFill(); _screenMask.blendMode = BlendMode.ERASE; _screenMask.x = 0; _screenMask.y = 0; - _screenMask.width = 100; - _screenMask.height = 100; + } private function resizeCanvasLogo():void { @@ -278,6 +282,8 @@ package org.flowplayer.view { private function onStageResize(event:Event = null):void { setSize(Arrange.parentWidth, Arrange.parentHeight); arrangeCanvasLogo(); + //#163 move second resize event here + arrangeScreen(event); } private function arrangeCanvasLogo():void { @@ -292,7 +298,7 @@ package org.flowplayer.view { var plugins:Array = _config.getLoadables(); log.debug("will load following plugins: "); logPluginInfo(plugins); - _pluginLoader = new PluginLoader(URLUtil.playerBaseUrl, _pluginRegistry, this, useExternalInterface()); + _pluginLoader = new PluginLoader(URLUtil.playerBaseUrl, _pluginRegistry, this, useExternalInterface(), (CONFIG::secondaryDomains).split(" ")); _pluginLoader.addEventListener(Event.COMPLETE, pluginLoadListener); _flowplayer.pluginLoader = _pluginLoader; if (plugins.length == 0) { @@ -598,14 +604,20 @@ package org.flowplayer.view { stage.removeEventListener(Event.RESIZE, arrangeScreen); _enteringFullscreen = true; - var delay:Timer = new Timer(1000, 1); - delay.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete); - delay.start(); + + //#163 add / remove delay timer + _fullscreenDelay = new Timer(1000, 1); + _fullscreenDelay.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete); + _fullscreenDelay.start(); } private function onTimerComplete(event:TimerEvent):void { log.debug("fullscreen wait delay complete, display clicks are enabled again"); _enteringFullscreen = false; + + _fullscreenDelay.reset(); + _fullscreenDelay.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete); + _fullscreenDelay = null; } private function createFlashVarsConfig():void { @@ -737,6 +749,7 @@ package org.flowplayer.view { //#508 disabling the stagevideo screen mask, canvas is visible without it. CONFIG::FLASH_10_1 { + _flowplayer.playlist.onStageVideoStateChange(onStageVideoStateChange); //#44 fixes for #627, now bind and unbind stagevideo events during seeking to prevent the mask repositioning. @@ -744,7 +757,9 @@ package org.flowplayer.view { _flowplayer.playlist.unbind(onStageVideoStateChange); }); - _flowplayer.playlist.onSeek(function(event:ClipEvent):void { + //#75 temporary fix for seeking with progressive download as it creates a delay to dispatch seek events because of the seek delay timer. + _flowplayer.playlist.onBufferFull(function(event:ClipEvent):void { + _flowplayer.playlist.unbind(onStageVideoStateChange); _flowplayer.playlist.onStageVideoStateChange(onStageVideoStateChange); }); } @@ -765,6 +780,7 @@ package org.flowplayer.view { log.debug("stage video state changed " + stageVideo); if (stageVideo) { + _screenMask.visible = false; //#44 fixes for #627 check if the stagevideo dimensions and positioning has changed to update the stage video mask with. //unbinding and binding stage video events caused issues with instream playlists therefore has to be kept binded. if (_screenMask.width !== stageVideo.viewPort.width) { @@ -795,11 +811,17 @@ package org.flowplayer.view { } CONFIG::commercialVersion { - addChildAt(_screenMask, 1); + //#75 set the child display list different when a gradient is set. + addChildAt(_screenMask, style.backgroundGradient ? 1 : 0); + } - //addChildAt(_screenMask, _canvasLogo ? 1 : 0); + + log.debug("adding mask"); } + _screenMask.visible = true; + + } else { if (contains(_screenMask)) { log.debug("removing mask") @@ -940,7 +962,7 @@ package org.flowplayer.view { _canvasLogo.scaleY = _canvasLogo.scaleX; _canvasLogo.alpha = .4; _canvasLogo.addEventListener(MouseEvent.CLICK, - function(event:MouseEvent):void { navigateToURL(new URLRequest("http://flowplayer.org"), "_self"); }); + function(event:MouseEvent):void { navigateToURL(new URLRequest("http://flash.flowplayer.org"), "_self"); }); _canvasLogo.buttonMode = true; log.debug("adding logo to display list"); addChild(_canvasLogo); diff --git a/core/src/actionscript/org/flowplayer/view/Panel.as b/core/src/actionscript/org/flowplayer/view/Panel.as index 6ec12d9..dc4a238 100644 --- a/core/src/actionscript/org/flowplayer/view/Panel.as +++ b/core/src/actionscript/org/flowplayer/view/Panel.as @@ -133,7 +133,7 @@ package org.flowplayer.view { } public function getZIndex(view:DisplayObject):int { - try { + try { return getChildIndex(view); } catch (e:Error) { // view not added in this panel @@ -168,6 +168,8 @@ package org.flowplayer.view { } private function createLayout(event:Event):void { + //#163 remove event listener + removeEventListener(Event.ADDED_TO_STAGE, createLayout); layout = new MarginLayout(stage); } diff --git a/core/src/actionscript/org/flowplayer/view/PluginLoader.as b/core/src/actionscript/org/flowplayer/view/PluginLoader.as index 2b8bfb0..7a8f901 100644 --- a/core/src/actionscript/org/flowplayer/view/PluginLoader.as +++ b/core/src/actionscript/org/flowplayer/view/PluginLoader.as @@ -18,46 +18,42 @@ */ package org.flowplayer.view { - import flash.display.AVM1Movie; +import com.adobe.utils.StringUtil; + +import flash.display.AVM1Movie; +import flash.display.DisplayObject; +import flash.display.Loader; +import flash.display.LoaderInfo; +import flash.events.Event; +import flash.events.EventDispatcher; +import flash.events.IOErrorEvent; +import flash.events.ProgressEvent; +import flash.net.URLRequest; +import flash.system.ApplicationDomain; +import flash.system.LoaderContext; import flash.system.Security; - - import org.flowplayer.model.ErrorCode; - import org.flowplayer.model.Plugin; - import org.flowplayer.controller.NetStreamControllingStreamProvider; - - import com.adobe.utils.StringUtil; - - import org.flowplayer.config.ExternalInterfaceHelper; - import org.flowplayer.controller.StreamProvider; - import org.flowplayer.model.Callable; - import org.flowplayer.model.DisplayPluginModel; - import org.flowplayer.model.FontProvider; - import org.flowplayer.model.Loadable; - import org.flowplayer.model.PlayerError; - import org.flowplayer.model.PluginError; - import org.flowplayer.model.PluginEvent; - import org.flowplayer.model.PluginModel; - import org.flowplayer.model.ProviderModel; - import org.flowplayer.util.Log; - import org.flowplayer.util.URLUtil; - - import flash.display.DisplayObject; - import flash.display.Loader; - import flash.display.LoaderInfo; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.IOErrorEvent; - import flash.events.ProgressEvent; - import flash.net.URLRequest; - import flash.system.ApplicationDomain; - import flash.system.LoaderContext; - import flash.system.SecurityDomain; - import flash.utils.Dictionary; - import flash.utils.getDefinitionByName; - import flash.utils.getQualifiedClassName; - - - /** +import flash.system.SecurityDomain; +import flash.utils.Dictionary; +import flash.utils.getDefinitionByName; +import flash.utils.getQualifiedClassName; + +import org.flowplayer.config.ExternalInterfaceHelper; +import org.flowplayer.controller.NetStreamControllingStreamProvider; +import org.flowplayer.controller.StreamProvider; +import org.flowplayer.model.Callable; +import org.flowplayer.model.DisplayPluginModel; +import org.flowplayer.model.FontProvider; +import org.flowplayer.model.Loadable; +import org.flowplayer.model.Plugin; +import org.flowplayer.model.PluginError; +import org.flowplayer.model.PluginEvent; +import org.flowplayer.model.PluginModel; +import org.flowplayer.model.ProviderModel; +import org.flowplayer.util.DomainUtil; +import org.flowplayer.util.Log; +import org.flowplayer.util.URLUtil; + +/** * @author api */ public class PluginLoader extends EventDispatcher { @@ -79,13 +75,15 @@ import flash.system.Security; private var _allPlugins:Array; private var _loaderContext:LoaderContext; private var _loadStartedCount:int = 0; + private var _secondaries:Array; - public function PluginLoader(baseUrl:String, pluginRegistry:PluginRegistry, errorHandler:ErrorHandler, useExternalInterface:Boolean) { + public function PluginLoader(baseUrl:String, pluginRegistry:PluginRegistry, errorHandler:ErrorHandler, useExternalInterface:Boolean, secondaries:Array) { _baseUrl = baseUrl; _pluginRegistry = pluginRegistry; _errorHandler = errorHandler; _useExternalInterface = useExternalInterface; _loadedCount = 0; + _secondaries = secondaries; } private function constructUrl(url:String):String { @@ -162,7 +160,14 @@ import flash.system.Security; for (var i:Number = 0; i < plugins.length; i++) { var loadable:Loadable = Loadable(plugins[i]); if (! loadable.isBuiltIn && loadable.url && result.indexOf(loadable.url) < 0) { - result.push(constructUrl(loadable.url)); + var pluginUrl:String = constructUrl(loadable.url); + + if (DomainUtil.allowCodeLoading(pluginUrl, _secondaries)) { + result.push(pluginUrl); + } else { + log.error("Unable to load plugin from " + loadable.url); + loadable.dispatchError(PluginError.ERROR, "Unable to load plugin from " + pluginUrl); + } } } return result; diff --git a/core/src/actionscript/org/flowplayer/view/PluginRegistry.as b/core/src/actionscript/org/flowplayer/view/PluginRegistry.as index 5cfaf91..471f8db 100644 --- a/core/src/actionscript/org/flowplayer/view/PluginRegistry.as +++ b/core/src/actionscript/org/flowplayer/view/PluginRegistry.as @@ -75,9 +75,10 @@ package org.flowplayer.view { public function getPlugin(name:String):Object { var plugin:Object = _plugins[name] || _providers[name] || _genericPlugins[name]; log.debug("found plugin " + plugin); - if (plugin is DisplayProperties) { - updateZIndex(plugin as DisplayProperties); - } + //#163 is this needed ? + //if (plugin is DisplayProperties) { + //updateZIndex(plugin as DisplayProperties); + //} return plugin; } @@ -203,6 +204,9 @@ package org.flowplayer.view { for each (var model:Object in transientCopy) { setPlayerToPlugin(model); } + + transientCopy.length = 0; + transientCopy = null; } internal function setPlayerToPlugin(plugin:Object):void { diff --git a/core/src/actionscript/org/flowplayer/view/RotatingAnimation.as b/core/src/actionscript/org/flowplayer/view/RotatingAnimation.as index 90bc5d9..2fb2d92 100644 --- a/core/src/actionscript/org/flowplayer/view/RotatingAnimation.as +++ b/core/src/actionscript/org/flowplayer/view/RotatingAnimation.as @@ -33,10 +33,12 @@ import flash.utils.Timer; } public function start():void { + _rotationTimer.addEventListener(TimerEvent.TIMER, rotate); _rotationTimer.start(); } public function stop():void { + _rotationTimer.removeEventListener(TimerEvent.TIMER, rotate); _rotationTimer.stop(); } diff --git a/core/src/actionscript/org/flowplayer/view/Screen.as b/core/src/actionscript/org/flowplayer/view/Screen.as index f510da6..012e476 100644 --- a/core/src/actionscript/org/flowplayer/view/Screen.as +++ b/core/src/actionscript/org/flowplayer/view/Screen.as @@ -70,6 +70,10 @@ package org.flowplayer.view { _pluginRegistry = pluginRegistry; } + //#163 dummy function for plugin registry + public function onLoad():void {} + + override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { addEventListenerToDisplays(_playList.clips.concat(_playList.childClips), type, listener); @@ -95,9 +99,8 @@ package org.flowplayer.view { private function createDisplays(clips:Array):void { for (var i:Number = 0; i < clips.length; i++) { - var clip:Clip = clips[i]; - if (! clip.isNullClip) { - createDisplay(clip); + if (! clips[i].isNullClip) { + createDisplay(clips[i]); } } } @@ -112,8 +115,6 @@ package org.flowplayer.view { _displays[clip] = display; for(var key:Object in _addDisplayListeners) _addDisplayListeners[key](display); - //#375 clearing the event listeners here prevents new events being added when the playlist is replaced - //_addDisplayListeners = new Dictionary(); } public function setVideoApiOverlaySize(width:Number, height:Number):void { @@ -263,7 +264,14 @@ package org.flowplayer.view { removeChild(_displays[clips[i]]); for(var key:Object in _removeDisplayListeners) _removeDisplayListeners[key](_displays[clips[i]]); + //#163 clear content and empty display list + clips[i].setContent(null); + _displays[clips[i]] = null; + delete _displays[clips[i]]; } + + //#163 initialize display list + _displays.length = 0; //#375 clearing the event listeners here prevents new events being added when the playlist is replaced //_removeDisplayListeners = new Dictionary(); } @@ -293,6 +301,8 @@ package org.flowplayer.view { private function removeOneShotDisplay(event:ClipEvent):void { log.debug("removing display of a one shot clip " + event.target); removeChild(_displays[event.target]); + //#163 clear content + event.target.setContent(null); delete _displays[event.target]; } diff --git a/core/src/javascript/flashembed.js b/core/src/javascript/flashembed.js index 6d81775..8aaa33b 100644 --- a/core/src/javascript/flashembed.js +++ b/core/src/javascript/flashembed.js @@ -88,10 +88,14 @@ conf: GLOBAL_OPTS, getVersion: function() { - var fo, ver; + var fo, ver, plugin; try { - ver = navigator.plugins["Shockwave Flash"].description.slice(16); + plugin = navigator.plugins["Shockwave Flash"]; + // Safari 6 reports version even when disabled + // but [0, 0] should be returned (#167) + if (plugin[0].enabledPlugin != null) + ver = plugin.description.slice(16); } catch(e) { try { diff --git a/core/src/javascript/flowplayer.js/build.xml b/core/src/javascript/flowplayer.js/build.xml deleted file mode 100644 index 1be9454..0000000 --- a/core/src/javascript/flowplayer.js/build.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/src/javascript/flowplayer.js/flowplayer-3.2.12.min.js b/core/src/javascript/flowplayer.js/flowplayer-3.2.12.min.js new file mode 100644 index 0000000..ff7b48f --- /dev/null +++ b/core/src/javascript/flowplayer.js/flowplayer-3.2.12.min.js @@ -0,0 +1,24 @@ +/* + * flowplayer.js 3.2.12. The Flowplayer API + * + * Copyright 2009-2011 Flowplayer Oy + * + * This file is part of Flowplayer. + * + * Flowplayer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Flowplayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Flowplayer. If not, see . + * + * Date: ${date} + * Revision: ${revision} + */ +!function(){function h(p){console.log("$f.fireEvent",[].slice.call(p))}function l(r){if(!r||typeof r!="object"){return r}var p=new r.constructor();for(var q in r){if(r.hasOwnProperty(q)){p[q]=l(r[q])}}return p}function n(u,r){if(!u){return}var p,q=0,s=u.length;if(s===undefined){for(p in u){if(r.call(u[p],p,u[p])===false){break}}}else{for(var t=u[0];q1){var u=arguments[1],r=(arguments.length==3)?arguments[2]:{};if(typeof u=="string"){u={src:u}}u=j({bgcolor:"#000000",version:[10,1],expressInstall:"http://releases.flowplayer.org/swf/expressinstall.swf",cachebusting:false},u);if(typeof p=="string"){if(p.indexOf(".")!=-1){var t=[];n(o(p),function(){t.push(new b(this,l(u),l(r)))});return new d(t)}else{var s=c(p);return new b(s!==null?s:l(p),l(u),l(r))}}else{if(p){return new b(p,l(u),l(r))}}}return null};j(window.$f,{fireEvent:function(){var q=[].slice.call(arguments);var r=$f(q[0]);return r?r._fireEvent(q.slice(1)):null},addPlugin:function(p,q){b.prototype[p]=q;return $f},each:n,extend:j});if(typeof jQuery=="function"){jQuery.fn.flowplayer=function(r,q){if(!arguments.length||typeof arguments[0]=="number"){var p=[];this.each(function(){var s=$f(this);if(s){p.push(s)}});return arguments.length?p[arguments[0]]:new d(p)}return this.each(function(){$f(this,l(r),q?l(q):{})})}}}();!function(){var h=document.all,j="http://get.adobe.com/flashplayer",c=typeof jQuery=="function",e=/(\d+)[^\d]+(\d+)[^\d]*(\d*)/,b={width:"100%",height:"100%",id:"_"+(""+Math.random()).slice(9),allowfullscreen:true,allowscriptaccess:"always",quality:"high",version:[3,0],onFail:null,expressInstall:null,w3c:false,cachebusting:false};if(window.attachEvent){window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}})}function i(m,l){if(l){for(var f in l){if(l.hasOwnProperty(f)){m[f]=l[f]}}}return m}function a(f,n){var m=[];for(var l in f){if(f.hasOwnProperty(l)){m[l]=n(f[l])}}return m}window.flashembed=function(f,m,l){if(typeof f=="string"){f=document.getElementById(f.replace("#",""))}if(!f){return}if(typeof m=="string"){m={src:m}}return new d(f,i(i({},b),m),l)};var g=i(window.flashembed,{conf:b,getVersion:function(){var m,f;try{f=navigator.plugins["Shockwave Flash"].description.slice(16)}catch(o){try{m=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");f=m&&m.GetVariable("$version")}catch(n){try{m=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");f=m&&m.GetVariable("$version")}catch(l){}}}f=e.exec(f);return f?[1*f[1],1*f[(f[1]*1>9?2:3)]*1]:[0,0]},asString:function(l){if(l===null||l===undefined){return null}var f=typeof l;if(f=="object"&&l.push){f="array"}switch(f){case"string":l=l.replace(new RegExp('(["\\\\])',"g"),"\\$1");l=l.replace(/^\s?(\d+\.?\d*)%/,"$1pct");return'"'+l+'"';case"array":return"["+a(l,function(o){return g.asString(o)}).join(",")+"]";case"function":return'"function()"';case"object":var m=[];for(var n in l){if(l.hasOwnProperty(n)){m.push('"'+n+'":'+g.asString(l[n]))}}return"{"+m.join(",")+"}"}return String(l).replace(/\s/g," ").replace(/\'/g,'"')},getHTML:function(o,l){o=i({},o);var n=''}o.width=o.height=o.id=o.w3c=o.src=null;o.onFail=o.version=o.expressInstall=null;for(var m in o){if(o[m]){n+=''}}var p="";if(l){for(var f in l){if(l[f]){var q=l[f];p+=f+"="+(/function|object/.test(typeof q)?g.asString(q):q)+"&"}}p=p.slice(0,-1);n+='"}n+="";return n},isSupported:function(f){return k[0]>f[0]||k[0]==f[0]&&k[1]>=f[1]}});var k=g.getVersion();function d(f,n,m){if(g.isSupported(n.version)){f.innerHTML=g.getHTML(n,m)}else{if(n.expressInstall&&g.isSupported([6,65])){f.innerHTML=g.getHTML(i(n,{src:n.expressInstall}),{MMredirectURL:encodeURIComponent(location.href),MMplayerType:"PlugIn",MMdoctitle:document.title})}else{if(!f.innerHTML.replace(/\s/g,"")){f.innerHTML="

Flash version "+n.version+" or greater is required

"+(k[0]>0?"Your version is "+k:"You have no flash plugin installed")+"

"+(f.tagName=="A"?"

Click here to download latest version

":"

Download latest version from here

");if(f.tagName=="A"||f.tagName=="DIV"){f.onclick=function(){location.href=j}}}if(n.onFail){var l=n.onFail.call(this);if(typeof l=="string"){f.innerHTML=l}}}}if(h){window[n.id]=document.getElementById(n.id)}i(this,{getRoot:function(){return f},getOptions:function(){return n},getConf:function(){return m},getApi:function(){return f.firstChild}})}if(c){jQuery.tools=jQuery.tools||{version:"3.2.12"};jQuery.tools.flashembed={conf:b};jQuery.fn.flashembed=function(l,f){return this.each(function(){$(this).data("flashembed",flashembed(this,l,f))})}}}(); \ No newline at end of file diff --git a/core/src/javascript/flowplayer.js/flowplayer-src.js b/core/src/javascript/flowplayer.js/flowplayer-src.js index 163c98e..c216e56 100644 --- a/core/src/javascript/flowplayer.js/flowplayer-src.js +++ b/core/src/javascript/flowplayer.js/flowplayer-src.js @@ -1,5 +1,5 @@ /*! - * flowplayer.js @VERSION. The Flowplayer API + * flowplayer.js The Flowplayer API * * Copyright 2009-2011 Flowplayer Oy * @@ -18,8 +18,6 @@ * You should have received a copy of the GNU General Public License * along with Flowplayer. If not, see . * - * Date: @DATE - * Revision: @REVISION */ !function() { @@ -262,7 +260,8 @@ } // 1. clip properties, 2-3. metadata, 4. updates, 5. resumes from nested clip - if (arg1 && "onBeforeBegin,onMetaData,onStart,onUpdate,onResume".indexOf(evt) != -1) { + //#148 add onMetaDataChange event to extend clip properties, this was needed to prevent regular updates during stream switching. + if (arg1 && "onBeforeBegin,onMetaData,onMetaDataChange,onStart,onUpdate,onResume".indexOf(evt) != -1) { // update clip properties extend(target, arg1); diff --git a/core/test/analytics.html b/core/test/analytics.html index 407b6e5..e34a0fa 100644 --- a/core/test/analytics.html +++ b/core/test/analytics.html @@ -1,7 +1,8 @@ - + + @@ -16,7 +17,11 @@ id="player"> diff --git a/core/test/audio.html b/core/test/audio.html index 7186265..b7ba659 100644 --- a/core/test/audio.html +++ b/core/test/audio.html @@ -1,7 +1,7 @@ - + @@ -16,9 +16,9 @@ id="player"> + @@ -19,7 +18,7 @@ id="player"> - +
+ + + + + + + + + + + + + +
\ No newline at end of file diff --git a/core/test/extconfig.html b/core/test/extconfig.html index 2b27791..3709728 100644 --- a/core/test/extconfig.html +++ b/core/test/extconfig.html @@ -18,9 +18,9 @@ id="player"> diff --git a/core/test/http-bitrates.html b/core/test/http-bitrates.html index 35f58e2..6f9aa31 100644 --- a/core/test/http-bitrates.html +++ b/core/test/http-bitrates.html @@ -1,7 +1,7 @@ - + @@ -15,10 +15,12 @@ style="display:block;width:440px;height:247px" id="player"> + + + @@ -11,14 +11,14 @@
diff --git a/core/test/instream3.html b/core/test/instream3.html new file mode 100644 index 0000000..8459709 --- /dev/null +++ b/core/test/instream3.html @@ -0,0 +1,75 @@ + + + + + + + + Minimal Flowplayer setup + + + +
+ + + +
+ + + \ No newline at end of file diff --git a/core/test/live-rtmp.html b/core/test/live-rtmp.html index 0f5b26e..cb79d69 100644 --- a/core/test/live-rtmp.html +++ b/core/test/live-rtmp.html @@ -16,15 +16,16 @@ id="player"> + + + + Minimal Flowplayer setup + + + +
+ + + +
+ + + + + + \ No newline at end of file diff --git a/core/test/rtmp-test.html b/core/test/rtmp-test.html index 29beb88..81f2ee4 100644 --- a/core/test/rtmp-test.html +++ b/core/test/rtmp-test.html @@ -15,9 +15,13 @@ id="player"> + + + + Minimal Flowplayer setup + + + +
+ + + +
+ + + \ No newline at end of file diff --git a/core/test/viral.html b/core/test/viral.html index 3b13c59..fae4cda 100644 --- a/core/test/viral.html +++ b/core/test/viral.html @@ -1,7 +1,7 @@ - + @@ -11,12 +11,12 @@
- Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/framework/OSMFTest/html-template/swfobject.js b/lib/osmf/framework/OSMFTest/html-template/swfobject.js index bf35c07..7a9d26f 100644 --- a/lib/osmf/framework/OSMFTest/html-template/swfobject.js +++ b/lib/osmf/framework/OSMFTest/html-template/swfobject.js @@ -1,777 +1,777 @@ -/*! SWFObject v2.2 - is released under the MIT License -*/ - -var swfobject = function() { - - var UNDEF = "undefined", - OBJECT = "object", - SHOCKWAVE_FLASH = "Shockwave Flash", - SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash", - FLASH_MIME_TYPE = "application/x-shockwave-flash", - EXPRESS_INSTALL_ID = "SWFObjectExprInst", - ON_READY_STATE_CHANGE = "onreadystatechange", - - win = window, - doc = document, - nav = navigator, - - plugin = false, - domLoadFnArr = [main], - regObjArr = [], - objIdArr = [], - listenersArr = [], - storedAltContent, - storedAltContentId, - storedCallbackFn, - storedCallbackObj, - isDomLoaded = false, - isExpressInstallActive = false, - dynamicStylesheet, - dynamicStylesheetMedia, - autoHideShow = true, - - /* Centralized function for browser feature detection - - User agent string detection is only used when no good alternative is possible - - Is executed directly for optimal performance - */ - ua = function() { - var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF, - u = nav.userAgent.toLowerCase(), - p = nav.platform.toLowerCase(), - windows = p ? /win/.test(p) : /win/.test(u), - mac = p ? /mac/.test(p) : /mac/.test(u), - webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit - ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html - playerVersion = [0,0,0], - d = null; - if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) { - d = nav.plugins[SHOCKWAVE_FLASH].description; - if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+ - plugin = true; - ie = false; // cascaded feature detection for Internet Explorer - d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1"); - playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10); - playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10); - playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0; - } - } - else if (typeof win.ActiveXObject != UNDEF) { - try { - var a = new ActiveXObject(SHOCKWAVE_FLASH_AX); - if (a) { // a will return null when ActiveX is disabled - d = a.GetVariable("$version"); - if (d) { - ie = true; // cascaded feature detection for Internet Explorer - d = d.split(" ")[1].split(","); - playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; - } - } - } - catch(e) {} - } - return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac }; - }(), - - /* Cross-browser onDomLoad - - Will fire an event as soon as the DOM of a web page is loaded - - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/ - - Regular onload serves as fallback - */ - onDomLoad = function() { - if (!ua.w3) { return; } - if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically - callDomLoadFunctions(); - } - if (!isDomLoaded) { - if (typeof doc.addEventListener != UNDEF) { - doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false); - } - if (ua.ie && ua.win) { - doc.attachEvent(ON_READY_STATE_CHANGE, function() { - if (doc.readyState == "complete") { - doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee); - callDomLoadFunctions(); - } - }); - if (win == top) { // if not inside an iframe - (function(){ - if (isDomLoaded) { return; } - try { - doc.documentElement.doScroll("left"); - } - catch(e) { - setTimeout(arguments.callee, 0); - return; - } - callDomLoadFunctions(); - })(); - } - } - if (ua.wk) { - (function(){ - if (isDomLoaded) { return; } - if (!/loaded|complete/.test(doc.readyState)) { - setTimeout(arguments.callee, 0); - return; - } - callDomLoadFunctions(); - })(); - } - addLoadEvent(callDomLoadFunctions); - } - }(); - - function callDomLoadFunctions() { - if (isDomLoaded) { return; } - try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early - var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span")); - t.parentNode.removeChild(t); - } - catch (e) { return; } - isDomLoaded = true; - var dl = domLoadFnArr.length; - for (var i = 0; i < dl; i++) { - domLoadFnArr[i](); - } - } - - function addDomLoadEvent(fn) { - if (isDomLoaded) { - fn(); - } - else { - domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+ - } - } - - /* Cross-browser onload - - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/ - - Will fire an event as soon as a web page including all of its assets are loaded - */ - function addLoadEvent(fn) { - if (typeof win.addEventListener != UNDEF) { - win.addEventListener("load", fn, false); - } - else if (typeof doc.addEventListener != UNDEF) { - doc.addEventListener("load", fn, false); - } - else if (typeof win.attachEvent != UNDEF) { - addListener(win, "onload", fn); - } - else if (typeof win.onload == "function") { - var fnOld = win.onload; - win.onload = function() { - fnOld(); - fn(); - }; - } - else { - win.onload = fn; - } - } - - /* Main function - - Will preferably execute onDomLoad, otherwise onload (as a fallback) - */ - function main() { - if (plugin) { - testPlayerVersion(); - } - else { - matchVersions(); - } - } - - /* Detect the Flash Player version for non-Internet Explorer browsers - - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description: - a. Both release and build numbers can be detected - b. Avoid wrong descriptions by corrupt installers provided by Adobe - c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports - - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available - */ - function testPlayerVersion() { - var b = doc.getElementsByTagName("body")[0]; - var o = createElement(OBJECT); - o.setAttribute("type", FLASH_MIME_TYPE); - var t = b.appendChild(o); - if (t) { - var counter = 0; - (function(){ - if (typeof t.GetVariable != UNDEF) { - var d = t.GetVariable("$version"); - if (d) { - d = d.split(" ")[1].split(","); - ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; - } - } - else if (counter < 10) { - counter++; - setTimeout(arguments.callee, 10); - return; - } - b.removeChild(o); - t = null; - matchVersions(); - })(); - } - else { - matchVersions(); - } - } - - /* Perform Flash Player and SWF version matching; static publishing only - */ - function matchVersions() { - var rl = regObjArr.length; - if (rl > 0) { - for (var i = 0; i < rl; i++) { // for each registered object element - var id = regObjArr[i].id; - var cb = regObjArr[i].callbackFn; - var cbObj = {success:false, id:id}; - if (ua.pv[0] > 0) { - var obj = getElementById(id); - if (obj) { - if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match! - setVisibility(id, true); - if (cb) { - cbObj.success = true; - cbObj.ref = getObjectById(id); - cb(cbObj); - } - } - else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported - var att = {}; - att.data = regObjArr[i].expressInstall; - att.width = obj.getAttribute("width") || "0"; - att.height = obj.getAttribute("height") || "0"; - if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); } - if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); } - // parse HTML object param element's name-value pairs - var par = {}; - var p = obj.getElementsByTagName("param"); - var pl = p.length; - for (var j = 0; j < pl; j++) { - if (p[j].getAttribute("name").toLowerCase() != "movie") { - par[p[j].getAttribute("name")] = p[j].getAttribute("value"); - } - } - showExpressInstall(att, par, id, cb); - } - else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF - displayAltContent(obj); - if (cb) { cb(cbObj); } - } - } - } - else { // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content) - setVisibility(id, true); - if (cb) { - var o = getObjectById(id); // test whether there is an HTML object element or not - if (o && typeof o.SetVariable != UNDEF) { - cbObj.success = true; - cbObj.ref = o; - } - cb(cbObj); - } - } - } - } - } - - function getObjectById(objectIdStr) { - var r = null; - var o = getElementById(objectIdStr); - if (o && o.nodeName == "OBJECT") { - if (typeof o.SetVariable != UNDEF) { - r = o; - } - else { - var n = o.getElementsByTagName(OBJECT)[0]; - if (n) { - r = n; - } - } - } - return r; - } - - /* Requirements for Adobe Express Install - - only one instance can be active at a time - - fp 6.0.65 or higher - - Win/Mac OS only - - no Webkit engines older than version 312 - */ - function canExpressInstall() { - return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312); - } - - /* Show the Adobe Express Install dialog - - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75 - */ - function showExpressInstall(att, par, replaceElemIdStr, callbackFn) { - isExpressInstallActive = true; - storedCallbackFn = callbackFn || null; - storedCallbackObj = {success:false, id:replaceElemIdStr}; - var obj = getElementById(replaceElemIdStr); - if (obj) { - if (obj.nodeName == "OBJECT") { // static publishing - storedAltContent = abstractAltContent(obj); - storedAltContentId = null; - } - else { // dynamic publishing - storedAltContent = obj; - storedAltContentId = replaceElemIdStr; - } - att.id = EXPRESS_INSTALL_ID; - if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; } - if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; } - doc.title = doc.title.slice(0, 47) + " - Flash Player Installation"; - var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn", - fv = "MMredirectURL=" + encodeURI(window.location).toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title; - if (typeof par.flashvars != UNDEF) { - par.flashvars += "&" + fv; - } - else { - par.flashvars = fv; - } - // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, - // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work - if (ua.ie && ua.win && obj.readyState != 4) { - var newObj = createElement("div"); - replaceElemIdStr += "SWFObjectNew"; - newObj.setAttribute("id", replaceElemIdStr); - obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf - obj.style.display = "none"; - (function(){ - if (obj.readyState == 4) { - obj.parentNode.removeChild(obj); - } - else { - setTimeout(arguments.callee, 10); - } - })(); - } - createSWF(att, par, replaceElemIdStr); - } - } - - /* Functions to abstract and display alternative content - */ - function displayAltContent(obj) { - if (ua.ie && ua.win && obj.readyState != 4) { - // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, - // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work - var el = createElement("div"); - obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content - el.parentNode.replaceChild(abstractAltContent(obj), el); - obj.style.display = "none"; - (function(){ - if (obj.readyState == 4) { - obj.parentNode.removeChild(obj); - } - else { - setTimeout(arguments.callee, 10); - } - })(); - } - else { - obj.parentNode.replaceChild(abstractAltContent(obj), obj); - } - } - - function abstractAltContent(obj) { - var ac = createElement("div"); - if (ua.win && ua.ie) { - ac.innerHTML = obj.innerHTML; - } - else { - var nestedObj = obj.getElementsByTagName(OBJECT)[0]; - if (nestedObj) { - var c = nestedObj.childNodes; - if (c) { - var cl = c.length; - for (var i = 0; i < cl; i++) { - if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) { - ac.appendChild(c[i].cloneNode(true)); - } - } - } - } - } - return ac; - } - - /* Cross-browser dynamic SWF creation - */ - function createSWF(attObj, parObj, id) { - var r, el = getElementById(id); - if (ua.wk && ua.wk < 312) { return r; } - if (el) { - if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content - attObj.id = id; - } - if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML - var att = ""; - for (var i in attObj) { - if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries - if (i.toLowerCase() == "data") { - parObj.movie = attObj[i]; - } - else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword - att += ' class="' + attObj[i] + '"'; - } - else if (i.toLowerCase() != "classid") { - att += ' ' + i + '="' + attObj[i] + '"'; - } - } - } - var par = ""; - for (var j in parObj) { - if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries - par += ''; - } - } - el.outerHTML = '' + par + ''; - objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only) - r = getElementById(attObj.id); - } - else { // well-behaving browsers - var o = createElement(OBJECT); - o.setAttribute("type", FLASH_MIME_TYPE); - for (var m in attObj) { - if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries - if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword - o.setAttribute("class", attObj[m]); - } - else if (m.toLowerCase() != "classid") { // filter out IE specific attribute - o.setAttribute(m, attObj[m]); - } - } - } - for (var n in parObj) { - if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element - createObjParam(o, n, parObj[n]); - } - } - el.parentNode.replaceChild(o, el); - r = o; - } - } - return r; - } - - function createObjParam(el, pName, pValue) { - var p = createElement("param"); - p.setAttribute("name", pName); - p.setAttribute("value", pValue); - el.appendChild(p); - } - - /* Cross-browser SWF removal - - Especially needed to safely and completely remove a SWF in Internet Explorer - */ - function removeSWF(id) { - var obj = getElementById(id); - if (obj && obj.nodeName == "OBJECT") { - if (ua.ie && ua.win) { - obj.style.display = "none"; - (function(){ - if (obj.readyState == 4) { - removeObjectInIE(id); - } - else { - setTimeout(arguments.callee, 10); - } - })(); - } - else { - obj.parentNode.removeChild(obj); - } - } - } - - function removeObjectInIE(id) { - var obj = getElementById(id); - if (obj) { - for (var i in obj) { - if (typeof obj[i] == "function") { - obj[i] = null; - } - } - obj.parentNode.removeChild(obj); - } - } - - /* Functions to optimize JavaScript compression - */ - function getElementById(id) { - var el = null; - try { - el = doc.getElementById(id); - } - catch (e) {} - return el; - } - - function createElement(el) { - return doc.createElement(el); - } - - /* Updated attachEvent function for Internet Explorer - - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks - */ - function addListener(target, eventType, fn) { - target.attachEvent(eventType, fn); - listenersArr[listenersArr.length] = [target, eventType, fn]; - } - - /* Flash Player and SWF content version matching - */ - function hasPlayerVersion(rv) { - var pv = ua.pv, v = rv.split("."); - v[0] = parseInt(v[0], 10); - v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0" - v[2] = parseInt(v[2], 10) || 0; - return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false; - } - - /* Cross-browser dynamic CSS creation - - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php - */ - function createCSS(sel, decl, media, newStyle) { - if (ua.ie && ua.mac) { return; } - var h = doc.getElementsByTagName("head")[0]; - if (!h) { return; } // to also support badly authored HTML pages that lack a head element - var m = (media && typeof media == "string") ? media : "screen"; - if (newStyle) { - dynamicStylesheet = null; - dynamicStylesheetMedia = null; - } - if (!dynamicStylesheet || dynamicStylesheetMedia != m) { - // create dynamic stylesheet + get a global reference to it - var s = createElement("style"); - s.setAttribute("type", "text/css"); - s.setAttribute("media", m); - dynamicStylesheet = h.appendChild(s); - if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) { - dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1]; - } - dynamicStylesheetMedia = m; - } - // add style rule - if (ua.ie && ua.win) { - if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) { - dynamicStylesheet.addRule(sel, decl); - } - } - else { - if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) { - dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}")); - } - } - } - - function setVisibility(id, isVisible) { - if (!autoHideShow) { return; } - var v = isVisible ? "visible" : "hidden"; - if (isDomLoaded && getElementById(id)) { - getElementById(id).style.visibility = v; - } - else { - createCSS("#" + id, "visibility:" + v); - } - } - - /* Filter to avoid XSS attacks - */ - function urlEncodeIfNecessary(s) { - var regex = /[\\\"<>\.;]/; - var hasBadChars = regex.exec(s) != null; - return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s; - } - - /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only) - */ - var cleanup = function() { - if (ua.ie && ua.win) { - window.attachEvent("onunload", function() { - // remove listeners to avoid memory leaks - var ll = listenersArr.length; - for (var i = 0; i < ll; i++) { - listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]); - } - // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect - var il = objIdArr.length; - for (var j = 0; j < il; j++) { - removeSWF(objIdArr[j]); - } - // cleanup library's main closures to avoid memory leaks - for (var k in ua) { - ua[k] = null; - } - ua = null; - for (var l in swfobject) { - swfobject[l] = null; - } - swfobject = null; - }); - } - }(); - - return { - /* Public API - - Reference: http://code.google.com/p/swfobject/wiki/documentation - */ - registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) { - if (ua.w3 && objectIdStr && swfVersionStr) { - var regObj = {}; - regObj.id = objectIdStr; - regObj.swfVersion = swfVersionStr; - regObj.expressInstall = xiSwfUrlStr; - regObj.callbackFn = callbackFn; - regObjArr[regObjArr.length] = regObj; - setVisibility(objectIdStr, false); - } - else if (callbackFn) { - callbackFn({success:false, id:objectIdStr}); - } - }, - - getObjectById: function(objectIdStr) { - if (ua.w3) { - return getObjectById(objectIdStr); - } - }, - - embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) { - var callbackObj = {success:false, id:replaceElemIdStr}; - if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) { - setVisibility(replaceElemIdStr, false); - addDomLoadEvent(function() { - widthStr += ""; // auto-convert to string - heightStr += ""; - var att = {}; - if (attObj && typeof attObj === OBJECT) { - for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs - att[i] = attObj[i]; - } - } - att.data = swfUrlStr; - att.width = widthStr; - att.height = heightStr; - var par = {}; - if (parObj && typeof parObj === OBJECT) { - for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs - par[j] = parObj[j]; - } - } - if (flashvarsObj && typeof flashvarsObj === OBJECT) { - for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs - if (typeof par.flashvars != UNDEF) { - par.flashvars += "&" + k + "=" + flashvarsObj[k]; - } - else { - par.flashvars = k + "=" + flashvarsObj[k]; - } - } - } - if (hasPlayerVersion(swfVersionStr)) { // create SWF - var obj = createSWF(att, par, replaceElemIdStr); - if (att.id == replaceElemIdStr) { - setVisibility(replaceElemIdStr, true); - } - callbackObj.success = true; - callbackObj.ref = obj; - } - else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install - att.data = xiSwfUrlStr; - showExpressInstall(att, par, replaceElemIdStr, callbackFn); - return; - } - else { // show alternative content - setVisibility(replaceElemIdStr, true); - } - if (callbackFn) { callbackFn(callbackObj); } - }); - } - else if (callbackFn) { callbackFn(callbackObj); } - }, - - switchOffAutoHideShow: function() { - autoHideShow = false; - }, - - ua: ua, - - getFlashPlayerVersion: function() { - return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] }; - }, - - hasFlashPlayerVersion: hasPlayerVersion, - - createSWF: function(attObj, parObj, replaceElemIdStr) { - if (ua.w3) { - return createSWF(attObj, parObj, replaceElemIdStr); - } - else { - return undefined; - } - }, - - showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) { - if (ua.w3 && canExpressInstall()) { - showExpressInstall(att, par, replaceElemIdStr, callbackFn); - } - }, - - removeSWF: function(objElemIdStr) { - if (ua.w3) { - removeSWF(objElemIdStr); - } - }, - - createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) { - if (ua.w3) { - createCSS(selStr, declStr, mediaStr, newStyleBoolean); - } - }, - - addDomLoadEvent: addDomLoadEvent, - - addLoadEvent: addLoadEvent, - - getQueryParamValue: function(param) { - var q = doc.location.search || doc.location.hash; - if (q) { - if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark - if (param == null) { - return urlEncodeIfNecessary(q); - } - var pairs = q.split("&"); - for (var i = 0; i < pairs.length; i++) { - if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) { - return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1))); - } - } - } - return ""; - }, - - // For internal usage only - expressInstallCallback: function() { - if (isExpressInstallActive) { - var obj = getElementById(EXPRESS_INSTALL_ID); - if (obj && storedAltContent) { - obj.parentNode.replaceChild(storedAltContent, obj); - if (storedAltContentId) { - setVisibility(storedAltContentId, true); - if (ua.ie && ua.win) { storedAltContent.style.display = "block"; } - } - if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); } - } - isExpressInstallActive = false; - } - } - }; -}(); +/*! SWFObject v2.2 + is released under the MIT License +*/ + +var swfobject = function() { + + var UNDEF = "undefined", + OBJECT = "object", + SHOCKWAVE_FLASH = "Shockwave Flash", + SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash", + FLASH_MIME_TYPE = "application/x-shockwave-flash", + EXPRESS_INSTALL_ID = "SWFObjectExprInst", + ON_READY_STATE_CHANGE = "onreadystatechange", + + win = window, + doc = document, + nav = navigator, + + plugin = false, + domLoadFnArr = [main], + regObjArr = [], + objIdArr = [], + listenersArr = [], + storedAltContent, + storedAltContentId, + storedCallbackFn, + storedCallbackObj, + isDomLoaded = false, + isExpressInstallActive = false, + dynamicStylesheet, + dynamicStylesheetMedia, + autoHideShow = true, + + /* Centralized function for browser feature detection + - User agent string detection is only used when no good alternative is possible + - Is executed directly for optimal performance + */ + ua = function() { + var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF, + u = nav.userAgent.toLowerCase(), + p = nav.platform.toLowerCase(), + windows = p ? /win/.test(p) : /win/.test(u), + mac = p ? /mac/.test(p) : /mac/.test(u), + webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit + ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html + playerVersion = [0,0,0], + d = null; + if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) { + d = nav.plugins[SHOCKWAVE_FLASH].description; + if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+ + plugin = true; + ie = false; // cascaded feature detection for Internet Explorer + d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1"); + playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10); + playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10); + playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0; + } + } + else if (typeof win.ActiveXObject != UNDEF) { + try { + var a = new ActiveXObject(SHOCKWAVE_FLASH_AX); + if (a) { // a will return null when ActiveX is disabled + d = a.GetVariable("$version"); + if (d) { + ie = true; // cascaded feature detection for Internet Explorer + d = d.split(" ")[1].split(","); + playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; + } + } + } + catch(e) {} + } + return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac }; + }(), + + /* Cross-browser onDomLoad + - Will fire an event as soon as the DOM of a web page is loaded + - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/ + - Regular onload serves as fallback + */ + onDomLoad = function() { + if (!ua.w3) { return; } + if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically + callDomLoadFunctions(); + } + if (!isDomLoaded) { + if (typeof doc.addEventListener != UNDEF) { + doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false); + } + if (ua.ie && ua.win) { + doc.attachEvent(ON_READY_STATE_CHANGE, function() { + if (doc.readyState == "complete") { + doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee); + callDomLoadFunctions(); + } + }); + if (win == top) { // if not inside an iframe + (function(){ + if (isDomLoaded) { return; } + try { + doc.documentElement.doScroll("left"); + } + catch(e) { + setTimeout(arguments.callee, 0); + return; + } + callDomLoadFunctions(); + })(); + } + } + if (ua.wk) { + (function(){ + if (isDomLoaded) { return; } + if (!/loaded|complete/.test(doc.readyState)) { + setTimeout(arguments.callee, 0); + return; + } + callDomLoadFunctions(); + })(); + } + addLoadEvent(callDomLoadFunctions); + } + }(); + + function callDomLoadFunctions() { + if (isDomLoaded) { return; } + try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early + var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span")); + t.parentNode.removeChild(t); + } + catch (e) { return; } + isDomLoaded = true; + var dl = domLoadFnArr.length; + for (var i = 0; i < dl; i++) { + domLoadFnArr[i](); + } + } + + function addDomLoadEvent(fn) { + if (isDomLoaded) { + fn(); + } + else { + domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+ + } + } + + /* Cross-browser onload + - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/ + - Will fire an event as soon as a web page including all of its assets are loaded + */ + function addLoadEvent(fn) { + if (typeof win.addEventListener != UNDEF) { + win.addEventListener("load", fn, false); + } + else if (typeof doc.addEventListener != UNDEF) { + doc.addEventListener("load", fn, false); + } + else if (typeof win.attachEvent != UNDEF) { + addListener(win, "onload", fn); + } + else if (typeof win.onload == "function") { + var fnOld = win.onload; + win.onload = function() { + fnOld(); + fn(); + }; + } + else { + win.onload = fn; + } + } + + /* Main function + - Will preferably execute onDomLoad, otherwise onload (as a fallback) + */ + function main() { + if (plugin) { + testPlayerVersion(); + } + else { + matchVersions(); + } + } + + /* Detect the Flash Player version for non-Internet Explorer browsers + - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description: + a. Both release and build numbers can be detected + b. Avoid wrong descriptions by corrupt installers provided by Adobe + c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports + - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available + */ + function testPlayerVersion() { + var b = doc.getElementsByTagName("body")[0]; + var o = createElement(OBJECT); + o.setAttribute("type", FLASH_MIME_TYPE); + var t = b.appendChild(o); + if (t) { + var counter = 0; + (function(){ + if (typeof t.GetVariable != UNDEF) { + var d = t.GetVariable("$version"); + if (d) { + d = d.split(" ")[1].split(","); + ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; + } + } + else if (counter < 10) { + counter++; + setTimeout(arguments.callee, 10); + return; + } + b.removeChild(o); + t = null; + matchVersions(); + })(); + } + else { + matchVersions(); + } + } + + /* Perform Flash Player and SWF version matching; static publishing only + */ + function matchVersions() { + var rl = regObjArr.length; + if (rl > 0) { + for (var i = 0; i < rl; i++) { // for each registered object element + var id = regObjArr[i].id; + var cb = regObjArr[i].callbackFn; + var cbObj = {success:false, id:id}; + if (ua.pv[0] > 0) { + var obj = getElementById(id); + if (obj) { + if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match! + setVisibility(id, true); + if (cb) { + cbObj.success = true; + cbObj.ref = getObjectById(id); + cb(cbObj); + } + } + else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported + var att = {}; + att.data = regObjArr[i].expressInstall; + att.width = obj.getAttribute("width") || "0"; + att.height = obj.getAttribute("height") || "0"; + if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); } + if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); } + // parse HTML object param element's name-value pairs + var par = {}; + var p = obj.getElementsByTagName("param"); + var pl = p.length; + for (var j = 0; j < pl; j++) { + if (p[j].getAttribute("name").toLowerCase() != "movie") { + par[p[j].getAttribute("name")] = p[j].getAttribute("value"); + } + } + showExpressInstall(att, par, id, cb); + } + else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF + displayAltContent(obj); + if (cb) { cb(cbObj); } + } + } + } + else { // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content) + setVisibility(id, true); + if (cb) { + var o = getObjectById(id); // test whether there is an HTML object element or not + if (o && typeof o.SetVariable != UNDEF) { + cbObj.success = true; + cbObj.ref = o; + } + cb(cbObj); + } + } + } + } + } + + function getObjectById(objectIdStr) { + var r = null; + var o = getElementById(objectIdStr); + if (o && o.nodeName == "OBJECT") { + if (typeof o.SetVariable != UNDEF) { + r = o; + } + else { + var n = o.getElementsByTagName(OBJECT)[0]; + if (n) { + r = n; + } + } + } + return r; + } + + /* Requirements for Adobe Express Install + - only one instance can be active at a time + - fp 6.0.65 or higher + - Win/Mac OS only + - no Webkit engines older than version 312 + */ + function canExpressInstall() { + return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312); + } + + /* Show the Adobe Express Install dialog + - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75 + */ + function showExpressInstall(att, par, replaceElemIdStr, callbackFn) { + isExpressInstallActive = true; + storedCallbackFn = callbackFn || null; + storedCallbackObj = {success:false, id:replaceElemIdStr}; + var obj = getElementById(replaceElemIdStr); + if (obj) { + if (obj.nodeName == "OBJECT") { // static publishing + storedAltContent = abstractAltContent(obj); + storedAltContentId = null; + } + else { // dynamic publishing + storedAltContent = obj; + storedAltContentId = replaceElemIdStr; + } + att.id = EXPRESS_INSTALL_ID; + if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; } + if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; } + doc.title = doc.title.slice(0, 47) + " - Flash Player Installation"; + var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn", + fv = "MMredirectURL=" + encodeURI(window.location).toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title; + if (typeof par.flashvars != UNDEF) { + par.flashvars += "&" + fv; + } + else { + par.flashvars = fv; + } + // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, + // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work + if (ua.ie && ua.win && obj.readyState != 4) { + var newObj = createElement("div"); + replaceElemIdStr += "SWFObjectNew"; + newObj.setAttribute("id", replaceElemIdStr); + obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf + obj.style.display = "none"; + (function(){ + if (obj.readyState == 4) { + obj.parentNode.removeChild(obj); + } + else { + setTimeout(arguments.callee, 10); + } + })(); + } + createSWF(att, par, replaceElemIdStr); + } + } + + /* Functions to abstract and display alternative content + */ + function displayAltContent(obj) { + if (ua.ie && ua.win && obj.readyState != 4) { + // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, + // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work + var el = createElement("div"); + obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content + el.parentNode.replaceChild(abstractAltContent(obj), el); + obj.style.display = "none"; + (function(){ + if (obj.readyState == 4) { + obj.parentNode.removeChild(obj); + } + else { + setTimeout(arguments.callee, 10); + } + })(); + } + else { + obj.parentNode.replaceChild(abstractAltContent(obj), obj); + } + } + + function abstractAltContent(obj) { + var ac = createElement("div"); + if (ua.win && ua.ie) { + ac.innerHTML = obj.innerHTML; + } + else { + var nestedObj = obj.getElementsByTagName(OBJECT)[0]; + if (nestedObj) { + var c = nestedObj.childNodes; + if (c) { + var cl = c.length; + for (var i = 0; i < cl; i++) { + if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) { + ac.appendChild(c[i].cloneNode(true)); + } + } + } + } + } + return ac; + } + + /* Cross-browser dynamic SWF creation + */ + function createSWF(attObj, parObj, id) { + var r, el = getElementById(id); + if (ua.wk && ua.wk < 312) { return r; } + if (el) { + if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content + attObj.id = id; + } + if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML + var att = ""; + for (var i in attObj) { + if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries + if (i.toLowerCase() == "data") { + parObj.movie = attObj[i]; + } + else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword + att += ' class="' + attObj[i] + '"'; + } + else if (i.toLowerCase() != "classid") { + att += ' ' + i + '="' + attObj[i] + '"'; + } + } + } + var par = ""; + for (var j in parObj) { + if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries + par += ''; + } + } + el.outerHTML = '' + par + ''; + objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only) + r = getElementById(attObj.id); + } + else { // well-behaving browsers + var o = createElement(OBJECT); + o.setAttribute("type", FLASH_MIME_TYPE); + for (var m in attObj) { + if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries + if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword + o.setAttribute("class", attObj[m]); + } + else if (m.toLowerCase() != "classid") { // filter out IE specific attribute + o.setAttribute(m, attObj[m]); + } + } + } + for (var n in parObj) { + if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element + createObjParam(o, n, parObj[n]); + } + } + el.parentNode.replaceChild(o, el); + r = o; + } + } + return r; + } + + function createObjParam(el, pName, pValue) { + var p = createElement("param"); + p.setAttribute("name", pName); + p.setAttribute("value", pValue); + el.appendChild(p); + } + + /* Cross-browser SWF removal + - Especially needed to safely and completely remove a SWF in Internet Explorer + */ + function removeSWF(id) { + var obj = getElementById(id); + if (obj && obj.nodeName == "OBJECT") { + if (ua.ie && ua.win) { + obj.style.display = "none"; + (function(){ + if (obj.readyState == 4) { + removeObjectInIE(id); + } + else { + setTimeout(arguments.callee, 10); + } + })(); + } + else { + obj.parentNode.removeChild(obj); + } + } + } + + function removeObjectInIE(id) { + var obj = getElementById(id); + if (obj) { + for (var i in obj) { + if (typeof obj[i] == "function") { + obj[i] = null; + } + } + obj.parentNode.removeChild(obj); + } + } + + /* Functions to optimize JavaScript compression + */ + function getElementById(id) { + var el = null; + try { + el = doc.getElementById(id); + } + catch (e) {} + return el; + } + + function createElement(el) { + return doc.createElement(el); + } + + /* Updated attachEvent function for Internet Explorer + - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks + */ + function addListener(target, eventType, fn) { + target.attachEvent(eventType, fn); + listenersArr[listenersArr.length] = [target, eventType, fn]; + } + + /* Flash Player and SWF content version matching + */ + function hasPlayerVersion(rv) { + var pv = ua.pv, v = rv.split("."); + v[0] = parseInt(v[0], 10); + v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0" + v[2] = parseInt(v[2], 10) || 0; + return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false; + } + + /* Cross-browser dynamic CSS creation + - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php + */ + function createCSS(sel, decl, media, newStyle) { + if (ua.ie && ua.mac) { return; } + var h = doc.getElementsByTagName("head")[0]; + if (!h) { return; } // to also support badly authored HTML pages that lack a head element + var m = (media && typeof media == "string") ? media : "screen"; + if (newStyle) { + dynamicStylesheet = null; + dynamicStylesheetMedia = null; + } + if (!dynamicStylesheet || dynamicStylesheetMedia != m) { + // create dynamic stylesheet + get a global reference to it + var s = createElement("style"); + s.setAttribute("type", "text/css"); + s.setAttribute("media", m); + dynamicStylesheet = h.appendChild(s); + if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) { + dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1]; + } + dynamicStylesheetMedia = m; + } + // add style rule + if (ua.ie && ua.win) { + if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) { + dynamicStylesheet.addRule(sel, decl); + } + } + else { + if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) { + dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}")); + } + } + } + + function setVisibility(id, isVisible) { + if (!autoHideShow) { return; } + var v = isVisible ? "visible" : "hidden"; + if (isDomLoaded && getElementById(id)) { + getElementById(id).style.visibility = v; + } + else { + createCSS("#" + id, "visibility:" + v); + } + } + + /* Filter to avoid XSS attacks + */ + function urlEncodeIfNecessary(s) { + var regex = /[\\\"<>\.;]/; + var hasBadChars = regex.exec(s) != null; + return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s; + } + + /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only) + */ + var cleanup = function() { + if (ua.ie && ua.win) { + window.attachEvent("onunload", function() { + // remove listeners to avoid memory leaks + var ll = listenersArr.length; + for (var i = 0; i < ll; i++) { + listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]); + } + // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect + var il = objIdArr.length; + for (var j = 0; j < il; j++) { + removeSWF(objIdArr[j]); + } + // cleanup library's main closures to avoid memory leaks + for (var k in ua) { + ua[k] = null; + } + ua = null; + for (var l in swfobject) { + swfobject[l] = null; + } + swfobject = null; + }); + } + }(); + + return { + /* Public API + - Reference: http://code.google.com/p/swfobject/wiki/documentation + */ + registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) { + if (ua.w3 && objectIdStr && swfVersionStr) { + var regObj = {}; + regObj.id = objectIdStr; + regObj.swfVersion = swfVersionStr; + regObj.expressInstall = xiSwfUrlStr; + regObj.callbackFn = callbackFn; + regObjArr[regObjArr.length] = regObj; + setVisibility(objectIdStr, false); + } + else if (callbackFn) { + callbackFn({success:false, id:objectIdStr}); + } + }, + + getObjectById: function(objectIdStr) { + if (ua.w3) { + return getObjectById(objectIdStr); + } + }, + + embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) { + var callbackObj = {success:false, id:replaceElemIdStr}; + if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) { + setVisibility(replaceElemIdStr, false); + addDomLoadEvent(function() { + widthStr += ""; // auto-convert to string + heightStr += ""; + var att = {}; + if (attObj && typeof attObj === OBJECT) { + for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs + att[i] = attObj[i]; + } + } + att.data = swfUrlStr; + att.width = widthStr; + att.height = heightStr; + var par = {}; + if (parObj && typeof parObj === OBJECT) { + for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs + par[j] = parObj[j]; + } + } + if (flashvarsObj && typeof flashvarsObj === OBJECT) { + for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs + if (typeof par.flashvars != UNDEF) { + par.flashvars += "&" + k + "=" + flashvarsObj[k]; + } + else { + par.flashvars = k + "=" + flashvarsObj[k]; + } + } + } + if (hasPlayerVersion(swfVersionStr)) { // create SWF + var obj = createSWF(att, par, replaceElemIdStr); + if (att.id == replaceElemIdStr) { + setVisibility(replaceElemIdStr, true); + } + callbackObj.success = true; + callbackObj.ref = obj; + } + else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install + att.data = xiSwfUrlStr; + showExpressInstall(att, par, replaceElemIdStr, callbackFn); + return; + } + else { // show alternative content + setVisibility(replaceElemIdStr, true); + } + if (callbackFn) { callbackFn(callbackObj); } + }); + } + else if (callbackFn) { callbackFn(callbackObj); } + }, + + switchOffAutoHideShow: function() { + autoHideShow = false; + }, + + ua: ua, + + getFlashPlayerVersion: function() { + return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] }; + }, + + hasFlashPlayerVersion: hasPlayerVersion, + + createSWF: function(attObj, parObj, replaceElemIdStr) { + if (ua.w3) { + return createSWF(attObj, parObj, replaceElemIdStr); + } + else { + return undefined; + } + }, + + showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) { + if (ua.w3 && canExpressInstall()) { + showExpressInstall(att, par, replaceElemIdStr, callbackFn); + } + }, + + removeSWF: function(objElemIdStr) { + if (ua.w3) { + removeSWF(objElemIdStr); + } + }, + + createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) { + if (ua.w3) { + createCSS(selStr, declStr, mediaStr, newStyleBoolean); + } + }, + + addDomLoadEvent: addDomLoadEvent, + + addLoadEvent: addLoadEvent, + + getQueryParamValue: function(param) { + var q = doc.location.search || doc.location.hash; + if (q) { + if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark + if (param == null) { + return urlEncodeIfNecessary(q); + } + var pairs = q.split("&"); + for (var i = 0; i < pairs.length; i++) { + if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) { + return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1))); + } + } + } + return ""; + }, + + // For internal usage only + expressInstallCallback: function() { + if (isExpressInstallActive) { + var obj = getElementById(EXPRESS_INSTALL_ID); + if (obj && storedAltContent) { + obj.parentNode.replaceChild(storedAltContent, obj); + if (storedAltContentId) { + setVisibility(storedAltContentId, true); + if (ua.ie && ua.win) { storedAltContent.style.display = "block"; } + } + if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); } + } + isExpressInstallActive = false; + } + } + }; +}(); diff --git a/lib/osmf/framework/OSMFTest/src/FlexUnitApplication-app.xml b/lib/osmf/framework/OSMFTest/src/FlexUnitApplication-app.xml deleted file mode 100644 index cc3fe6b..0000000 --- a/lib/osmf/framework/OSMFTest/src/FlexUnitApplication-app.xml +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - - FlexUnitApplication - - - FlexUnitApplication - - - FlexUnitApplication - - - 0.0.0 - - - - - - - - - - - - - - - - - - [This value will be overwritten by Flash Builder in the output app.xml] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/osmf/framework/OSMFTest/src/FlexUnitApplication.mxml b/lib/osmf/framework/OSMFTest/src/FlexUnitApplication.mxml deleted file mode 100644 index 553bde9..0000000 --- a/lib/osmf/framework/OSMFTest/src/FlexUnitApplication.mxml +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - - - - - diff --git a/lib/osmf/framework/OSMFTest/src/OSMFTest-app.xml b/lib/osmf/framework/OSMFTest/src/OSMFTest-app.xml deleted file mode 100644 index e230b4a..0000000 --- a/lib/osmf/framework/OSMFTest/src/OSMFTest-app.xml +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - - OSMFTest - - - OSMFTest - - - OSMFTest - - - 0.0.0 - - - - - - - - - - - - - - - - - - [This value will be overwritten by Flash Builder in the output app.xml] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/osmf/framework/OSMFTest/src/OSMFTest.mxml b/lib/osmf/framework/OSMFTest/src/OSMFTest.mxml index 016eebc..5f08fb6 100644 --- a/lib/osmf/framework/OSMFTest/src/OSMFTest.mxml +++ b/lib/osmf/framework/OSMFTest/src/OSMFTest.mxml @@ -2,184 +2,15 @@ - + @@ -201,4 +32,4 @@ - + diff --git a/lib/osmf/framework/OSMFTest/src/OSMFTests.as b/lib/osmf/framework/OSMFTest/src/OSMFTests.as new file mode 100644 index 0000000..775123d --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/OSMFTests.as @@ -0,0 +1,255 @@ +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import org.osmf.containers.TestHTMLMediaContainer; + import org.osmf.containers.TestMediaContainer; + import org.osmf.events.TestMediaError; + import org.osmf.events.TestMediaErrorAsSubclass; + import org.osmf.layout.TestAbsoluteLayoutMetadata; + import org.osmf.layout.TestAnchorLayoutMetadata; + import org.osmf.layout.TestBinarySearch; + import org.osmf.layout.TestBoxAttributesMetadata; + import org.osmf.layout.TestGenericLayout; + import org.osmf.layout.TestLayoutAttributesMetadata; + import org.osmf.layout.TestLayoutMetadata; + import org.osmf.layout.TestLayoutRenderer; + import org.osmf.layout.TestLayoutRendererBase; + import org.osmf.layout.TestLayoutTargetEvent; + import org.osmf.layout.TestLayoutTargetRenderers; + import org.osmf.layout.TestLayoutTargetSprite; + import org.osmf.layout.TestMediaElementLayoutTarget; + import org.osmf.layout.TestOverlayLayoutMetadata; + import org.osmf.layout.TestPaddingLayoutMetadata; + import org.osmf.layout.TestRelativeLayoutMetadata; + import org.osmf.layout.TestScaleModeUtils; + import org.osmf.logging.TestLog; + import org.osmf.media.MediaTraitResolverBaseTestCase; + import org.osmf.media.TestDefaultMediaFactory; + import org.osmf.media.TestDefaultTraitResolver; + import org.osmf.media.TestLoadableElementBase; + import org.osmf.media.TestMediaElement; + import org.osmf.media.TestMediaElementAsSubclass; + import org.osmf.media.TestMediaFactory; + import org.osmf.media.TestMediaFactoryItem; + import org.osmf.media.TestMediaPlayer; + import org.osmf.media.TestMediaPlayerSprite; + import org.osmf.media.TestMediaPlayerWithAudioElement; + import org.osmf.media.TestMediaPlayerWithAudioElementWithSoundLoader; + import org.osmf.media.TestMediaPlayerWithBeaconElement; + import org.osmf.media.TestMediaPlayerWithDurationElement; + import org.osmf.media.TestMediaPlayerWithDynamicStreamingVideoElement; + import org.osmf.media.TestMediaPlayerWithDynamicStreamingVideoElementSubclip; + import org.osmf.media.TestMediaPlayerWithLightweightVideoElement; + import org.osmf.media.TestMediaPlayerWithProxyElement; + import org.osmf.media.TestMediaPlayerWithSerialElementWithDurationElements; + import org.osmf.media.TestMediaPlayerWithVideoElement; + import org.osmf.media.TestMediaPlayerWithVideoElementSubclip; + import org.osmf.media.TestMediaTraitResolver; + import org.osmf.media.TestMediaType; + import org.osmf.media.TestMediaTypeUtil; + import org.osmf.media.TestPluginInfo; + import org.osmf.media.TestURLResource; + import org.osmf.media.pluginClasses.TestDynamicPluginLoader; + import org.osmf.media.pluginClasses.TestPluginElement; + import org.osmf.media.pluginClasses.TestPluginLoadingState; + import org.osmf.media.pluginClasses.TestPluginManager; + import org.osmf.media.pluginClasses.TestStaticPluginLoader; + import org.osmf.metadata.TestCuePoint; + import org.osmf.metadata.TestMetadata; + import org.osmf.metadata.TestMetadataWatcher; + import org.osmf.metadata.TestTimelineMarker; + import org.osmf.metadata.TestTimelineMetadata; + import org.osmf.net.TestDynamicStreamingItem; + import org.osmf.net.TestDynamicStreamingResource; + import org.osmf.net.TestSwitchManager; + import org.osmf.net.drm.TestDRMServices; + import org.osmf.net.metrics.TestActualBitrateMetric; + import org.osmf.net.metrics.TestAvailableQualityLevelsMetric; + import org.osmf.net.metrics.TestBandwidthMetric; + import org.osmf.net.metrics.TestBufferFragmentsMetric; + import org.osmf.net.metrics.TestBufferLengthMetric; + import org.osmf.net.metrics.TestBufferOccupationRatioMetric; + import org.osmf.net.metrics.TestCurrentStatusMetric; + import org.osmf.net.metrics.TestDefaultMetricFactory; + import org.osmf.net.metrics.TestDroppedFPSMetric; + import org.osmf.net.metrics.TestEmptyBufferInterruptionMetric; + import org.osmf.net.metrics.TestFPSMetric; + import org.osmf.net.metrics.TestFragmentCountMetric; + import org.osmf.net.metrics.TestMetricBase; + import org.osmf.net.metrics.TestMetricFactory; + import org.osmf.net.metrics.TestMetricFactoryItem; + import org.osmf.net.metrics.TestMetricRepository; + import org.osmf.net.metrics.TestMetricValue; + import org.osmf.net.metrics.TestRecentSwitchMetric; + import org.osmf.net.qos.TestQoSInfoHistory; + import org.osmf.net.rules.TestAfterUpSwitchBufferBandwidthRule; + import org.osmf.net.rules.TestBandwidthRule; + import org.osmf.net.rules.TestBufferBandwidthRule; + import org.osmf.net.rules.TestDroppedFPSRule; + import org.osmf.net.rules.TestEmptyBufferRule; + import org.osmf.net.rules.TestRecommendation; + import org.osmf.net.rules.TestRuleUtils; + import org.osmf.traits.TestAudioTrait; + import org.osmf.traits.TestBufferTrait; + import org.osmf.traits.TestBufferTraitAsSubclass; + import org.osmf.traits.TestDRMTrait; + import org.osmf.traits.TestDVRTrait; + import org.osmf.traits.TestDisplayObjectTrait; + import org.osmf.traits.TestDisplayObjectTraitAsSubclass; + import org.osmf.traits.TestDynamicStreamTrait; + import org.osmf.traits.TestLoadTrait; + import org.osmf.traits.TestLoadTraitAsSubclass; + import org.osmf.traits.TestLoaderBase; + import org.osmf.traits.TestPlayTrait; + import org.osmf.traits.TestPlayTraitAsSubclass; + import org.osmf.traits.TestSeekTrait; + import org.osmf.traits.TestTimeTrait; + import org.osmf.traits.TestTimeTraitAsSubclass; + import org.osmf.traits.TestTraitEventDispatcher; + import org.osmf.utils.OSMFUtilTestSettings; + import org.osmf.utils.OSMFUtilTestStrings; + import org.osmf.utils.OSMFUtilTestTime; + import org.osmf.utils.OSMFUtilTestURL; + import org.osmf.utils.TestURL; + + public class OSMFTests + { + public static function currentRunTestSuite():Array + { + var testsToRun:Array = new Array(); + + testsToRun.push(org.osmf.containers.TestHTMLMediaContainer); + testsToRun.push(org.osmf.containers.TestMediaContainer); + testsToRun.push(org.osmf.events.TestMediaError); + testsToRun.push(org.osmf.events.TestMediaErrorAsSubclass); + testsToRun.push(org.osmf.layout.TestAbsoluteLayoutMetadata); + testsToRun.push(org.osmf.layout.TestAnchorLayoutMetadata); + testsToRun.push(org.osmf.layout.TestBinarySearch); + testsToRun.push(org.osmf.layout.TestBoxAttributesMetadata); + testsToRun.push(org.osmf.layout.TestGenericLayout); + testsToRun.push(org.osmf.layout.TestLayoutAttributesMetadata); + testsToRun.push(org.osmf.layout.TestLayoutMetadata); + testsToRun.push(org.osmf.layout.TestLayoutRenderer); + testsToRun.push(org.osmf.layout.TestLayoutRendererBase); + testsToRun.push(org.osmf.layout.TestLayoutTargetEvent); + testsToRun.push(org.osmf.layout.TestLayoutTargetRenderers); + testsToRun.push(org.osmf.layout.TestMediaElementLayoutTarget); + testsToRun.push(org.osmf.layout.TestLayoutTargetSprite); + testsToRun.push(org.osmf.layout.TestOverlayLayoutMetadata); + testsToRun.push(org.osmf.layout.TestPaddingLayoutMetadata); + testsToRun.push(org.osmf.layout.TestRelativeLayoutMetadata); + testsToRun.push(org.osmf.layout.TestScaleModeUtils); + testsToRun.push(org.osmf.logging.TestLog); + testsToRun.push(org.osmf.media.MediaTraitResolverBaseTestCase); + testsToRun.push(org.osmf.media.TestDefaultMediaFactory); + testsToRun.push(org.osmf.media.TestDefaultTraitResolver); + testsToRun.push(org.osmf.media.TestLoadableElementBase); + testsToRun.push(org.osmf.media.TestMediaElement); + testsToRun.push(org.osmf.media.TestMediaElementAsSubclass); + testsToRun.push(org.osmf.media.TestMediaFactory); + testsToRun.push(org.osmf.media.TestMediaFactoryItem); + testsToRun.push(org.osmf.media.TestMediaPlayer); + testsToRun.push(org.osmf.media.TestMediaPlayerSprite); + testsToRun.push(org.osmf.media.TestMediaPlayerWithAudioElement); + testsToRun.push(org.osmf.media.TestMediaPlayerWithAudioElementWithSoundLoader); + testsToRun.push(org.osmf.media.TestMediaPlayerWithBeaconElement); + testsToRun.push(org.osmf.media.TestMediaPlayerWithDurationElement); + testsToRun.push(org.osmf.media.TestMediaPlayerWithDynamicStreamingVideoElement); + testsToRun.push(org.osmf.media.TestMediaPlayerWithDynamicStreamingVideoElementSubclip); + testsToRun.push(org.osmf.media.TestMediaPlayerWithLightweightVideoElement); + testsToRun.push(org.osmf.media.TestMediaPlayerWithProxyElement); + testsToRun.push(org.osmf.media.TestMediaPlayerWithSerialElementWithDurationElements); + testsToRun.push(org.osmf.media.TestMediaPlayerWithVideoElement); + testsToRun.push(org.osmf.media.TestMediaPlayerWithVideoElementSubclip); + testsToRun.push(org.osmf.media.TestMediaTraitResolver); + testsToRun.push(org.osmf.media.TestMediaType); + testsToRun.push(org.osmf.media.TestMediaTypeUtil); + testsToRun.push(org.osmf.media.TestPluginInfo); + testsToRun.push(org.osmf.media.TestURLResource); + testsToRun.push(org.osmf.media.pluginClasses.TestDynamicPluginLoader); + testsToRun.push(org.osmf.media.pluginClasses.TestPluginElement); + testsToRun.push(org.osmf.media.pluginClasses.TestPluginLoadingState); + testsToRun.push(org.osmf.media.pluginClasses.TestPluginManager); + testsToRun.push(org.osmf.media.pluginClasses.TestStaticPluginLoader); + testsToRun.push(org.osmf.metadata.TestCuePoint); + testsToRun.push(org.osmf.metadata.TestMetadata); + testsToRun.push(org.osmf.metadata.TestMetadataWatcher); + testsToRun.push(org.osmf.metadata.TestTimelineMarker); + testsToRun.push(org.osmf.metadata.TestTimelineMetadata); + testsToRun.push(org.osmf.net.drm.TestDRMServices); + testsToRun.push(org.osmf.net.TestDynamicStreamingItem); + testsToRun.push(org.osmf.net.TestDynamicStreamingResource); + testsToRun.push(org.osmf.net.TestSwitchManager); + testsToRun.push(org.osmf.net.metrics.TestActualBitrateMetric); + testsToRun.push(org.osmf.net.metrics.TestAvailableQualityLevelsMetric); + testsToRun.push(org.osmf.net.metrics.TestBandwidthMetric); + testsToRun.push(org.osmf.net.metrics.TestBufferFragmentsMetric); + testsToRun.push(org.osmf.net.metrics.TestBufferLengthMetric); + testsToRun.push(org.osmf.net.metrics.TestBufferOccupationRatioMetric); + testsToRun.push(org.osmf.net.metrics.TestCurrentStatusMetric); + testsToRun.push(org.osmf.net.metrics.TestDefaultMetricFactory); + testsToRun.push(org.osmf.net.metrics.TestDroppedFPSMetric); + testsToRun.push(org.osmf.net.metrics.TestEmptyBufferInterruptionMetric); + testsToRun.push(org.osmf.net.metrics.TestFPSMetric); + testsToRun.push(org.osmf.net.metrics.TestFragmentCountMetric); + testsToRun.push(org.osmf.net.metrics.TestMetricBase); + testsToRun.push(org.osmf.net.metrics.TestMetricFactory); + testsToRun.push(org.osmf.net.metrics.TestMetricFactoryItem); + testsToRun.push(org.osmf.net.metrics.TestMetricRepository); + testsToRun.push(org.osmf.net.metrics.TestMetricValue); + testsToRun.push(org.osmf.net.metrics.TestRecentSwitchMetric); + testsToRun.push(org.osmf.net.qos.TestQoSInfoHistory); + testsToRun.push(org.osmf.net.rules.TestAfterUpSwitchBufferBandwidthRule); + testsToRun.push(org.osmf.net.rules.TestBandwidthRule); + testsToRun.push(org.osmf.net.rules.TestBufferBandwidthRule); + testsToRun.push(org.osmf.net.rules.TestDroppedFPSRule); + testsToRun.push(org.osmf.net.rules.TestEmptyBufferRule); + testsToRun.push(org.osmf.net.rules.TestRecommendation); + testsToRun.push(org.osmf.net.rules.TestRuleUtils); + testsToRun.push(org.osmf.traits.TestAudioTrait); + testsToRun.push(org.osmf.traits.TestBufferTrait); + testsToRun.push(org.osmf.traits.TestBufferTraitAsSubclass); + testsToRun.push(org.osmf.traits.TestDisplayObjectTrait); + testsToRun.push(org.osmf.traits.TestDisplayObjectTraitAsSubclass); + testsToRun.push(org.osmf.traits.TestDRMTrait); + testsToRun.push(org.osmf.traits.TestDVRTrait); + testsToRun.push(org.osmf.traits.TestDynamicStreamTrait); + testsToRun.push(org.osmf.traits.TestLoaderBase); + testsToRun.push(org.osmf.traits.TestLoadTrait); + testsToRun.push(org.osmf.traits.TestLoadTraitAsSubclass); + testsToRun.push(org.osmf.traits.TestPlayTrait); + testsToRun.push(org.osmf.traits.TestPlayTraitAsSubclass); + testsToRun.push(org.osmf.traits.TestSeekTrait); + testsToRun.push(org.osmf.traits.TestTimeTrait); + testsToRun.push(org.osmf.traits.TestTimeTraitAsSubclass); + testsToRun.push(org.osmf.traits.TestTraitEventDispatcher); + testsToRun.push(org.osmf.utils.OSMFUtilTestSettings); + testsToRun.push(org.osmf.utils.OSMFUtilTestStrings); + testsToRun.push(org.osmf.utils.OSMFUtilTestTime); + testsToRun.push(org.osmf.utils.OSMFUtilTestURL); + testsToRun.push(org.osmf.utils.TestURL); + + return testsToRun; + } + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/containers/TestHTMLMediaContainer.as b/lib/osmf/framework/OSMFTest/src/org/osmf/containers/TestHTMLMediaContainer.as index eb5ac84..1f77aaa 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/containers/TestHTMLMediaContainer.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/containers/TestHTMLMediaContainer.as @@ -1,111 +1,97 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.containers -{ - import flash.external.ExternalInterface; - - import org.flexunit.Assert; - import org.osmf.elements.HTMLElement; - import org.osmf.elements.ProxyElement; - import org.osmf.media.MediaElement; - - public class TestHTMLMediaContainer - { - [Test(expects="flash.errors.IllegalOperationError")] - public function testAddMediaElementNull():void - { - var container:HTMLMediaContainer = new HTMLMediaContainer("test"); - container.addMediaElement(null); - } - - [Test(expects="flash.errors.IllegalOperationError")] - public function testAddMediaElementEmptyMediaElement():void - { - var container:HTMLMediaContainer = new HTMLMediaContainer("test"); - container.addMediaElement(new MediaElement()); - } - - [Ignore("This test needs further review: it seems to fail on IE for no apparent reason")] - [Test] - public function testExternalFunctions():void - { - if (ExternalInterface.available) - { - var container:HTMLMediaContainer = new HTMLMediaContainer("test"); - - Assert.assertTrue(ExternalInterface.call("function(){return document.osmf;}")); - Assert.assertTrue(ExternalInterface.call("function(){return document.osmf.containers;}")); - Assert.assertTrue(ExternalInterface.call("function(){return document.osmf.containers.MediaFrameworkTest_test;}")); - } - } - - [Test] - public function testHTMLMediaContainer():void - { - if (ExternalInterface.available) - { - var container:HTMLMediaContainer = new HTMLMediaContainer("test"); - - var element:HTMLElement = new HTMLElement(); - container.addMediaElement(element); - - Assert.assertTrue(container.containsMediaElement(element)); - Assert.assertFalse(container.containsMediaElement(null)); - Assert.assertFalse(container.containsMediaElement(new MediaElement())); - - try - { - container.removeMediaElement(null); - - Assert.fail(); - } - catch(e:Error) - { - } - - try - { - container.removeMediaElement(new MediaElement()); - - Assert.fail(); - } - catch(e:Error) - { - } - - container.removeMediaElement(element); - Assert.assertFalse(container.containsMediaElement(element)); - - container.addMediaElement(element); - Assert.assertTrue(container.containsMediaElement(element)); - - var element2:HTMLElement = new HTMLElement(); - container.addMediaElement(new ProxyElement(new ProxyElement(element2))); - - Assert.assertTrue(container.containsMediaElement(element2)); - - // Test if the container constructs its own id if we omit it: - var container2:HTMLMediaContainer = new HTMLMediaContainer(); - } - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.containers +{ + import flash.external.ExternalInterface; + + import org.flexunit.Assert; + import org.osmf.elements.HTMLElement; + import org.osmf.elements.ProxyElement; + import org.osmf.media.MediaElement; + + public class TestHTMLMediaContainer + { + [Test(expects="flash.errors.IllegalOperationError")] + public function testAddMediaElementNull():void + { + var container:HTMLMediaContainer = new HTMLMediaContainer("test"); + container.addMediaElement(null); + } + + [Test(expects="flash.errors.IllegalOperationError")] + public function testAddMediaElementEmptyMediaElement():void + { + var container:HTMLMediaContainer = new HTMLMediaContainer("test"); + container.addMediaElement(new MediaElement()); + } + + [Test] + public function testHTMLMediaContainer():void + { + if (ExternalInterface.available) + { + var container:HTMLMediaContainer = new HTMLMediaContainer("test"); + + var element:HTMLElement = new HTMLElement(); + container.addMediaElement(element); + + Assert.assertTrue(container.containsMediaElement(element)); + Assert.assertFalse(container.containsMediaElement(null)); + Assert.assertFalse(container.containsMediaElement(new MediaElement())); + + try + { + container.removeMediaElement(null); + + Assert.fail(); + } + catch(e:Error) + { + } + + try + { + container.removeMediaElement(new MediaElement()); + + Assert.fail(); + } + catch(e:Error) + { + } + + container.removeMediaElement(element); + Assert.assertFalse(container.containsMediaElement(element)); + + container.addMediaElement(element); + Assert.assertTrue(container.containsMediaElement(element)); + + var element2:HTMLElement = new HTMLElement(); + container.addMediaElement(new ProxyElement(new ProxyElement(element2))); + + Assert.assertTrue(container.containsMediaElement(element2)); + + // Test if the container constructs its own id if we omit it: + var container2:HTMLMediaContainer = new HTMLMediaContainer(); + } + } + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/containers/TestMediaContainer.as b/lib/osmf/framework/OSMFTest/src/org/osmf/containers/TestMediaContainer.as index c77efc3..e8c41cd 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/containers/TestMediaContainer.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/containers/TestMediaContainer.as @@ -1,227 +1,227 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.containers -{ - import flash.display.Sprite; - import flash.errors.IllegalOperationError; - - import org.flexunit.Assert; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutRenderer; - import org.osmf.layout.LayoutRendererBase; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.TesterSprite; - import org.osmf.layout.VerticalAlign; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.utils.DynamicMediaElement; - - public class TestMediaContainer - { - public function constructContainer(renderer:LayoutRendererBase=null):MediaContainer - { - return new MediaContainer(renderer); - } - - [Test(expects="flash.errors.IllegalOperationError")] - public function testAddChildNull():void - { - var container:MediaContainer = constructContainer(); - container.addChild(null); - } - - [Test(expects="flash.errors.IllegalOperationError")] - public function testAddChildAtNull():void - { - var container:MediaContainer = constructContainer(); - container.addChildAt(null, 0); - } - - [Test(expects="flash.errors.IllegalOperationError")] - public function testRemoveChildNull():void - { - var container:MediaContainer = constructContainer(); - container.removeChild(null); - } - - [Test(expects="RangeError")] - public function testRemoveChildAtNull():void - { - var container:MediaContainer = constructContainer(); - container.removeChildAt(0); - } - - [Test(expects="flash.errors.IllegalOperationError")] - public function testSetChildIndexNull():void - { - var container:MediaContainer = constructContainer(); - container.setChildIndex(null,0); - } - - [Test] - public function testContainerMediaElements():void - { - var renderer:LayoutRenderer = new LayoutRenderer(); - var parent:MediaContainer = constructContainer(renderer); - parent.backgroundColor = 0xff0000; - parent.backgroundAlpha = 1; - parent.clipChildren = true; - - myAssertThrows(parent.addMediaElement,null); - - var element1:DynamicMediaElement = new DynamicMediaElement(); - var element2:DynamicMediaElement = new DynamicMediaElement(); - - Assert.assertNotNull(parent); - Assert.assertFalse(parent.containsMediaElement(element1)); - Assert.assertFalse(parent.containsMediaElement(element2)); - - parent.addMediaElement(element1); - Assert.assertTrue(parent.containsMediaElement(element1)); - - myAssertThrows(parent.addMediaElement,element1); - - parent.addMediaElement(element2); - Assert.assertTrue(parent.containsMediaElement(element2)); - - Assert.assertTrue(element1 == parent.removeMediaElement(element1)); - Assert.assertFalse(parent.containsMediaElement(element1)); - - var c2:MediaContainer = constructContainer(); - c2.addMediaElement(element2); - - Assert.assertFalse(parent.containsMediaElement(element2)); - - var error:Error; - try - { - parent.removeMediaElement(element1); - } - catch(e:Error) - { - error = e; - } - - Assert.assertNotNull(error); - Assert.assertTrue(error is IllegalOperationError); - - myAssertThrows(parent.removeMediaElement, null); - } - - - [Test] - public function testContainerScaleAndAlign():void - { - // Child - - var mediaElement:DynamicMediaElement = new DynamicMediaElement(); - - var viewSprite:Sprite = new TesterSprite(); - var viewTrait:DisplayObjectTrait = new DisplayObjectTrait(viewSprite, 486, 60); - mediaElement.doAddTrait(MediaTraitType.DISPLAY_OBJECT, viewTrait); - var layout:LayoutMetadata = new LayoutMetadata(); - mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - layout.scaleMode = ScaleMode.NONE; - layout.verticalAlign = VerticalAlign.MIDDLE; - layout.horizontalAlign = HorizontalAlign.CENTER; - - var container:MediaContainer = constructContainer(); - container.width = 800; - container.height = 80; - - container.addMediaElement(mediaElement); - - container.validateNow(); - - Assert.assertEquals(486, viewSprite.width); - Assert.assertEquals(60, viewSprite.height); - - Assert.assertEquals(800/2 - 486/2, viewSprite.x); - Assert.assertEquals(80/2 - 60/2, viewSprite.y); - } - - [Test] - public function testContainerAttributes():void - { - var container:MediaContainer = constructContainer(); - container.width = 500; - container.height = 400; - - Assert.assertTrue(isNaN(container.backgroundColor)); - Assert.assertTrue(isNaN(container.backgroundAlpha)); - - container.backgroundColor = 0xFF00FF; - Assert.assertEquals(0xFF00FF, container.backgroundColor); - - container.backgroundColor = 0xFF00FF; - Assert.assertEquals(0xFF00FF, container.backgroundColor); - - container.backgroundAlpha = 0.5; - Assert.assertEquals(0.5, container.backgroundAlpha); - - container.backgroundAlpha = 0.5; - Assert.assertEquals(0.5, container.backgroundAlpha); - - Assert.assertFalse(container.clipChildren); - container.clipChildren = true; - Assert.assertTrue(container.clipChildren); - - container.clipChildren = true; - Assert.assertTrue(container.clipChildren); - - container.clipChildren = false; - Assert.assertFalse(container.clipChildren); - - container.validateNow(); - Assert.assertEquals(500, container.width); - Assert.assertEquals(400, container.height); - } - - [Test] - public function testConstructor():void - { - var renderer:LayoutRenderer = new LayoutRenderer(); - var container:MediaContainer = constructContainer(renderer); - Assert.assertEquals(renderer, container.layoutRenderer); - - var container2:MediaContainer = new MediaContainer(); - Assert.assertNotNull(container2.layoutRenderer); - } - - private function myAssertThrows(f:Function, ...arguments):* - { - var result:*; - - try - { - result = f.apply(null,arguments); - Assert.fail(); - } - catch(e:Error) - { - } - - return result; - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.containers +{ + import flash.display.Sprite; + import flash.errors.IllegalOperationError; + + import org.flexunit.Assert; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutRenderer; + import org.osmf.layout.LayoutRendererBase; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.TesterSprite; + import org.osmf.layout.VerticalAlign; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.utils.DynamicMediaElement; + + public class TestMediaContainer + { + public function constructContainer(renderer:LayoutRendererBase=null):MediaContainer + { + return new MediaContainer(renderer); + } + + [Test(expects="flash.errors.IllegalOperationError")] + public function testAddChildNull():void + { + var container:MediaContainer = constructContainer(); + container.addChild(null); + } + + [Test(expects="flash.errors.IllegalOperationError")] + public function testAddChildAtNull():void + { + var container:MediaContainer = constructContainer(); + container.addChildAt(null, 0); + } + + [Test(expects="flash.errors.IllegalOperationError")] + public function testRemoveChildNull():void + { + var container:MediaContainer = constructContainer(); + container.removeChild(null); + } + + [Test(expects="RangeError")] + public function testRemoveChildAtNull():void + { + var container:MediaContainer = constructContainer(); + container.removeChildAt(0); + } + + [Test(expects="flash.errors.IllegalOperationError")] + public function testSetChildIndexNull():void + { + var container:MediaContainer = constructContainer(); + container.setChildIndex(null,0); + } + + [Test] + public function testContainerMediaElements():void + { + var renderer:LayoutRenderer = new LayoutRenderer(); + var parent:MediaContainer = constructContainer(renderer); + parent.backgroundColor = 0xff0000; + parent.backgroundAlpha = 1; + parent.clipChildren = true; + + myAssertThrows(parent.addMediaElement,null); + + var element1:DynamicMediaElement = new DynamicMediaElement(); + var element2:DynamicMediaElement = new DynamicMediaElement(); + + Assert.assertNotNull(parent); + Assert.assertFalse(parent.containsMediaElement(element1)); + Assert.assertFalse(parent.containsMediaElement(element2)); + + parent.addMediaElement(element1); + Assert.assertTrue(parent.containsMediaElement(element1)); + + myAssertThrows(parent.addMediaElement,element1); + + parent.addMediaElement(element2); + Assert.assertTrue(parent.containsMediaElement(element2)); + + Assert.assertTrue(element1 == parent.removeMediaElement(element1)); + Assert.assertFalse(parent.containsMediaElement(element1)); + + var c2:MediaContainer = constructContainer(); + c2.addMediaElement(element2); + + Assert.assertFalse(parent.containsMediaElement(element2)); + + var error:Error; + try + { + parent.removeMediaElement(element1); + } + catch(e:Error) + { + error = e; + } + + Assert.assertNotNull(error); + Assert.assertTrue(error is IllegalOperationError); + + myAssertThrows(parent.removeMediaElement, null); + } + + + [Test] + public function testContainerScaleAndAlign():void + { + // Child + + var mediaElement:DynamicMediaElement = new DynamicMediaElement(); + + var viewSprite:Sprite = new TesterSprite(); + var viewTrait:DisplayObjectTrait = new DisplayObjectTrait(viewSprite, 486, 60); + mediaElement.doAddTrait(MediaTraitType.DISPLAY_OBJECT, viewTrait); + var layout:LayoutMetadata = new LayoutMetadata(); + mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + layout.scaleMode = ScaleMode.NONE; + layout.verticalAlign = VerticalAlign.MIDDLE; + layout.horizontalAlign = HorizontalAlign.CENTER; + + var container:MediaContainer = constructContainer(); + container.width = 800; + container.height = 80; + + container.addMediaElement(mediaElement); + + container.validateNow(); + + Assert.assertEquals(486, viewSprite.width); + Assert.assertEquals(60, viewSprite.height); + + Assert.assertEquals(800/2 - 486/2, viewSprite.x); + Assert.assertEquals(80/2 - 60/2, viewSprite.y); + } + + [Test] + public function testContainerAttributes():void + { + var container:MediaContainer = constructContainer(); + container.width = 500; + container.height = 400; + + Assert.assertTrue(isNaN(container.backgroundColor)); + Assert.assertTrue(isNaN(container.backgroundAlpha)); + + container.backgroundColor = 0xFF00FF; + Assert.assertEquals(0xFF00FF, container.backgroundColor); + + container.backgroundColor = 0xFF00FF; + Assert.assertEquals(0xFF00FF, container.backgroundColor); + + container.backgroundAlpha = 0.5; + Assert.assertEquals(0.5, container.backgroundAlpha); + + container.backgroundAlpha = 0.5; + Assert.assertEquals(0.5, container.backgroundAlpha); + + Assert.assertFalse(container.clipChildren); + container.clipChildren = true; + Assert.assertTrue(container.clipChildren); + + container.clipChildren = true; + Assert.assertTrue(container.clipChildren); + + container.clipChildren = false; + Assert.assertFalse(container.clipChildren); + + container.validateNow(); + Assert.assertEquals(500, container.width); + Assert.assertEquals(400, container.height); + } + + [Test] + public function testConstructor():void + { + var renderer:LayoutRenderer = new LayoutRenderer(); + var container:MediaContainer = constructContainer(renderer); + Assert.assertEquals(renderer, container.layoutRenderer); + + var container2:MediaContainer = new MediaContainer(); + Assert.assertNotNull(container2.layoutRenderer); + } + + private function myAssertThrows(f:Function, ...arguments):* + { + var result:*; + + try + { + result = f.apply(null,arguments); + Assert.fail(); + } + catch(e:Error) + { + } + + return result; + } + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/TestExternalMediaParser.as b/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/TestExternalMediaParser.as new file mode 100644 index 0000000..505c019 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/TestExternalMediaParser.as @@ -0,0 +1,77 @@ +package org.osmf.elements.f4mClasses +{ + import org.flexunit.Assert; + import org.flexunit.async.Async; + import org.osmf.elements.f4mClasses.ExternalMediaParser; + import org.osmf.events.ParseEvent; + + public class TestExternalMediaParser + { + + [Before] + public function setUp():void + { + parser = new ExternalMediaParser(); + } + + [After] + public function tearDown():void + { + parser = null; + } + + [Test(async, description="Tests a media node from a 2.0 F4M.")] + public function testParseExternalMedia():void + { + var test:XML = ; + var asyncHandler:Function = Async.asyncHandler(this, handleExternalParseComplete, TIMEOUT, null, handleTimeout); + parser.addEventListener(ParseEvent.PARSE_COMPLETE, asyncHandler, false, 0, true); + parser.parse(test.toXMLString()); + } + + private function handleExternalParseComplete(event:ParseEvent, passThroughData:Object):void + { + Assert.assertNull(event.data); + } + + [Test(async, description="Tests a media node from a 1.0 F4M.")] + public function testParseInlineMedia():void + { + var test:XML = + + AgAKb25NZXRhRGF0YQgAAAAAAAhkdXJhdGlvbgBAYwYy29GUIwAFd2lkdGgAQIgAAAAAAAAABmhlaWdodABAewAAAAAAAAAMdmlkZW9jb2RlY2lkAgAEYXZjMQAMYXVkaW9jb2RlY2lkAgAEbXA0YQAKYXZjcHJvZmlsZQBAUIAAAAAAAAAIYXZjbGV2ZWwAQD4AAAAAAAAABmFhY2FvdAAAAAAAAAAAAAAOdmlkZW9mcmFtZXJhdGUAQDf53LURIocAD2F1ZGlvc2FtcGxlcmF0ZQBA1YiAAAAAAAANYXVkaW9jaGFubmVscwBAAAAAAAAAAAAJdHJhY2tpbmZvCgAAAAIDAAZsZW5ndGgAQUveFIAAAAAACXRpbWVzY2FsZQBA13AAAAAAAAAIbGFuZ3VhZ2UCAANgYGAAAAkDAAZsZW5ndGgAQUmab4AAAAAACXRpbWVzY2FsZQBA1YiAAAAAAAAIbGFuZ3VhZ2UCAANgYGAAAAkAB2N1c3RkZWYKAAAAAAAACQ== + + ; + var asyncHandler:Function = Async.asyncHandler(this, handleInlineParseComplete, TIMEOUT, null, handleTimeout); + parser.addEventListener(ParseEvent.PARSE_COMPLETE, asyncHandler, false, 0, true); + parser.parse(test.toXMLString()); + } + + private function handleInlineParseComplete(event:ParseEvent, passThroughData:Object):void + { + var m:Media = event.data as Media; + + Assert.assertNotNull(m); + Assert.assertEquals(m.url, 'http://samples.osmf.org/jit/sample1_150kbps'); + Assert.assertEquals(m.bitrate, 1030); + Assert.assertEquals(m.bootstrapInfo.id, 'bootstrap971'); + } + + private function handleTimeout(passThroughData:Object):void + { + Assert.fail("Timeout reached before event."); + } + + private static const TIMEOUT:Number = 1000; + + private var parser:ExternalMediaParser; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/builders/TestManifestBuilder.as b/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/builders/TestManifestBuilder.as new file mode 100644 index 0000000..91f3527 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/builders/TestManifestBuilder.as @@ -0,0 +1,52 @@ +package org.osmf.elements.f4mClasses.builders +{ + import org.flexunit.Assert; + import org.hamcrest.assertThat; + import org.hamcrest.core.isA; + import org.osmf.elements.f4mClasses.builders.ManifestBuilder; + import org.osmf.elements.f4mClasses.ManifestParser; + + public class TestManifestBuilder + { + private var builder:ManifestBuilder; + + [Before] + public function setUp():void + { + builder = new ManifestBuilder(); + } + + [After] + public function tearDown():void + { + builder = null; + } + + [Test] + public function testCanParseTrue():void + { + var test:String = ""; + var result:Boolean = builder.canParse(test); + + Assert.assertTrue(result); + } + + [Test] + public function testCanParseFalse():void + { + var test:String = ""; + var result:Boolean = builder.canParse(test); + + Assert.assertFalse(result); + } + + [Test] + public function testBuild():void + { + var test:String = ""; + var parser:ManifestParser = builder.build(test); + + assertThat(parser, isA(ManifestParser)); + } + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/builders/TestMultiLevelManifestBuilder.as b/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/builders/TestMultiLevelManifestBuilder.as new file mode 100644 index 0000000..0324cf1 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/elements/f4mClasses/builders/TestMultiLevelManifestBuilder.as @@ -0,0 +1,53 @@ +package org.osmf.elements.f4mClasses.builders +{ + import org.flexunit.Assert; + import org.hamcrest.assertThat; + import org.hamcrest.core.isA; + import org.osmf.elements.f4mClasses.builders.MultiLevelManifestBuilder; + import org.osmf.elements.f4mClasses.ManifestParser; + import org.osmf.elements.f4mClasses.MultiLevelManifestParser; + + public class TestMultiLevelManifestBuilder + { + private var builder:MultiLevelManifestBuilder; + + [Before] + public function setUp():void + { + builder = new MultiLevelManifestBuilder(); + } + + [After] + public function tearDown():void + { + builder = null; + } + + [Test] + public function testCanParseTrue():void + { + var test:String = ""; + var result:Boolean = builder.canParse(test); + + Assert.assertTrue(result); + } + + [Test] + public function testCanParseFalse():void + { + var test:String = ""; + var result:Boolean = builder.canParse(test); + + Assert.assertFalse(result); + } + + [Test] + public function testBuild():void + { + var test:String = ""; + var parser:ManifestParser = builder.build(test); + + assertThat(parser, isA(MultiLevelManifestParser)); + } + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/layout/TestLayoutTargetSprite.as b/lib/osmf/framework/OSMFTest/src/org/osmf/layout/TestLayoutTargetSprite.as new file mode 100644 index 0000000..0ceba70 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/layout/TestLayoutTargetSprite.as @@ -0,0 +1,183 @@ +package org.osmf.layout +{ + import flexunit.framework.Assert; + + public class TestLayoutTargetSprite + { + private var layoutTargetSprite:LayoutTargetSprite; + + [Before] + public function setUp():void + { + this.layoutTargetSprite = new LayoutTargetSprite() + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testXSetterSingleChild():void + { + var triggered:Boolean = false; + + function genericTriggeredCallback():void + { + triggered = true; + } + + var genericDO:GenericDisplayObject = new GenericDisplayObject(genericTriggeredCallback); + this.layoutTargetSprite.addChild(genericDO); + + this.layoutTargetSprite.x = 10; + + Assert.assertTrue(triggered); + } + + [Test] + public function testYSetterSingleChild():void + { + var triggered:Boolean = false; + + function genericTriggeredCallback():void + { + triggered = true; + } + + var genericDO:GenericDisplayObject = new GenericDisplayObject(genericTriggeredCallback); + this.layoutTargetSprite.addChild(genericDO); + + this.layoutTargetSprite.y = 10; + + Assert.assertTrue(triggered); + } + + [Test] + public function testXSetterMultipleChildren():void + { + var triggered1:Boolean = false; + var triggered2:Boolean = false; + + function genericTriggeredCallback1():void + { + triggered1 = true; + } + + function genericTriggeredCallback2():void + { + triggered2 = true; + } + + var genericDO1:GenericDisplayObject = new GenericDisplayObject(genericTriggeredCallback1); + var genericDO2:GenericDisplayObject = new GenericDisplayObject(genericTriggeredCallback2); + this.layoutTargetSprite.addChild(genericDO1); + this.layoutTargetSprite.addChild(genericDO2); + + this.layoutTargetSprite.x = 10; + + Assert.assertTrue(triggered1); + Assert.assertTrue(triggered2); + } + + [Test] + public function testYSetterMultipleChildren():void + { + var triggered1:Boolean = false; + var triggered2:Boolean = false; + + function genericTriggeredCallback1():void + { + triggered1 = true; + } + + function genericTriggeredCallback2():void + { + triggered2 = true; + } + + var genericDO1:GenericDisplayObject = new GenericDisplayObject(genericTriggeredCallback1); + var genericDO2:GenericDisplayObject = new GenericDisplayObject(genericTriggeredCallback2); + this.layoutTargetSprite.addChild(genericDO1); + this.layoutTargetSprite.addChild(genericDO2); + + this.layoutTargetSprite.y = 10; + + Assert.assertTrue(triggered1); + Assert.assertTrue(triggered2); + } + + [Test] + public function testXSetterMultipleContainers():void + { + var triggered:Boolean = false; + + function genericTriggeredCallback():void + { + triggered = true; + } + + var genericDO:GenericDisplayObject = new GenericDisplayObject(genericTriggeredCallback); + var middleLayoutTargetSprite:LayoutTargetSprite = new LayoutTargetSprite(); + + middleLayoutTargetSprite.addChild(genericDO); + this.layoutTargetSprite.addChild(middleLayoutTargetSprite); + + this.layoutTargetSprite.x = 10; + + Assert.assertTrue(triggered); + } + + [Test] + public function testYSetterMultipleContainers():void + { + var triggered:Boolean = false; + + function genericTriggeredCallback():void + { + triggered = true; + } + + var genericDO:GenericDisplayObject = new GenericDisplayObject(genericTriggeredCallback); + var middleLayoutTargetSprite:LayoutTargetSprite = new LayoutTargetSprite(); + + middleLayoutTargetSprite.addChild(genericDO); + this.layoutTargetSprite.addChild(middleLayoutTargetSprite); + + this.layoutTargetSprite.y = 10; + + Assert.assertTrue(triggered); + } + } +} +import flash.display.Sprite; + +internal class GenericDisplayObject extends Sprite +{ + private var _callback:Function; + + public function GenericDisplayObject(callback:Function) + { + this._callback = callback; + } + + override public function set x(value:Number):void + { + this._callback(); + } + + override public function set y(value:Number):void + { + this._callback(); + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/logging/TestLog.as b/lib/osmf/framework/OSMFTest/src/org/osmf/logging/TestLog.as index 51b00a5..defa098 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/logging/TestLog.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/logging/TestLog.as @@ -48,47 +48,56 @@ package org.osmf.logging [Test] public function testAccessLoggerFactory():void { - var loggerFactory:TraceLoggerFactory = new TraceLoggerFactory(); - Log.loggerFactory = loggerFactory; - - Assert.assertTrue(loggerFactory == Log.loggerFactory); + CONFIG::LOGGING + { + var loggerFactory:TraceLoggerFactory = new TraceLoggerFactory(); + Log.loggerFactory = loggerFactory; + + Assert.assertTrue(loggerFactory == Log.loggerFactory); + } } [Test] public function testGetLogger():void { - var logger:Logger = Log.getLogger("testLogger"); - CONFIG::LOGGING { + var logger:Logger = Log.getLogger("testLogger"); + + CONFIG::LOGGING + { + Assert.assertTrue(logger != null); + logger = null; + } + + Assert.assertTrue(logger == null); + + Log.loggerFactory = new TraceLoggerFactory(); + + logger = Log.getLogger("testLogger"); Assert.assertTrue(logger != null); - logger = null; } - - Assert.assertTrue(logger == null); - - Log.loggerFactory = new TraceLoggerFactory(); - - logger = Log.getLogger("testLogger"); - Assert.assertTrue(logger != null); } [Test] public function testLevelEnablements():void { - var logger:Logger = new TraceLoggerFactory().getLogger("testLogger"); - - logger.debug("message"); - logger.error("message"); - logger.info("message"); - logger.warn("message"); - logger.fatal("message"); - - logger.debug("{0} message", "debug"); - logger.error("{0} message", "error"); - logger.info("{0} message", "info"); - logger.warn("{0} message", "warn"); - logger.fatal("{0} message", "fatal"); + CONFIG::LOGGING + { + var logger:Logger = new TraceLoggerFactory().getLogger("testLogger"); + + logger.debug("message"); + logger.error("message"); + logger.info("message"); + logger.warn("message"); + logger.fatal("message"); + + logger.debug("{0} message", "debug"); + logger.error("{0} message", "error"); + logger.info("{0} message", "info"); + logger.warn("{0} message", "warn"); + logger.fatal("{0} message", "fatal"); + } } } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/media/MediaTraitResolverBaseTestCase.as b/lib/osmf/framework/OSMFTest/src/org/osmf/media/MediaTraitResolverBaseTestCase.as index ccec2cc..2a98a3a 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/media/MediaTraitResolverBaseTestCase.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/media/MediaTraitResolverBaseTestCase.as @@ -1,101 +1,56 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.media -{ - import org.flexunit.Assert; - import org.osmf.traits.BufferTrait; - import org.osmf.traits.MediaTraitBase; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.TimeTrait; - import org.osmf.traits.DisplayObjectTrait; - - public class MediaTraitResolverBaseTestCase - { - public function constructResolver(type:String, traitOfType:MediaTraitBase):MediaTraitResolver - { - return null; - } - - [Ignore] - [Test(expects="ArgumentError")] - public function testConstructor():void - { - var resolver:MediaTraitResolver; - resolver = constructResolver(null, null); - Assert.assertNull(resolver); - } - - [Ignore] - [Test] - public function testType():void - { - var resolver:MediaTraitResolver; - resolver = constructResolver(MediaTraitType.BUFFER, new BufferTrait()); - Assert.assertNotNull(resolver); - Assert.assertEquals(MediaTraitType.BUFFER, resolver.type); - } - - [Test(expects="Error")] - public function testAddTraitNull():void - { - var type:String = MediaTraitType.TIME; - var resolver:MediaTraitResolver = constructResolver(type, new TimeTrait()); - - resolver.addTrait(null); - } - - [Test(expects="Error")] - public function testAddTrait():void - { - var type:String = MediaTraitType.TIME; - var resolver:MediaTraitResolver = constructResolver(type, new TimeTrait()); - - resolver.addTrait(new DisplayObjectTrait(null)); - } - - [Ignore] - [Test(expects="Error")] - public function testRemoveTraitNull():void - { - var type:String = MediaTraitType.TIME; - var resolver:MediaTraitResolver = constructResolver(type, new TimeTrait()); - - resolver.removeTrait(null); - - } - - [Ignore] - [Test(expects="Error")] - public function testRemoveNonAddedTrait():void - { - var type:String = MediaTraitType.TIME; - var resolver:MediaTraitResolver = constructResolver(type, new TimeTrait()); - var tt:TimeTrait = new TimeTrait(); - - resolver.removeTrait(tt); - - //How to test this ... - //resolver.addTrait(tt); - //resolver.removeTrait(tt); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.media +{ + import org.flexunit.Assert; + import org.osmf.traits.BufferTrait; + import org.osmf.traits.MediaTraitBase; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.TimeTrait; + import org.osmf.traits.DisplayObjectTrait; + + public class MediaTraitResolverBaseTestCase + { + public function constructResolver(type:String, traitOfType:MediaTraitBase):MediaTraitResolver + { + return null; + } + + [Test(expects="Error")] + public function testAddTraitNull():void + { + var type:String = MediaTraitType.TIME; + var resolver:MediaTraitResolver = constructResolver(type, new TimeTrait()); + + resolver.addTrait(null); + } + + [Test(expects="Error")] + public function testAddTrait():void + { + var type:String = MediaTraitType.TIME; + var resolver:MediaTraitResolver = constructResolver(type, new TimeTrait()); + + resolver.addTrait(new DisplayObjectTrait(null)); + } + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestDefaultTraitResolver.as b/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestDefaultTraitResolver.as index 6b5cbc5..26e721b 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestDefaultTraitResolver.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestDefaultTraitResolver.as @@ -1,66 +1,66 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.media -{ - import org.osmf.traits.MediaTraitBase; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.TimeTrait; - - import org.flexunit.Assert; - - public class TestDefaultTraitResolver extends MediaTraitResolverBaseTestCase - { - override public function constructResolver(type:String, traitOfType:MediaTraitBase):MediaTraitResolver - { - return new DefaultTraitResolver(type, traitOfType); - } - - [Test(expects="Error")] - public function testDefaultTraitResolver():void - { - new DefaultTraitResolver(MediaTraitType.AUDIO, new TimeTrait()); - } - - [Test(expects="Error")] - public function testDefaultTraitResolverNull():void - { - new DefaultTraitResolver(MediaTraitType.TIME, null); - } - - [Test] - public function testResolvedTrait():void - { - var t1:TimeTrait = new TimeTrait(); - var resolver:DefaultTraitResolver = new DefaultTraitResolver(MediaTraitType.TIME, t1); - - Assert.assertEquals(MediaTraitType.TIME, resolver.type); - Assert.assertEquals(t1, resolver.resolvedTrait); - - var t2:TimeTrait = new TimeTrait(); - resolver.addTrait(t2); - Assert.assertEquals(t2, resolver.resolvedTrait); - - resolver.removeTrait(t2); - Assert.assertEquals(t1, resolver.resolvedTrait); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.media +{ + import org.osmf.traits.MediaTraitBase; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.TimeTrait; + + import org.flexunit.Assert; + + public class TestDefaultTraitResolver extends MediaTraitResolverBaseTestCase + { + override public function constructResolver(type:String, traitOfType:MediaTraitBase):MediaTraitResolver + { + return new DefaultTraitResolver(type, traitOfType); + } + + [Test(expects="Error")] + public function testDefaultTraitResolver():void + { + new DefaultTraitResolver(MediaTraitType.AUDIO, new TimeTrait()); + } + + [Test(expects="Error")] + public function testDefaultTraitResolverNull():void + { + new DefaultTraitResolver(MediaTraitType.TIME, null); + } + + [Test] + public function testResolvedTrait():void + { + var t1:TimeTrait = new TimeTrait(); + var resolver:DefaultTraitResolver = new DefaultTraitResolver(MediaTraitType.TIME, t1); + + Assert.assertEquals(MediaTraitType.TIME, resolver.type); + Assert.assertEquals(t1, resolver.resolvedTrait); + + var t2:TimeTrait = new TimeTrait(); + resolver.addTrait(t2); + Assert.assertEquals(t2, resolver.resolvedTrait); + + resolver.removeTrait(t2); + Assert.assertEquals(t1, resolver.resolvedTrait); + } + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaElement.as b/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaElement.as index 4d93413..9865128 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaElement.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaElement.as @@ -53,41 +53,6 @@ package org.osmf.media { _eventDispatcher = null; } - - [Ignore] - [Test] - public function testGetTraitTypes():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyGetTraitTypes(mediaElement, existentTraitTypesOnInitialization); - } - - [Ignore] - [Test] - public function testHasTrait():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyHasTrait(mediaElement, existentTraitTypesOnInitialization); - } - - [Ignore] - [Test(expects="ArgumentError")] - public function testHasTraitWhenParamIsNull():void - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.hasTrait(null); - } - - [Ignore] - [Test] - public function testGetTrait():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyGetTrait(mediaElement, existentTraitTypesOnInitialization); - } [Test(expects="ArgumentError")] public function testGetTraitWhenParamIsNull():void diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaPlayerSprite.as b/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaPlayerSprite.as index 894418a..6571613 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaPlayerSprite.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaPlayerSprite.as @@ -1,132 +1,132 @@ -package org.osmf.media -{ - import flexunit.framework.Assert; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.AudioElement; - import org.osmf.elements.VideoElement; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - - public class TestMediaPlayerSprite - { - [Test] - public function testConstructor():void - { - var container:MediaContainer = new MediaContainer(); - var player:MediaPlayer = new MediaPlayer(); - var factory:MediaFactory = new MediaFactory(); - - var mps:MediaPlayerSprite = new MediaPlayerSprite(player, container, factory); - Assert.assertEquals(mps.mediaPlayer, player); - Assert.assertEquals(mps.mediaContainer, container); - Assert.assertEquals(mps.mediaFactory, factory); - - mps = new MediaPlayerSprite(); - Assert.assertNotNull(mps.mediaPlayer); - Assert.assertNotNull(mps.mediaContainer); - Assert.assertNotNull(mps.mediaFactory); - - player.media = new AudioElement(); - - mps = new MediaPlayerSprite(player); - Assert.assertTrue(mps.mediaContainer.containsMediaElement(player.media)); - Assert.assertEquals(mps.media, player.media); - } - - [Test] - public function testMedia():void - { - var mps:MediaPlayerSprite = new MediaPlayerSprite(); - - Assert.assertNull(mps.media); - Assert.assertNull(mps.mediaPlayer.media); - - mps.mediaPlayer.media = new AudioElement(); - - Assert.assertEquals(mps.media, mps.mediaPlayer.media); - Assert.assertTrue(mps.mediaContainer.containsMediaElement(mps.media)); - - mps.media = new VideoElement(); - - Assert.assertEquals(mps.media, mps.mediaPlayer.media); - Assert.assertTrue(mps.mediaContainer.containsMediaElement(mps.media)); - Assert.assertTrue(mps.media is VideoElement); - } - - [Test] - public function testResource():void - { - var mps:MediaPlayerSprite = new MediaPlayerSprite(); - - var resource:URLResource = new URLResource("http://example.com/video.flv"); - - mps.resource = resource; - - Assert.assertEquals(mps.resource, resource); - Assert.assertNotNull(mps.media); - Assert.assertEquals(mps.media, mps.mediaPlayer.media); - - } - - [Test] - public function testScaleMode():void - { - var mps:MediaPlayerSprite = new MediaPlayerSprite(); - - Assert.assertEquals(mps.scaleMode, ScaleMode.LETTERBOX); - - mps.media = new VideoElement(); - - Assert.assertEquals(mps.scaleMode, ScaleMode.LETTERBOX); - - var layout:LayoutMetadata = mps.media.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; - - Assert.assertEquals(layout.scaleMode, mps.scaleMode, ScaleMode.LETTERBOX); - - mps.scaleMode = ScaleMode.NONE; - - Assert.assertEquals(layout.scaleMode, mps.scaleMode, ScaleMode.NONE); - - - //Make sure layout is preserved if already set. - var element:MediaElement = new VideoElement(); - layout = new LayoutMetadata() - element.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - layout.percentWidth = 50; - layout.percentHeight = 50; - layout.percentX = 20; - layout.percentY = 20; - layout.scaleMode = ScaleMode.STRETCH; - - mps = new MediaPlayerSprite(); - - mps.media = element; - - Assert.assertEquals(mps.scaleMode, ScaleMode.LETTERBOX); - - Assert.assertEquals(mps.media.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE), layout); - - } - - [Test] - public function testLayout():void - { - var mps:MediaPlayerSprite = new MediaPlayerSprite(); - - mps.media = new VideoElement(); - - mps.width = 200; - mps.height = 200; - - Assert.assertEquals(mps.mediaContainer.width, mps.width); - Assert.assertEquals(mps.mediaContainer.height, mps.height); - - mps.width = 400; - mps.height = 400; - - Assert.assertEquals(mps.mediaContainer.width, mps.width); - Assert.assertEquals(mps.mediaContainer.height, mps.height); - } - } +package org.osmf.media +{ + import flexunit.framework.Assert; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.AudioElement; + import org.osmf.elements.VideoElement; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + + public class TestMediaPlayerSprite + { + [Test] + public function testConstructor():void + { + var container:MediaContainer = new MediaContainer(); + var player:MediaPlayer = new MediaPlayer(); + var factory:MediaFactory = new MediaFactory(); + + var mps:MediaPlayerSprite = new MediaPlayerSprite(player, container, factory); + Assert.assertEquals(mps.mediaPlayer, player); + Assert.assertEquals(mps.mediaContainer, container); + Assert.assertEquals(mps.mediaFactory, factory); + + mps = new MediaPlayerSprite(); + Assert.assertNotNull(mps.mediaPlayer); + Assert.assertNotNull(mps.mediaContainer); + Assert.assertNotNull(mps.mediaFactory); + + player.media = new AudioElement(); + + mps = new MediaPlayerSprite(player); + Assert.assertTrue(mps.mediaContainer.containsMediaElement(player.media)); + Assert.assertEquals(mps.media, player.media); + } + + [Test] + public function testMedia():void + { + var mps:MediaPlayerSprite = new MediaPlayerSprite(); + + Assert.assertNull(mps.media); + Assert.assertNull(mps.mediaPlayer.media); + + mps.mediaPlayer.media = new AudioElement(); + + Assert.assertEquals(mps.media, mps.mediaPlayer.media); + Assert.assertTrue(mps.mediaContainer.containsMediaElement(mps.media)); + + mps.media = new VideoElement(); + + Assert.assertEquals(mps.media, mps.mediaPlayer.media); + Assert.assertTrue(mps.mediaContainer.containsMediaElement(mps.media)); + Assert.assertTrue(mps.media is VideoElement); + } + + [Test] + public function testResource():void + { + var mps:MediaPlayerSprite = new MediaPlayerSprite(); + + var resource:URLResource = new URLResource("http://example.com/video.flv"); + + mps.resource = resource; + + Assert.assertEquals(mps.resource, resource); + Assert.assertNotNull(mps.media); + Assert.assertEquals(mps.media, mps.mediaPlayer.media); + + } + + [Test] + public function testScaleMode():void + { + var mps:MediaPlayerSprite = new MediaPlayerSprite(); + + Assert.assertEquals(mps.scaleMode, ScaleMode.LETTERBOX); + + mps.media = new VideoElement(); + + Assert.assertEquals(mps.scaleMode, ScaleMode.LETTERBOX); + + var layout:LayoutMetadata = mps.media.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; + + Assert.assertEquals(layout.scaleMode, mps.scaleMode, ScaleMode.LETTERBOX); + + mps.scaleMode = ScaleMode.NONE; + + Assert.assertEquals(layout.scaleMode, mps.scaleMode, ScaleMode.NONE); + + + //Make sure layout is preserved if already set. + var element:MediaElement = new VideoElement(); + layout = new LayoutMetadata() + element.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + layout.percentWidth = 50; + layout.percentHeight = 50; + layout.percentX = 20; + layout.percentY = 20; + layout.scaleMode = ScaleMode.STRETCH; + + mps = new MediaPlayerSprite(); + + mps.media = element; + + Assert.assertEquals(mps.scaleMode, ScaleMode.LETTERBOX); + + Assert.assertEquals(mps.media.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE), layout); + + } + + [Test] + public function testLayout():void + { + var mps:MediaPlayerSprite = new MediaPlayerSprite(); + + mps.media = new VideoElement(); + + mps.width = 200; + mps.height = 200; + + Assert.assertEquals(mps.mediaContainer.width, mps.width); + Assert.assertEquals(mps.mediaContainer.height, mps.height); + + mps.width = 400; + mps.height = 400; + + Assert.assertEquals(mps.mediaContainer.width, mps.width); + Assert.assertEquals(mps.mediaContainer.height, mps.height); + } + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaTraitResolver.as b/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaTraitResolver.as index 1f94b5a..f192be6 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaTraitResolver.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/media/TestMediaTraitResolver.as @@ -1,39 +1,39 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.media -{ - import org.osmf.traits.MediaTraitBase; - - public class TestMediaTraitResolver extends MediaTraitResolverBaseTestCase - { - override public function constructResolver(type:String, traitOfType:MediaTraitBase):MediaTraitResolver - { - return new MediaTraitResolver(type) as MediaTraitResolver; - } - - [Test] - public function test1():void - { - - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.media +{ + import org.osmf.traits.MediaTraitBase; + + public class TestMediaTraitResolver extends MediaTraitResolverBaseTestCase + { + override public function constructResolver(type:String, traitOfType:MediaTraitBase):MediaTraitResolver + { + return new MediaTraitResolver(type) as MediaTraitResolver; + } + + [Test] + public function test1():void + { + + } + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/media/pluginClasses/TestPluginManager.as b/lib/osmf/framework/OSMFTest/src/org/osmf/media/pluginClasses/TestPluginManager.as index 165ef9c..08adb1c 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/media/pluginClasses/TestPluginManager.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/media/pluginClasses/TestPluginManager.as @@ -171,12 +171,7 @@ package org.osmf.media.pluginClasses [Test] public function testLoadPluginWithDifferentVersions():void - { - // Note: This test will need updating any time the framework - // version number changes. I've added the following Assert.assertion - // to make this explicit. - Assert.assertTrue(Version.version == "1.6"); - + { // First number is minimum supported framework version. // Second number is plugin's framework version. @@ -185,17 +180,17 @@ package org.osmf.media.pluginClasses assertPluginHasValidVersion("0.9", "0.95", true); // But not newer plugins. - assertPluginHasValidVersion("0.9", "1.9", false); + assertPluginHasValidVersion("0.9", "99.9", false); // And we can't load older plugins if their version is less // than the minimum. assertPluginHasValidVersion("0.95", "0.9", false); assertPluginHasValidVersion("0.95", "0.95", true); - assertPluginHasValidVersion("0.95", "1.9", false); + assertPluginHasValidVersion("0.95", "99.9", false); assertPluginHasValidVersion("1.1", "0.9", false); assertPluginHasValidVersion("1.1", "0.95", false); - assertPluginHasValidVersion("1.1", "1.9", false); + assertPluginHasValidVersion("1.1", "99.9", false); // Verify we take the number of digits in the minor version // into account. diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/metadata/TestCuePoint.as b/lib/osmf/framework/OSMFTest/src/org/osmf/metadata/TestCuePoint.as index 0db98da..509868b 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/metadata/TestCuePoint.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/metadata/TestCuePoint.as @@ -1,47 +1,47 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.metadata -{ - import flexunit.framework.Assert; - - public class TestCuePoint - { - [Test] - public function testCuePoint():void - { - var params:Object = new Object(); - params["100"] = "a"; - params["101"] = "b"; - var cuePoint:CuePoint = new CuePoint(CuePointType.ACTIONSCRIPT, 120, "test cue point", params, 5); - - Assert.assertEquals(CuePointType.ACTIONSCRIPT, cuePoint.type); - Assert.assertEquals(120, cuePoint.time); - Assert.assertEquals("test cue point", cuePoint.name); - - params = cuePoint.parameters; - Assert.assertEquals("a", params["100"]); - Assert.assertEquals("b", params["101"]); - - Assert.assertEquals(5, cuePoint.duration); - } - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.metadata +{ + import flexunit.framework.Assert; + + public class TestCuePoint + { + [Test] + public function testCuePoint():void + { + var params:Object = new Object(); + params["100"] = "a"; + params["101"] = "b"; + var cuePoint:CuePoint = new CuePoint(CuePointType.ACTIONSCRIPT, 120, "test cue point", params, 5); + + Assert.assertEquals(CuePointType.ACTIONSCRIPT, cuePoint.type); + Assert.assertEquals(120, cuePoint.time); + Assert.assertEquals("test cue point", cuePoint.name); + + params = cuePoint.parameters; + Assert.assertEquals("a", params["100"]); + Assert.assertEquals("b", params["101"]); + + Assert.assertEquals(5, cuePoint.duration); + } + } +} diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/metadata/TestTimelineMetadata.as b/lib/osmf/framework/OSMFTest/src/org/osmf/metadata/TestTimelineMetadata.as index 3ce0440..37609f3 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/metadata/TestTimelineMetadata.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/metadata/TestTimelineMetadata.as @@ -1,427 +1,427 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.metadata -{ - import __AS3__.vec.Vector; - - import flash.events.Event; - import flash.events.EventDispatcher; - - import flexunit.framework.Assert; - - import org.osmf.elements.VideoElement; - import org.osmf.events.LoadEvent; - import org.osmf.events.MetadataEvent; - import org.osmf.events.TimelineMetadataEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.net.NetLoader; - import org.osmf.net.NetStreamLoadTrait; - import org.osmf.netmocker.MockNetLoader; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - import org.osmf.utils.DynamicMediaElement; - import org.osmf.utils.NetFactory; - import org.osmf.utils.TestConstants; - - public class TestTimelineMetadata - { - [Before] - public function setUp():void - { - netFactory = new NetFactory(); - loader = netFactory.createNetLoader(); - createTemporalData(); - eventDispatcher = new EventDispatcher(); - } - - [After] - public function tearDown():void - { - netFactory = null; - loader = null; - _testValues = null; - eventDispatcher = null; - } - - [Test(expects="ArgumentError")] - public function testConstructorPassingNullArguments():void - { - var timelineMetadata:TimelineMetadata = new TimelineMetadata(null); - } - - [Test] - public function testConstructorPassingValidArguments():void - { - var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); - Assert.assertTrue(metadata != null); - } - - [Test] - public function testAddValue():void - { - var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); - metadata.addEventListener(MetadataEvent.VALUE_ADD, onAdd); - var addCount:int = 0; - - for each(var value:TimelineMarker in _testValues) - { - metadata.addValue("" + value.time, value); - } - Assert.assertTrue(addCount == _testValues.length); - - // Values should be sorted by time when we get them back - var numMarkers:int = metadata.keys.length - var lastValue:Number = 0; - - for (var i:int = 0; i < numMarkers; i++) - { - var val:TimelineMarker = metadata.getMarkerAt(i); - Assert.assertTrue(val.time > lastValue); - lastValue = val.time; - } - - // Test invalid values - try - { - metadata.addValue(null, null); - - Assert.fail(); - } - catch(err:ArgumentError) - { - } - - try - { - metadata.addValue("" + -100, new TimelineMarker(-100, -10)); - - Assert.fail(); - } - catch(err:ArgumentError) - { - } - - function onAdd(event:MetadataEvent):void - { - addCount++; - Assert.assertTrue(event.value != null); - } - } - - [Test] - public function testAddMarker():void - { - var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); - metadata.addEventListener(TimelineMetadataEvent.MARKER_ADD, onAdd); - var addCount:int = 0; - - for each (var value:TimelineMarker in _testValues) - { - metadata.addMarker(value); - } - Assert.assertTrue(addCount == _testValues.length); - - // Values should be sorted by time when we get them back - var numMarkers:int = metadata.numMarkers; - var lastValue:Number = 0; - - for (var i:int = 0; i < numMarkers; i++) - { - var val:TimelineMarker = metadata.getMarkerAt(i); - Assert.assertTrue(val.time > lastValue); - lastValue = val.time; - } - - // Test invalid values - try - { - metadata.addMarker(null); - - Assert.fail(); - } - catch(err:ArgumentError) - { - } - - try - { - metadata.addMarker(new TimelineMarker(-100, -10)); - - Assert.fail(); - } - catch(err:ArgumentError) - { - } - - function onAdd(event:TimelineMetadataEvent):void - { - addCount++; - Assert.assertTrue(event.marker != null); - } - } - - [Test] - public function testRemoveValue():void - { - var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); - metadata.addEventListener(MetadataEvent.VALUE_REMOVE, onRemove); - var removeCount:int = 0; - - Assert.assertTrue(metadata.removeValue("" + 3) == null); - - for each(var value:TimelineMarker in _testValues) - { - metadata.addValue("" + value.time, value); - } - Assert.assertTrue(removeCount == 0); - - var result:* = metadata.removeValue("" + 3); - Assert.assertTrue(result != null); - Assert.assertTrue(result is TimelineMarker); - Assert.assertTrue(TimelineMarker(result).time == 3); - Assert.assertTrue(TimelineMarker(result).duration == 1); - Assert.assertTrue(removeCount == 1); - - Assert.assertTrue(metadata.removeValue("" + 3) == null); - Assert.assertTrue(metadata.removeValue("" + 2.8) == null); - Assert.assertTrue(removeCount == 1); - - // Test invalid values - try - { - metadata.removeValue(null); - - Assert.fail(); - } - catch(err:ArgumentError) - { - } - - function onRemove(event:MetadataEvent):void - { - removeCount++; - Assert.assertTrue(event.value != null); - } - } - - [Test] - public function testRemoveMarker():void - { - var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); - metadata.addEventListener(TimelineMetadataEvent.MARKER_REMOVE, onRemove); - var removeCount:int = 0; - - Assert.assertTrue(metadata.removeMarker(new TimelineMarker(3)) == null); - - for each (var value:TimelineMarker in _testValues) - { - metadata.addMarker(value); - } - Assert.assertTrue(removeCount == 0); - - var result:TimelineMarker = metadata.removeMarker(new TimelineMarker(3)); - Assert.assertTrue(result != null); - Assert.assertTrue(result.time == 3); - Assert.assertTrue(result.duration == 1); - Assert.assertTrue(removeCount == 1); - - Assert.assertTrue(metadata.removeMarker(new TimelineMarker(3)) == null); - Assert.assertTrue(metadata.removeMarker(new TimelineMarker(2.8)) == null); - Assert.assertTrue(removeCount == 1); - - // Test invalid values - try - { - metadata.removeMarker(null); - - Assert.fail(); - } - catch(err:ArgumentError) - { - } - - function onRemove(event:TimelineMetadataEvent):void - { - removeCount++; - Assert.assertTrue(event.marker != null); - } - } - - [Test] - public function testGetValue():void - { - var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); - - metadata.addValue("" + 500, new TimelineMarker(500, 5)); - metadata.addValue("" + 300, new TimelineMarker(300)); - metadata.addValue("" + 400, new TimelineMarker(400, 2)); - - Assert.assertTrue(TimelineMarker(metadata.getValue("" + 500)).time == 500); - Assert.assertTrue(TimelineMarker(metadata.getValue("" + 500)).duration == 5); - Assert.assertTrue(TimelineMarker(metadata.getValue("" + 300)).time == 300); - Assert.assertTrue(isNaN(TimelineMarker(metadata.getValue("" + 300)).duration)); - Assert.assertTrue(TimelineMarker(metadata.getValue("" + 400)).time == 400); - Assert.assertTrue(TimelineMarker(metadata.getValue("" + 400)).duration == 2); - - Assert.assertNull(metadata.getValue("" + 123)); - Assert.assertNull(metadata.getValue("foo")); - - try - { - metadata.getValue(null); - - Assert.fail(); - } - catch(err:ArgumentError) - { - } - } - - [Test] - public function testGetMarkerAt():void - { - var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); - - metadata.addMarker(new TimelineMarker(500, 5)); - metadata.addMarker(new TimelineMarker(300)); - metadata.addMarker(new TimelineMarker(400, 2)); - - Assert.assertTrue(metadata.numMarkers == 3); - Assert.assertTrue(metadata.getMarkerAt(0).time == 300); - Assert.assertTrue(isNaN(metadata.getMarkerAt(0).duration)); - Assert.assertTrue(metadata.getMarkerAt(1).time == 400); - Assert.assertTrue(metadata.getMarkerAt(1).duration == 2); - Assert.assertTrue(metadata.getMarkerAt(2).time == 500); - Assert.assertTrue(metadata.getMarkerAt(2).duration == 5); - - Assert.assertNull(metadata.getMarkerAt(-5)); - Assert.assertNull(metadata.getMarkerAt(3)); - } - - [Test] - public function testRemovingATrait():void - { - var mediaElement:DynamicMediaElement = createDynamicMediaElement(); - - var metadata:TimelineMetadata = new TimelineMetadata(mediaElement); - - for each (var value:TimelineMarker in _testValues) - { - metadata.addMarker(value); - } - - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - Assert.assertTrue(loadTrait != null); - loadTrait.load(); - Assert.assertTrue(loadTrait.loadState == LoadState.READY); - - var playTrait:PlayTrait = mediaElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - Assert.assertTrue(playTrait != null); - playTrait.play(); - - var timeTrait:TimeTrait = mediaElement.getTrait(MediaTraitType.TIME) as TimeTrait; - Assert.assertTrue(timeTrait != null); - - var seekTrait:SeekTrait = mediaElement.getTrait(MediaTraitType.SEEK) as SeekTrait; - Assert.assertTrue(seekTrait != null); - - // Remove the traits while playing - mediaElement.doRemoveTrait(MediaTraitType.SEEK); - mediaElement.doRemoveTrait(MediaTraitType.PLAY); - mediaElement.doRemoveTrait(MediaTraitType.TIME); - } - - private function createTemporalData():void - { - _testValues = new Vector.(); - - _testValues.push(new TimelineMarker(3.5, 1)); - _testValues.push(new TimelineMarker(1)); - _testValues.push(new TimelineMarker(3, 0)); - _testValues.push(new TimelineMarker(2)); - _testValues.push(new TimelineMarker(2.5, 1)); - - // Add a few duplicates. - _testValues.push(new TimelineMarker(1, 1)); - _testValues.push(new TimelineMarker(3, 1)); - } - - - private function createMediaElement():VideoElement - { - if (loader is MockNetLoader) - { - // Give our mock loader an arbitrary duration and size to ensure - // we get metadata. - MockNetLoader(loader).netStreamExpectedDuration = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_DURATION; - MockNetLoader(loader).netStreamExpectedWidth = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_WIDTH; - MockNetLoader(loader).netStreamExpectedHeight = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_HEIGHT; - } - - return new VideoElement(null, loader); - } - - private function createDynamicMediaElement():DynamicMediaElement - { - if (loader is MockNetLoader) - { - // Give our mock loader an arbitrary duration and size to ensure - // we get metadata. - MockNetLoader(loader).netStreamExpectedDuration = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_DURATION; - MockNetLoader(loader).netStreamExpectedWidth = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_WIDTH; - MockNetLoader(loader).netStreamExpectedHeight = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_HEIGHT; - } - - var elem:DynamicMediaElement = new DynamicMediaElement([ MediaTraitType.PLAY, - MediaTraitType.SEEK, MediaTraitType.TIME ], - loader, resourceForMediaElement); - elem.doAddTrait(MediaTraitType.LOAD, new NetStreamLoadTrait(loader, resourceForMediaElement)); - return elem; - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - private function get resourceForMediaElement():MediaResourceBase - { - // Use a valid URL so that the tests will pass if we use - // a real NetLoader rather than a MockNetLoader. - return new URLResource(TestConstants.REMOTE_PROGRESSIVE_VIDEO); - } - - private static const TOLERANCE:Number = .25; - private static const TIMEOUT:Number = 9000; - - private var _testValues:Vector.; - - private var netFactory:NetFactory; - private var loader:NetLoader; - private var eventDispatcher:EventDispatcher; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.metadata +{ + import __AS3__.vec.Vector; + + import flash.events.Event; + import flash.events.EventDispatcher; + + import flexunit.framework.Assert; + + import org.osmf.elements.VideoElement; + import org.osmf.events.LoadEvent; + import org.osmf.events.MetadataEvent; + import org.osmf.events.TimelineMetadataEvent; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.net.NetLoader; + import org.osmf.net.NetStreamLoadTrait; + import org.osmf.netmocker.MockNetLoader; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + import org.osmf.utils.DynamicMediaElement; + import org.osmf.utils.NetFactory; + import org.osmf.utils.TestConstants; + + public class TestTimelineMetadata + { + [Before] + public function setUp():void + { + netFactory = new NetFactory(); + loader = netFactory.createNetLoader(); + createTemporalData(); + eventDispatcher = new EventDispatcher(); + } + + [After] + public function tearDown():void + { + netFactory = null; + loader = null; + _testValues = null; + eventDispatcher = null; + } + + [Test(expects="ArgumentError")] + public function testConstructorPassingNullArguments():void + { + var timelineMetadata:TimelineMetadata = new TimelineMetadata(null); + } + + [Test] + public function testConstructorPassingValidArguments():void + { + var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); + Assert.assertTrue(metadata != null); + } + + [Test] + public function testAddValue():void + { + var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); + metadata.addEventListener(MetadataEvent.VALUE_ADD, onAdd); + var addCount:int = 0; + + for each(var value:TimelineMarker in _testValues) + { + metadata.addValue("" + value.time, value); + } + Assert.assertTrue(addCount == _testValues.length); + + // Values should be sorted by time when we get them back + var numMarkers:int = metadata.keys.length + var lastValue:Number = 0; + + for (var i:int = 0; i < numMarkers; i++) + { + var val:TimelineMarker = metadata.getMarkerAt(i); + Assert.assertTrue(val.time > lastValue); + lastValue = val.time; + } + + // Test invalid values + try + { + metadata.addValue(null, null); + + Assert.fail(); + } + catch(err:ArgumentError) + { + } + + try + { + metadata.addValue("" + -100, new TimelineMarker(-100, -10)); + + Assert.fail(); + } + catch(err:ArgumentError) + { + } + + function onAdd(event:MetadataEvent):void + { + addCount++; + Assert.assertTrue(event.value != null); + } + } + + [Test] + public function testAddMarker():void + { + var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); + metadata.addEventListener(TimelineMetadataEvent.MARKER_ADD, onAdd); + var addCount:int = 0; + + for each (var value:TimelineMarker in _testValues) + { + metadata.addMarker(value); + } + Assert.assertTrue(addCount == _testValues.length); + + // Values should be sorted by time when we get them back + var numMarkers:int = metadata.numMarkers; + var lastValue:Number = 0; + + for (var i:int = 0; i < numMarkers; i++) + { + var val:TimelineMarker = metadata.getMarkerAt(i); + Assert.assertTrue(val.time > lastValue); + lastValue = val.time; + } + + // Test invalid values + try + { + metadata.addMarker(null); + + Assert.fail(); + } + catch(err:ArgumentError) + { + } + + try + { + metadata.addMarker(new TimelineMarker(-100, -10)); + + Assert.fail(); + } + catch(err:ArgumentError) + { + } + + function onAdd(event:TimelineMetadataEvent):void + { + addCount++; + Assert.assertTrue(event.marker != null); + } + } + + [Test] + public function testRemoveValue():void + { + var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); + metadata.addEventListener(MetadataEvent.VALUE_REMOVE, onRemove); + var removeCount:int = 0; + + Assert.assertTrue(metadata.removeValue("" + 3) == null); + + for each(var value:TimelineMarker in _testValues) + { + metadata.addValue("" + value.time, value); + } + Assert.assertTrue(removeCount == 0); + + var result:* = metadata.removeValue("" + 3); + Assert.assertTrue(result != null); + Assert.assertTrue(result is TimelineMarker); + Assert.assertTrue(TimelineMarker(result).time == 3); + Assert.assertTrue(TimelineMarker(result).duration == 1); + Assert.assertTrue(removeCount == 1); + + Assert.assertTrue(metadata.removeValue("" + 3) == null); + Assert.assertTrue(metadata.removeValue("" + 2.8) == null); + Assert.assertTrue(removeCount == 1); + + // Test invalid values + try + { + metadata.removeValue(null); + + Assert.fail(); + } + catch(err:ArgumentError) + { + } + + function onRemove(event:MetadataEvent):void + { + removeCount++; + Assert.assertTrue(event.value != null); + } + } + + [Test] + public function testRemoveMarker():void + { + var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); + metadata.addEventListener(TimelineMetadataEvent.MARKER_REMOVE, onRemove); + var removeCount:int = 0; + + Assert.assertTrue(metadata.removeMarker(new TimelineMarker(3)) == null); + + for each (var value:TimelineMarker in _testValues) + { + metadata.addMarker(value); + } + Assert.assertTrue(removeCount == 0); + + var result:TimelineMarker = metadata.removeMarker(new TimelineMarker(3)); + Assert.assertTrue(result != null); + Assert.assertTrue(result.time == 3); + Assert.assertTrue(result.duration == 1); + Assert.assertTrue(removeCount == 1); + + Assert.assertTrue(metadata.removeMarker(new TimelineMarker(3)) == null); + Assert.assertTrue(metadata.removeMarker(new TimelineMarker(2.8)) == null); + Assert.assertTrue(removeCount == 1); + + // Test invalid values + try + { + metadata.removeMarker(null); + + Assert.fail(); + } + catch(err:ArgumentError) + { + } + + function onRemove(event:TimelineMetadataEvent):void + { + removeCount++; + Assert.assertTrue(event.marker != null); + } + } + + [Test] + public function testGetValue():void + { + var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); + + metadata.addValue("" + 500, new TimelineMarker(500, 5)); + metadata.addValue("" + 300, new TimelineMarker(300)); + metadata.addValue("" + 400, new TimelineMarker(400, 2)); + + Assert.assertTrue(TimelineMarker(metadata.getValue("" + 500)).time == 500); + Assert.assertTrue(TimelineMarker(metadata.getValue("" + 500)).duration == 5); + Assert.assertTrue(TimelineMarker(metadata.getValue("" + 300)).time == 300); + Assert.assertTrue(isNaN(TimelineMarker(metadata.getValue("" + 300)).duration)); + Assert.assertTrue(TimelineMarker(metadata.getValue("" + 400)).time == 400); + Assert.assertTrue(TimelineMarker(metadata.getValue("" + 400)).duration == 2); + + Assert.assertNull(metadata.getValue("" + 123)); + Assert.assertNull(metadata.getValue("foo")); + + try + { + metadata.getValue(null); + + Assert.fail(); + } + catch(err:ArgumentError) + { + } + } + + [Test] + public function testGetMarkerAt():void + { + var metadata:TimelineMetadata = new TimelineMetadata(new VideoElement()); + + metadata.addMarker(new TimelineMarker(500, 5)); + metadata.addMarker(new TimelineMarker(300)); + metadata.addMarker(new TimelineMarker(400, 2)); + + Assert.assertTrue(metadata.numMarkers == 3); + Assert.assertTrue(metadata.getMarkerAt(0).time == 300); + Assert.assertTrue(isNaN(metadata.getMarkerAt(0).duration)); + Assert.assertTrue(metadata.getMarkerAt(1).time == 400); + Assert.assertTrue(metadata.getMarkerAt(1).duration == 2); + Assert.assertTrue(metadata.getMarkerAt(2).time == 500); + Assert.assertTrue(metadata.getMarkerAt(2).duration == 5); + + Assert.assertNull(metadata.getMarkerAt(-5)); + Assert.assertNull(metadata.getMarkerAt(3)); + } + + [Test] + public function testRemovingATrait():void + { + var mediaElement:DynamicMediaElement = createDynamicMediaElement(); + + var metadata:TimelineMetadata = new TimelineMetadata(mediaElement); + + for each (var value:TimelineMarker in _testValues) + { + metadata.addMarker(value); + } + + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + Assert.assertTrue(loadTrait != null); + loadTrait.load(); + Assert.assertTrue(loadTrait.loadState == LoadState.READY); + + var playTrait:PlayTrait = mediaElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + Assert.assertTrue(playTrait != null); + playTrait.play(); + + var timeTrait:TimeTrait = mediaElement.getTrait(MediaTraitType.TIME) as TimeTrait; + Assert.assertTrue(timeTrait != null); + + var seekTrait:SeekTrait = mediaElement.getTrait(MediaTraitType.SEEK) as SeekTrait; + Assert.assertTrue(seekTrait != null); + + // Remove the traits while playing + mediaElement.doRemoveTrait(MediaTraitType.SEEK); + mediaElement.doRemoveTrait(MediaTraitType.PLAY); + mediaElement.doRemoveTrait(MediaTraitType.TIME); + } + + private function createTemporalData():void + { + _testValues = new Vector.(); + + _testValues.push(new TimelineMarker(3.5, 1)); + _testValues.push(new TimelineMarker(1)); + _testValues.push(new TimelineMarker(3, 0)); + _testValues.push(new TimelineMarker(2)); + _testValues.push(new TimelineMarker(2.5, 1)); + + // Add a few duplicates. + _testValues.push(new TimelineMarker(1, 1)); + _testValues.push(new TimelineMarker(3, 1)); + } + + + private function createMediaElement():VideoElement + { + if (loader is MockNetLoader) + { + // Give our mock loader an arbitrary duration and size to ensure + // we get metadata. + MockNetLoader(loader).netStreamExpectedDuration = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_DURATION; + MockNetLoader(loader).netStreamExpectedWidth = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_WIDTH; + MockNetLoader(loader).netStreamExpectedHeight = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_HEIGHT; + } + + return new VideoElement(null, loader); + } + + private function createDynamicMediaElement():DynamicMediaElement + { + if (loader is MockNetLoader) + { + // Give our mock loader an arbitrary duration and size to ensure + // we get metadata. + MockNetLoader(loader).netStreamExpectedDuration = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_DURATION; + MockNetLoader(loader).netStreamExpectedWidth = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_WIDTH; + MockNetLoader(loader).netStreamExpectedHeight = TestConstants.REMOTE_PROGRESSIVE_VIDEO_EXPECTED_HEIGHT; + } + + var elem:DynamicMediaElement = new DynamicMediaElement([ MediaTraitType.PLAY, + MediaTraitType.SEEK, MediaTraitType.TIME ], + loader, resourceForMediaElement); + elem.doAddTrait(MediaTraitType.LOAD, new NetStreamLoadTrait(loader, resourceForMediaElement)); + return elem; + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + private function get resourceForMediaElement():MediaResourceBase + { + // Use a valid URL so that the tests will pass if we use + // a real NetLoader rather than a MockNetLoader. + return new URLResource(TestConstants.REMOTE_PROGRESSIVE_VIDEO); + } + + private static const TOLERANCE:Number = .25; + private static const TIMEOUT:Number = 9000; + + private var _testValues:Vector.; + + private var netFactory:NetFactory; + private var loader:NetLoader; + private var eventDispatcher:EventDispatcher; + } +} diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/ABRTestUtils.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/ABRTestUtils.as new file mode 100644 index 0000000..9f29184 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/ABRTestUtils.as @@ -0,0 +1,65 @@ +package org.osmf.net +{ + import org.osmf.net.rules.RuleBase; + + public class ABRTestUtils + { + // helper function to test whether two Vector. are equal + public static function equalNumberVectors(v:Vector., w:Vector.):Boolean + { + if (v == w) + { + return true; + } + + if (v == null || w == null) + { + return false; + } + + if (v.length != w.length) + { + return false; + } + + for (var i:uint = 0; i < v.length; i++) + { + if (v[i] != w[i] && !(isNaN(v[i]) && isNaN(w[i]))) + { + return false; + } + } + + return true; + } + + // helper function to test whether two Vector. are equal + public static function equalRuleBaseVectors(v:Vector., w:Vector.):Boolean + { + if (v == w) + { + return true; + } + + if (v == null || w == null) + { + return false; + } + + if (v.length != w.length) + { + return false; + } + + for (var i:uint = 0; i < v.length; i++) + { + if (v[i] != w[i]) + { + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/NetStreamSwitcherMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/NetStreamSwitcherMocker.as new file mode 100644 index 0000000..e5b18fd --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/NetStreamSwitcherMocker.as @@ -0,0 +1,75 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net +{ + import flash.net.NetStream; + + + public class NetStreamSwitcherMocker extends NetStreamSwitcher + { + public function NetStreamSwitcherMocker(netStream:NetStream, dsResource:DynamicStreamingResource) + { + super(netStream, dsResource); + } + + override public function get currentIndex():uint + { + return _currentIndexMocker; + } + + public function set currentIndex(value:uint):void + { + _currentIndexMocker = value; + } + + override public function get actualIndex():int + { + return _actualIndexMocker; + } + + public function set actualIndex(value:int):void + { + _actualIndexMocker = value; + } + + override public function get switching():Boolean + { + return _switchingMocker; + } + + public function set switching(value:Boolean):void + { + _switchingMocker = value; + } + + override public function switchTo(index:int):void + { + lastSwitchIndex = index; + } + + public var lastSwitchIndex:int = -1; + + private var _currentIndexMocker:uint = 0; + private var _actualIndexMocker:int = 0; + private var _switchingMocker:Boolean = false; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/TestSwitchManager.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/TestSwitchManager.as new file mode 100644 index 0000000..c2171e3 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/TestSwitchManager.as @@ -0,0 +1,1587 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net +{ + import flash.events.Event; + import flash.net.NetConnection; + import flash.net.NetStream; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertNull; + import org.flexunit.asserts.assertStrictlyEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.HTTPStreamingEvent; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.httpstreaming.DefaultHTTPStreamingSwitchManager; + import org.osmf.net.metrics.ActualBitrateMetricMocker; + import org.osmf.net.metrics.AvailableQualityLevelsMetricMocker; + import org.osmf.net.metrics.BandwidthMetricMocker; + import org.osmf.net.metrics.DefaultMetricFactoryMocker; + import org.osmf.net.metrics.FragmentCountMetricMocker; + import org.osmf.net.metrics.MetricFactory; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.metrics.MetricType; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + import org.osmf.net.rules.Recommendation; + import org.osmf.net.rules.RuleBase; + import org.osmf.net.rules.RuleMocker; + + public class TestSwitchManager + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + netStream.client = new NetClient(); + qosInfoHistory = new QoSInfoHistory(netStream); + //just to make the metrics work if the metrics have not mocked the getters for the value + addQoSInfo(generateQoSInfo(mockTimestamp++, 150, 250, 350, 450, 550)); + + metricFactory = new DefaultMetricFactoryMocker(qosInfoHistory); + metricRepository = new MetricRepository(metricFactory); + + qualityLevels = new Vector.(); + for(var i:int = 0; i<5; i++) + qualityLevels.push( new QualityLevel(i, 150+100*i, "test" + (150+100*i))); + + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testDefaultSwitchManagerInitWith3Rules():void + { + var ruleWeights:Vector. = new Vector.(); + ruleWeights.push(0.7); + ruleWeights.push(0.2); + ruleWeights.push(0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push(new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push(new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push(new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights); + + assertTrue(switchManager.autoSwitch); + assertEquals(3, switchManager.normalRuleWeights.length); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(int.MAX_VALUE, switchManager.maxAllowedIndex); + assertEquals(0, switchManager.currentIndex); + assertEquals(12, switchManager.metricRepository.metricFactory.numItems); + assertEquals(0.85, switchManager.minReliability); + assertNull(switchManager.emergencyRules); + assertEquals(0, switchManager.actualIndex); + assertEquals(3, switchManager.normalRules.length); + + assertTrue(ABRTestUtils.equalRuleBaseVectors(rules, switchManager.normalRules)); + + assertEquals(5, switchManager.minReliabilityRecordSize); + assertEquals(30, switchManager.maxReliabilityRecordSize); + + assertEquals(0.9, switchManager.climbFactor); + + assertEquals(1, switchManager.maxUpSwitchLimit); + assertEquals(2, switchManager.maxDownSwitchLimit); + + + } + + + [Test] + public function testDefaultSwitchManagerInitNonDefault():void + { + var ruleWeights:Vector. = new Vector.(); + ruleWeights.push(0.7); + ruleWeights.push(0.2); + ruleWeights.push(0.1); + + rules = new Vector.(); + + emergencyRules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push(new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push(new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push(new RuleMocker(new Recommendation("rule3", 700, 1))); + + emergencyRules.push(new RuleMocker(new Recommendation("emergencyrule1", 50, 1))); + emergencyRules.push(new RuleMocker(new Recommendation("emergencyrule2", 60, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, emergencyRules, false, rules, ruleWeights, 0.89, 6, 16, 0.85, 3, 4); + + assertFalse(switchManager.autoSwitch); + assertEquals(3, switchManager.normalRuleWeights.length); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(int.MAX_VALUE, switchManager.maxAllowedIndex); + assertEquals(0, switchManager.currentIndex); + assertEquals(12 ,switchManager.metricRepository.metricFactory.numItems); + assertNotNull(switchManager.emergencyRules); + assertEquals(2, switchManager.emergencyRules.length); + assertTrue(ABRTestUtils.equalRuleBaseVectors(emergencyRules, switchManager.emergencyRules)); + + assertEquals(0, switchManager.actualIndex); + assertEquals(3, switchManager.normalRules.length); + assertTrue(ABRTestUtils.equalRuleBaseVectors(rules, switchManager.normalRules)); + + assertEquals(0.89, switchManager.minReliability); + + assertEquals(6, switchManager.minReliabilityRecordSize); + assertEquals(16, switchManager.maxReliabilityRecordSize); + + assertEquals(0.85, switchManager.climbFactor); + + assertEquals(3, switchManager.maxUpSwitchLimit); + assertEquals(4, switchManager.maxDownSwitchLimit); + + assertFalse(switchManager.autoSwitch); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithNullNetStream():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(null, switcher, metricRepository, null, true, rules, ruleWeights); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithNullSwitcher():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, null, metricRepository, null, true, rules, ruleWeights); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithNullMetricRepository():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, null, null, true, rules, ruleWeights); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithNullRules():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, null, ruleWeights); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithEmptyRulesAndRuleWeights():void + { + var ruleWeights:Vector. = new Vector.(); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithNullRuleWeights():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, null); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithMinimumReliabilityNaN():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, null, NaN); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithNegativeMinimumReliability():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, -0.1 ); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithMinimumReliabilityGreaterThanOne():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 1.1); + } + + [Test] + public function testDefaultSwitchManagerInitWithMinimumReliabilityOne():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 1); + assertEquals(1, switchManager.minReliability); + + } + + [Test] + public function testDefaultSwitchManagerInitWithMinimumReliabilityZero():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 0); + assertEquals(0, switchManager.minReliability); + + } + + public function testDefaultSwitchManagerInitWithIncorrectRecordSizeInterval():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 0.9, 20, 10); + assertEquals(20, switchManager.minReliabilityRecordSize); + assertEquals(20, switchManager.maxReliabilityRecordSize); + } + + [Test(expects = "ArgumentError")] + public function testDefaultSwitchManagerInitWithIncorrectRecordSizeMinimum():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 0.9, 0.5, 1, 14); + } + + [Test] + public function testDefaultSwitchManagerInitWithMinimumRecordInterval():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 0.9, 2, 2); + + assertEquals(2, switchManager.maxReliabilityRecordSize); + assertEquals(2, switchManager.minReliabilityRecordSize); + } + + + public function testDefaultSwitchManagerInitWithZeroUpSwitchLimit():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 0.9, 4,29, 0.89, 0); + assertEquals(-1, switchManager.maxUpSwitchLimit); + } + + public function testDefaultSwitchManagerInitWithZeroDownSwitchLimit():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 0.9, 4,29, 0.89, 1, 0); + assertEquals(-1, switchManager.maxUpSwitchLimit); + } + + [Test] + public function testDefaultSwitchManagerInitWithNegativeSwitchingLimits():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 1,5, 30, 0.9, -2, -3); + assertEquals(-1, switchManager.maxUpSwitchLimit); + assertEquals(-1, switchManager.maxDownSwitchLimit); + } + + [Test] + public function testSetMinimumReliability():void + { + createSwitchManager3Rules(); + switchManager.minReliability = 0.77; + assertEquals(0.77, switchManager.minReliability); + switchManager.minReliability = 0; + assertEquals(0, switchManager.minReliability); + switchManager.minReliability = 1; + assertEquals(1, switchManager.minReliability); + } + + [Test(expects = "ArgumentError")] + public function testSetMinimumReliabilityNegative():void + { + createSwitchManager3Rules(); + switchManager.minReliability = -0.1; + } + + [Test(expects = "ArgumentError")] + public function testSetMinimumReliabilityGreaterThan1():void + { + createSwitchManager3Rules(); + switchManager.minReliability = 1.1; + } + + [Test(expects = "ArgumentError")] + public function testSetMinimumReliabilityNaN():void + { + createSwitchManager3Rules(); + switchManager.minReliability = NaN; + } + + + [Test(expects = "ArgumentError")] + public function testSetClimbFactorNegative():void + { + createSwitchManager3Rules(); + switchManager.climbFactor = -0.1; + } + + + [Test(expects = "ArgumentError")] + public function testSetClimbFactorNaN():void + { + createSwitchManager3Rules(); + switchManager.climbFactor = NaN; + } + + [Test(expects = "ArgumentError")] + public function testSetClimbFactorZero():void + { + createSwitchManager3Rules(); + switchManager.climbFactor = 0; + } + + [Test] + public function testGetAndSetRuleWeights():void + { + createSwitchManager3Rules(); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(0.2, switchManager.normalRuleWeights[1]); + assertEquals(0.1, switchManager.normalRuleWeights[2]); + switchManager.normalRuleWeights = generateWeights(10.1, 11.2, 12.3); + + assertEquals(10.1, switchManager.normalRuleWeights[0]); + assertEquals(11.2, switchManager.normalRuleWeights[1]); + assertEquals(12.3, switchManager.normalRuleWeights[2]); + } + + [Test] + public function testGetAndSetRuleWeightsOneNotZero():void + { + createSwitchManager3Rules(); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(0.2, switchManager.normalRuleWeights[1]); + assertEquals(0.1, switchManager.normalRuleWeights[2]); + switchManager.normalRuleWeights = generateWeights(0, 2, 0); + + assertEquals(0, switchManager.normalRuleWeights[0]); + assertEquals(2, switchManager.normalRuleWeights[1]); + assertEquals(0, switchManager.normalRuleWeights[2]); + } + + [Test(expects = "ArgumentError")] + public function testGetAndSetDifferentSizeRuleWeights():void + { + createSwitchManager3Rules(); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(0.2, switchManager.normalRuleWeights[1]); + assertEquals(0.1, switchManager.normalRuleWeights[2]); + switchManager.normalRuleWeights = generateWeights(10.1, 11.2, 12.3, 13.4); + } + + [Test(expects = "ArgumentError")] + public function testGetAndSetAllZeroRuleWeights():void + { + createSwitchManager3Rules(); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(0.2, switchManager.normalRuleWeights[1]); + assertEquals(0.1, switchManager.normalRuleWeights[2]); + switchManager.normalRuleWeights = generateWeights(0, 0, 0); + } + + [Test(expects = "ArgumentError")] + public function testGetAndSetNullRuleWeights():void + { + createSwitchManager3Rules(); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(0.2, switchManager.normalRuleWeights[1]); + assertEquals(0.1, switchManager.normalRuleWeights[2]); + switchManager.normalRuleWeights = null; + } + + + [Test(expects = "ArgumentError")] + public function testGetAndSetNegativeRuleWeights():void + { + createSwitchManager3Rules(); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(0.2, switchManager.normalRuleWeights[1]); + assertEquals(0.1, switchManager.normalRuleWeights[2]); + switchManager.normalRuleWeights = generateWeights(-2, 1, 1); + } + + [Test(expects = "ArgumentError")] + public function testGetAndSetNaNRuleWeights():void + { + createSwitchManager3Rules(); + assertEquals(0.7, switchManager.normalRuleWeights[0]); + assertEquals(0.2, switchManager.normalRuleWeights[1]); + assertEquals(0.1, switchManager.normalRuleWeights[2]); + switchManager.normalRuleWeights = generateWeights(NaN, 1, 1); + } + + public function testSetDownSwitchLimit():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + assertEquals(2, switchManager.maxDownSwitchLimit); + switchManager.maxDownSwitchLimit = 0; + assertEquals(-1, switchManager.maxDownSwitchLimit); + } + + public function testSetUpSwitchLimit():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + assertEquals(1, switchManager.maxUpSwitchLimit); + switchManager.maxUpSwitchLimit = 0; + assertEquals(-1, switchManager.maxUpSwitchLimit); + } + + [Test] + public function testSetMaxDownAndUpSwitchLimit():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + assertEquals(1, switchManager.maxUpSwitchLimit); + assertEquals(2, switchManager.maxDownSwitchLimit); + switchManager.maxUpSwitchLimit = 3; + switchManager.maxDownSwitchLimit = 4; + assertEquals(3, switchManager.maxUpSwitchLimit); + assertEquals(4, switchManager.maxDownSwitchLimit); + + switchManager.maxUpSwitchLimit = -3; + switchManager.maxDownSwitchLimit = -4; + assertEquals(-1, switchManager.maxUpSwitchLimit); + assertEquals(-1, switchManager.maxDownSwitchLimit); + } + + + + /** + * Test switch up + * + **/ + [Test] + public function testGetNewIndexSwitchFrom0To1():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 320, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 310, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 300, 1); + + //should go to 250, switch up 1. + assertEquals(1, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(250,true); + } + + /** + * Test switch up blocked by security factor. + * + **/ + [Test] + public function testGetNewIndexSwitchFrom2To3LimitedByFactor():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 420, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 410, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 400, 1); + + //setup: should go to 350, switch up 2. + assertEquals(2, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(350,true); + + + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", (450 + (0.9-1) * 350) / 0.9 - 0.01, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 410, 0); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 400, 0); + //instead of going to 450, switch up 3, should stay on 2 + assertEquals(2, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(350,true); + + + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", (450 + (0.9-1) * 350) / 0.9 + 0.01, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 410, 0); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 400, 0); + //switch up to 450 = index 3 + assertEquals(3, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(450,true); + + } + + + /** + * Test switch down + * + **/ + [Test] + public function testGetNewIndexSwitchFrom2To1():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 420, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 410, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 400, 1); + + //prepare switch, go to 350, switch up to stream 2. + assertEquals(2, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(350,true); + + + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 320, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 310, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 300, 1); + + //should go to 250, switch down to 1. + assertEquals(1, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(250,true); + + } + + + + /** + * Test unavailable AvailableBitratesMetric + * + **/ + [Test(expects = "Error")] + public function testGetNewIndexUnavailableAvailableBitratesMetric():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = false; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 320, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 310, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 300, 1); + + var i:int = switchManager.getNewIndex(); + + } + + /** + * Test unavailable ActualBitrate + * Note: currentindex cannot be updated in unit tests, will test against a value of 0 + * + **/ + [Test] + public function testGetNewIndexWhenActualBitrateIsInvalid():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 420, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 410, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 400, 1); + + //prepare switch, go to 350, switch up to stream 2. + assertEquals(2, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + //make it invalid + mockSwitchTo(350,false); + + //indirect evaluation of the currentIndex = 0 + //switch up to 2 should stop to 1 + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 350*0.9 -0.01, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 310, 0); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 300, 0); + + + assertEquals(1, switchManager.getNewIndex()); + + mockSwitchTo(250,true); + + } + + [Test] + public function testGetNewIndexSwitchOnSameIndex():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 420, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 410, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 400, 1); + + //prepare switch, go to 350, switch up to stream 2. + assertEquals(2, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(350,true); + + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 420, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 410, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 400, 1); + + //prepare switch, go to 350, switch up to stream 2. + assertEquals(2, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(350,true); + + } + + /** + * Test switch up blocked by an unreliable bitrate level. + * + **/ + [Test] + public function testGetNewIndexSwitchForUnreliableBitrate():void + { + //setup switches + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(3); + mockRules(2); + mockRules(3); + mockRules(1); + + //real test, try to switch to 3 + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 520, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 510, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 500, 1); + //do not switch up due to low Reliability + assertEquals(2, switchManager.getNewIndex()); + mockSwitchTo(350,true); + + } + + [Test] + public function testGetReliability():void + { + //setup switches + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(3); + mockRules(2); + + mockRules(3); + + var i:int; + for (i = 0; i<5; i++) + assertTrue(isNaN(switchManager.getCurrentReliability(i))); + + mockRules(1); + + assertEquals(1, switchManager.getCurrentReliability(0)); + assertTrue(isNaN(switchManager.getCurrentReliability(1))); + assertEquals(1, switchManager.getCurrentReliability(2)); + assertEquals(1-(2*2)/(2*2), switchManager.getCurrentReliability(3)); + assertTrue(isNaN(switchManager.getCurrentReliability(4))); + + mockRules(2); + mockRules(1); + + assertEquals(1, switchManager.getCurrentReliability(0)); + assertEquals(1, switchManager.getCurrentReliability(1)); + assertEquals(1-(1*1)/(2*3), switchManager.getCurrentReliability(2)); + assertEquals(1-(2*2)/(2*3), switchManager.getCurrentReliability(3)); + assertTrue(isNaN(switchManager.getCurrentReliability(4))); + } + + [Test] + public function testGetReliabilityforEmergencySwitches():void + { + //setup switches + createSwitchManager3Rulesand2EmergencyRules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(3); + mockRules(2); + mockRules(4); + + var i:int; + for (i = 0; i<5; i++) + assertTrue(isNaN(switchManager.getCurrentReliability(i))); + + mockEmergencyRules(2); + + assertEquals(1, switchManager.getCurrentReliability(0)); + assertTrue(isNaN(switchManager.getCurrentReliability(1))); + assertEquals(1, switchManager.getCurrentReliability(2)); + assertEquals(1-(1*1)/(1*2), switchManager.getCurrentReliability(3)); + assertEquals(0,switchManager.getCurrentReliability(4)); + + mockRules(1); + + assertEquals(1, switchManager.getCurrentReliability(0)); + assertTrue(isNaN(switchManager.getCurrentReliability(1))); + assertEquals(1-(1*1)/(2*3), switchManager.getCurrentReliability(2)); + assertEquals(1-(1*1)/(1*3), switchManager.getCurrentReliability(3)); + assertEquals(0,switchManager.getCurrentReliability(4)); + + mockRules(1); + + assertEquals(1, switchManager.getCurrentReliability(0)); + assertEquals(1, switchManager.getCurrentReliability(1)); + assertEquals(1-(1*1)/(2*3), switchManager.getCurrentReliability(2)); + assertEquals(1-(1*1)/(1*3), switchManager.getCurrentReliability(3)); + assertEquals(0,switchManager.getCurrentReliability(4)); + + } + + // http://bugs.adobe.com/jira/browse/FM-1493 + // [ABR] A stream should be marked unreliable if an emergency down switch occurred, even if the record is small + [Test] + public function testGetReliabilityforEmergencySwitchWithReliabilityRecordBelowMinThreshold():void + { + //setup switches + createSwitchManager3Rulesand2EmergencyRules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(3); + mockEmergencyRules(2); + + assertEquals(0,switchManager.getCurrentReliability(3)); + } + + [Test] + public function testGetReliabilityforEmergencySwitchesUpwards():void + { + //setup switches + createSwitchManager3Rulesand2EmergencyRules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(1); + mockRules(2); + mockRules(2); + mockRules(3); + mockEmergencyRules(3); + + assertEquals(1, switchManager.getCurrentReliability(0)); + assertEquals(1, switchManager.getCurrentReliability(1)); + assertEquals(1, switchManager.getCurrentReliability(2)); + assertEquals(1, switchManager.getCurrentReliability(3)); + assertTrue(isNaN(switchManager.getCurrentReliability(4))); + + mockEmergencyRules(4); + + assertEquals(1, switchManager.getCurrentReliability(0)); + assertEquals(1, switchManager.getCurrentReliability(1)); + assertEquals(1, switchManager.getCurrentReliability(2)); + assertEquals(1, switchManager.getCurrentReliability(3)); + assertTrue(isNaN(switchManager.getCurrentReliability(4))); + + + } + + + /** + * Test PushToHistory indirect by checking reliability of an idex that should not be any more in history + * + **/ + [Test] + public function testPushReliabilityToHistory():void + { + //setup switches 0/401230120101230/1 + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + + mockRules(4); + mockRules(0); + mockRules(1); + mockRules(2); + mockRules(3); + mockRules(0); + mockRules(1); + mockRules(2); + mockRules(0); + mockRules(1); + mockRules(0); + mockRules(1); + mockRules(2); + mockRules(3); + mockRules(0); + assertEquals(1-(1*1)/(1*7), switchManager.getCurrentReliability(4)); + mockRules(1); + //this is the main check + assertTrue(isNaN(switchManager.getCurrentReliability(4))); + + } + + [Test] + public function testGetNewIndexBitrateOverMax():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 3200, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 3100, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 3000, 1); + + //should go to 550, switch up 4. + assertEquals(4, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(550,true); + + } + + [Test] + public function testGetNewIndexBitrateUnderMin():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(4); + + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 32, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 31, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 30, 1); + + //should go to 150, switch down to 0. + assertEquals(0, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(150,true); + + } + + [Test] + public function testGetNewIndexBitrateIgnoreUnsureRules():void + { + createSwitchManager3Rules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(2); + + availableQualityMetric.returnValid = true; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 320, 0); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 310, 0); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 300, 0); + + //should stay on the same index + assertEquals(2, switchManager.getNewIndex()); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(350,true); + } + + + [Test] + public function testGetNewIndexForEmergencyRule():void + { + createSwitchManager3Rulesand2EmergencyRules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(3); + + mockRules(4); + + (emergencyRules[0] as RuleMocker).returnValue = new Recommendation("emergencyrule1", 320, 1); + (emergencyRules[1] as RuleMocker).returnValue = new Recommendation("emergencyrule2", 220, 1); + + //call the algorithm run + + netStream.dispatchEvent(new HTTPStreamingEvent(HTTPStreamingEvent.RUN_ALGORITHM)); + + //check the ideal zero-time switch result + assertEquals(0, switcher.lastSwitchIndex); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(150,true); + + } + + [Test] + public function testGetNewIndexForUnsureEmergencyRule():void + { + createSwitchManager3Rulesand2EmergencyRules(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", 420, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 410, 1); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 400, 1); + + + (emergencyRules[0] as RuleMocker).returnValue = new Recommendation("emergencyrule1", 320, 0.8); + (emergencyRules[1] as RuleMocker).returnValue = new Recommendation("emergencyrule2", 220 ,0.6); + //should go to 350 + //call the algorithm run + + netStream.dispatchEvent(new HTTPStreamingEvent(HTTPStreamingEvent.RUN_ALGORITHM)); + + //check the ideal zero-time switch result + assertEquals(2, switcher.lastSwitchIndex); + + //simmulate switch in metric + //the value should be around the declared bitrate + mockSwitchTo(350,true); + } + + + /** + * Tests the initial value, more will be on integration tests + **/ + [Test] + public function testGetCurrentIndex():void + { + createSwitchManager1Rule(); + assertEquals(0, switchManager.currentIndex); + } + + [Test] + public function testGetMetricRepository():void + { + createSwitchManager1Rule(); + assertTrue(switchManager.metricRepository is MetricRepository); + } + + [Test] + public function testGetCurrentReliability():void + { + createSwitchManager1Rule(); + assertTrue(isNaN(switchManager.getCurrentReliability(0))); + } + + [Test] + public function testAutoSwitch():void + { + //full test will be done in integration suite + createSwitchManager1Rule(); + assertTrue( switchManager.autoSwitch); + + switchManager.autoSwitch = false; + assertFalse(switchManager.autoSwitch); + + + switchManager.autoSwitch = true; + assertTrue( switchManager.autoSwitch); + } + + + /** + * Tests setting a maxallowedindex + * No negative tests, nothing is enforced + */ + [Test] + public function testSetMaxAllowedIndex():void + { + createSwitchManager1Rule(); + assertEquals(int.MAX_VALUE, switchManager.maxAllowedIndex); + + switchManager.maxAllowedIndex = 4; + assertEquals(4, switchManager.maxAllowedIndex); + + } + + [Test] + public function testSwitchTo():void + { + createSwitchManager1Rule(); + switchManager.autoSwitch = false; + switchManager.switchTo(3); + + assertEquals(3, (switcher as NetStreamSwitcherMocker).lastSwitchIndex); + } + + [Test(expects = "flash.errors.IllegalOperationError")] + public function testSwitchToInAutoSwitchMode():void + { + createSwitchManager1Rule(); + switchManager.switchTo(3); + } + + + [Test] + public function testGetNewIndexForDownSwitchLimit():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(1); + mockRules(2); + mockRules(3); + mockRules(4); + //real test + mockRules(0,2); + + } + + [Test] + public function testGetNewIndexForUpSwitchLimit():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(4, 1); + + } + + [Test] + public function testGetNewIndexForDownSwitchLimitAndUnreliable():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + switchManager.maxUpSwitchLimit = 10; + + mockRules(1); + mockRules(2); + mockEmergencyRules(1); + mockRules(3); + mockRules(4); + //real test + mockRules(0, 3); + + } + + [Test] + public function testGetNewIndexForUpSwitchLimitAndUnreliable():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(1); + mockRules(2); + mockRules(3); + mockEmergencyRules(2); + mockRules(4, 2); + + } + + //this might overlap with another test + [Test] + public function testGetNewIndexForUpSwitchLimitAndUnreliableModifiedLimit():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + switchManager.maxUpSwitchLimit = 2; + + mockRules(1); + mockRules(2); + mockRules(3); + mockRules(4); + mockEmergencyRules(2); + mockRules(4, 3); + } + + + [Test] + public function testGetNewIndexForUpSwitchLimitAndNegativeMaxUpSwitchLimit():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(-1,2); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(4); + } + + [Test] + public function testGetNewIndexForDownSwitchLimitAndNegativeMaxDownSwitchLimit():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(1,-1); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(1); + mockRules(2); + mockRules(3); + mockRules(4); + + mockRules(0); + } + + [Test] + public function testGetNewIndexForSwitchLimitAndNegativeMaxSwitchLimits():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(-1,-1); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(4); + + mockRules(0); + } + + [Test] + public function testGetNewIndexForUpSwitchEmergency():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockEmergencyRules(4); + } + + [Test] + public function testGetNewIndexForDownSwitchEmergency():void + { + createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(); + availableQualityMetric.internalValue = qualityLevels; + availableQualityMetric.returnValid = true; + + mockRules(1); + mockRules(2); + mockRules(3); + mockRules(4); + + mockEmergencyRules(0); + } + + + + private function createSwitchManager1Rule():void + { + var ruleWeights:Vector. = generateWeights(0.6); + + rules = new Vector.(); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + dsResource.streamItems = new Vector.(); + for (var i:uint = 0; i < 5; i++) + { + var streamItem:DynamicStreamingItem = new DynamicStreamingItem("stream" + i, 150 + i * 100); + dsResource.streamItems.push(streamItem); + } + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 0.91, 6, 16, 0.9, uint.MAX_VALUE, uint.MAX_VALUE); + + initMetrics(); + + } + + private function createSwitchManager3Rules():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, null, true, rules, ruleWeights, 0.85, 5, 15, 0.9, uint.MAX_VALUE, uint.MAX_VALUE); + + initMetrics(); + } + + + private function createSwitchManager3Rulesand2EmergencyRules():void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + emergencyRules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + emergencyRules.push( new RuleMocker(new Recommendation("emergencyrule1", 50, 0))); + emergencyRules.push( new RuleMocker(new Recommendation("emergencyrule2", 60, 0))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, emergencyRules, true, rules, ruleWeights, 0.9, 5, 15, 0.9, uint.MAX_VALUE, uint.MAX_VALUE); + + initMetrics(); + } + + private function createSwitchManager3Rulesand2EmergencyRulesAndSwitchLimit(maxUp:int = 1, maxDown:int = 2):void + { + var ruleWeights:Vector. = generateWeights(0.7, 0.2, 0.1); + + rules = new Vector.(); + emergencyRules = new Vector.(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource("http://example.com/vod"); + + rules.push( new RuleMocker(new Recommendation("rule1", 500, 1))); + rules.push( new RuleMocker(new Recommendation("rule2", 600, 1))); + rules.push( new RuleMocker(new Recommendation("rule3", 700, 1))); + + emergencyRules.push( new RuleMocker(new Recommendation("emergencyrule1", 50, 0))); + emergencyRules.push( new RuleMocker(new Recommendation("emergencyrule2", 60, 0))); + + switcher = new NetStreamSwitcherMocker(netStream, dsResource); + + switchManager = new DefaultHTTPStreamingSwitchManager(netStream, switcher, metricRepository, emergencyRules, true, rules, ruleWeights, 0.9, 5, 15, 0.9, maxUp, maxDown); + + initMetrics(); + } + + private function initMetrics():void + { + availableQualityMetric = metricRepository.getMetric(MetricType.AVAILABLE_QUALITY_LEVELS) as AvailableQualityLevelsMetricMocker; + actualBitrateMetric = metricRepository.getMetric(MetricType.ACTUAL_BITRATE, 10) as ActualBitrateMetricMocker; + + availableQualityMetric.returnValid = true; + availableQualityMetric.internalValue = qualityLevels; + + mockSwitchTo(150,true); + } + + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:uint = 0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + private function mockSwitchTo(value:Number, valid:Boolean = true):void + { + //simmulate switch in metric and switcher + //the value should be around the declared bitrate + //qos needs to be updated to get the non-cached value + actualBitrateMetric.internalValue = value; + actualBitrateMetric.returnValid = valid; + addQoSInfo(generateQoSInfo(mockTimestamp++, 150, 250, 350, 450, 550)); + (switcher as NetStreamSwitcherMocker).actualIndex = (value - 150) / 100; + } + + private function mockRules(index:int, targetIndex:int = -1):void + { + if (targetIndex==-1) + targetIndex=index; + var bitrate:Number = 150 + 100*index + 80; + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", bitrate, 1); + (rules[1] as RuleMocker).returnValue = new Recommendation("rule2", 510, 0); + (rules[2] as RuleMocker).returnValue = new Recommendation("rule3", 500, 0); + + //initiate and check if the correct switch is done + netStream.dispatchEvent(new HTTPStreamingEvent(HTTPStreamingEvent.RUN_ALGORITHM)); + + var newBitrate:Number = 150 + 100 * targetIndex + 80; + //check the ideal zero-time switch result + assertEquals(targetIndex, switcher.lastSwitchIndex); + + //simulate switch behind the scenes; + mockSwitchTo(newBitrate, true); + + //clear emergency rules for a possible new switch + (rules[0] as RuleMocker).returnValue = new Recommendation("rule1", newBitrate, 0); + } + + private function mockEmergencyRules(index:int, targetIndex:int = -1):void + { + if (targetIndex==-1) + targetIndex=index; + var bitrate:Number = 150 + 100*index + 80; + (emergencyRules[0] as RuleMocker).returnValue = new Recommendation("emergencyRule1", bitrate, 1); + (emergencyRules[1] as RuleMocker).returnValue = new Recommendation("emergencyRule2", bitrate, 0); + //initiate and check if the correct switch is done + netStream.dispatchEvent(new HTTPStreamingEvent(HTTPStreamingEvent.RUN_ALGORITHM)); + //check the ideal zero-time switch result + assertEquals(targetIndex, switcher.lastSwitchIndex); + + //simulate switch behind the scenes; + + var newBitrate:Number = 150 + 100 * targetIndex + 80; + + mockSwitchTo(newBitrate, true); + //clear emergency rules for a possible new switch + (emergencyRules[0] as RuleMocker).returnValue = new Recommendation("emergencyRule1", newBitrate, 0); + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, ... qualityLevels):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint = 0; i< qualityLevels.length; i++) + { + v[i] = new QualityLevel( i, qualityLevels[i], "test" + qualityLevels[i] ); + } + return (new QoSInfo(timestamp, timestamp+5678, v, 0, 0, new FragmentDetails(14000, 4000, 568, 2))); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + private var metricFactory:MetricFactory; + private var metricRepository:MetricRepository; + private var switchManager:DefaultHTTPStreamingSwitchManager; + private var switcher:NetStreamSwitcherMocker; + private var rules:Vector.; + private var emergencyRules:Vector.; + + + private var availableQualityMetric:AvailableQualityLevelsMetricMocker; + private var actualBitrateMetric:ActualBitrateMetricMocker; + + private var qualityLevels:Vector.; + + private var mockTimestamp:int = 0; + + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/drm/TestDRMServices.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/drm/TestDRMServices.as new file mode 100644 index 0000000..8bd3003 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/drm/TestDRMServices.as @@ -0,0 +1,91 @@ +/***************************************************** + * + * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems + * Incorporated. All Rights Reserved. + * + * Contributor(s): Akamai Technologies + * + *****************************************************/ +package org.osmf.net.drm +{ + import flash.utils.ByteArray; + + import flexunit.framework.Assert; + + public class TestDRMServices + { + [Test(description="Using a null or an empty token")] + public function convertEmptyTokens():void + { + CONFIG::FLASH_10_1 + { + var token:ByteArray = null; + + token = DRMServices.convertToken(null); + Assert.assertEquals(token, null); + + token = DRMServices.convertToken(""); + Assert.assertEquals(token, null); + } + } + + [Test(description="Using a byte array token. Conversion shouldn't happen.")] + public function convertByteArrayTokens():void + { + CONFIG::FLASH_10_1 + { + var token:ByteArray = null; + + var originalToken:ByteArray = new ByteArray(); + token = DRMServices.convertToken(originalToken); + Assert.assertEquals(token, originalToken); + + originalToken.writeUTFBytes(DEFAULT_TOKEN_DATA); + token = DRMServices.convertToken(originalToken); + Assert.assertEquals(token, originalToken); + } + } + + [Test(description="Using a string as token. The string content should be serialized as a byte array.")] + public function convertStringToken():void + { + CONFIG::FLASH_10_1 + { + var token:ByteArray = null; + + token = DRMServices.convertToken(DEFAULT_TOKEN_DATA); + Assert.assertNotNull(token); + Assert.assertEquals(token.bytesAvailable, DEFAULT_TOKEN_DATA_LEN); + Assert.assertEquals(token.length, DEFAULT_TOKEN_DATA_LEN); + Assert.assertEquals(token.toString(), DEFAULT_TOKEN_DATA); + + token = DRMServices.convertToken(LONGER_TOKEN_DATA); + Assert.assertNotNull(token); + Assert.assertEquals(token.bytesAvailable, LONGER_TOKEN_DATA_LEN); + Assert.assertEquals(token.length, LONGER_TOKEN_DATA_LEN); + Assert.assertEquals(token.toString(), LONGER_TOKEN_DATA); + } + } + + /// Internals + private static const DEFAULT_TOKEN_DATA:String = "1234"; + private static const DEFAULT_TOKEN_DATA_LEN:int = 4; + private static const LONGER_TOKEN_DATA:String = "0123456789"; + private static const LONGER_TOKEN_DATA_LEN:int = 10; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/ActualBitrateMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/ActualBitrateMetricMocker.as new file mode 100644 index 0000000..5d1ddac --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/ActualBitrateMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class ActualBitrateMetricMocker extends ActualBitrateMetric + { + public function ActualBitrateMetricMocker(qosInfoHistory:QoSInfoHistory, maxFragments:uint = 5) + { + super(qosInfoHistory, maxFragments); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Number + { + return _internalValue; + } + + public function set internalValue(value:Number):void + { + _internalValue = value; + } + + private var _internalValue:Number=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/AvailableQualityLevelsMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/AvailableQualityLevelsMetricMocker.as new file mode 100644 index 0000000..27782c3 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/AvailableQualityLevelsMetricMocker.as @@ -0,0 +1,72 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class AvailableQualityLevelsMetricMocker extends AvailableQualityLevelsMetric + { + public function AvailableQualityLevelsMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Vector. + { + return _internalValue; + } + + public function set internalValue(value:Vector.):void + { + _internalValue = value; + } + + private var _internalValue:Vector.=null; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BandwidthMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BandwidthMetricMocker.as new file mode 100644 index 0000000..5bbebfb --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BandwidthMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class BandwidthMetricMocker extends BandwidthMetric + { + public function BandwidthMetricMocker(qosInfoHistory:QoSInfoHistory, weights:Vector.) + { + super(qosInfoHistory, weights); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Number + { + return _internalValue; + } + + public function set internalValue(value:Number):void + { + _internalValue = value; + } + + private var _internalValue:Number=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferFragmentsMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferFragmentsMetricMocker.as new file mode 100644 index 0000000..dc8bcc8 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferFragmentsMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class BufferFragmentsMetricMocker extends BufferFragmentsMetric + { + public function BufferFragmentsMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Number + { + return _internalValue; + } + + public function set internalValue(value:Number):void + { + _internalValue = value; + } + + private var _internalValue:Number=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferLengthMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferLengthMetricMocker.as new file mode 100644 index 0000000..7201f85 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferLengthMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class BufferLengthMetricMocker extends BufferLengthMetric + { + public function BufferLengthMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Number + { + return _internalValue; + } + + public function set internalValue(value:Number):void + { + _internalValue = value; + } + + private var _internalValue:Number=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferOccupationRatioMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferOccupationRatioMetricMocker.as new file mode 100644 index 0000000..87ee1fc --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/BufferOccupationRatioMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class BufferOccupationRatioMetricMocker extends BufferOccupationRatioMetric + { + public function BufferOccupationRatioMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Number + { + return _internalValue; + } + + public function set internalValue(value:Number):void + { + _internalValue = value; + } + + private var _internalValue:Number=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/CurrentStatusMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/CurrentStatusMetricMocker.as new file mode 100644 index 0000000..21d3732 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/CurrentStatusMetricMocker.as @@ -0,0 +1,73 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class CurrentStatusMetricMocker extends CurrentStatusMetric + { + public function CurrentStatusMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Vector. + { + return _internalValue; + } + + public function set internalValue(value:Vector.):void + { + _internalValue = value; + } + + private var _internalValue:Vector.=null; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/DefaultMetricFactoryMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/DefaultMetricFactoryMocker.as new file mode 100644 index 0000000..2a8940e --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/DefaultMetricFactoryMocker.as @@ -0,0 +1,185 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + /** + * DefaultMetricFactory is the default implementation of the MetricFactory. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public class DefaultMetricFactoryMocker extends MetricFactory + { + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function DefaultMetricFactoryMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + + init(); + } + + private function init():void + { + addItem + ( new MetricFactoryItem + ( MetricType.ACTUAL_BITRATE + , function(qosInfoHistory:QoSInfoHistory, maxFragments:uint = 5):MetricBase + { + return new ActualBitrateMetricMocker(qosInfoHistory, maxFragments); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.FRAGMENT_COUNT + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new FragmentCountMetricMocker(qosInfoHistory); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.AVAILABLE_QUALITY_LEVELS + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new AvailableQualityLevelsMetricMocker(qosInfoHistory); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.CURRENT_STATUS + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new CurrentStatusMetricMocker(qosInfoHistory); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.BANDWIDTH + , function(qosInfoHistory:QoSInfoHistory, weights:Vector.):MetricBase + { + return new BandwidthMetricMocker(qosInfoHistory, weights); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.FPS + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new FPSMetricMocker(qosInfoHistory); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.DROPPED_FPS + , function(qosInfoHistory:QoSInfoHistory, desiredSampleLength:Number = 10):MetricBase + { + return new DroppedFPSMetricMocker(qosInfoHistory, desiredSampleLength); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.BUFFER_OCCUPATION_RATIO + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new BufferOccupationRatioMetricMocker(qosInfoHistory); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.BUFFER_LENGTH + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new BufferLengthMetricMocker(qosInfoHistory); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.BUFFER_FRAGMENTS + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new BufferFragmentsMetricMocker(qosInfoHistory); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.EMPTY_BUFFER + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new EmptyBufferMetricMocker(qosInfoHistory); + } + ) + ); + + addItem + ( new MetricFactoryItem + ( MetricType.RECENT_SWITCH + , function(qosInfoHistory:QoSInfoHistory):MetricBase + { + return new RecentSwitchMetricMocker(qosInfoHistory); + } + ) + ); + } + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/DroppedFPSMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/DroppedFPSMetricMocker.as new file mode 100644 index 0000000..7b23053 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/DroppedFPSMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class DroppedFPSMetricMocker extends DroppedFPSMetric + { + public function DroppedFPSMetricMocker(qosInfoHistory:QoSInfoHistory, desiredSampleLength:Number = 10) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Number + { + return _internalValue; + } + + public function set internalValue(value:Number):void + { + _internalValue = value; + } + + private var _internalValue:Number=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/EmptyBufferMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/EmptyBufferMetricMocker.as new file mode 100644 index 0000000..5f60545 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/EmptyBufferMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class EmptyBufferMetricMocker extends EmptyBufferMetric + { + public function EmptyBufferMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Boolean + { + return _internalValue; + } + + public function set internalValue(value:Boolean):void + { + _internalValue = value; + } + + private var _internalValue:Boolean = false; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/FPSMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/FPSMetricMocker.as new file mode 100644 index 0000000..8aaec9f --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/FPSMetricMocker.as @@ -0,0 +1,73 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class FPSMetricMocker extends FPSMetric + { + public function FPSMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():Number + { + return _internalValue; + } + + public function set internalValue(value:Number):void + { + _internalValue = value; + } + + private var _internalValue:Number=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/FragmentCountMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/FragmentCountMetricMocker.as new file mode 100644 index 0000000..b1e1320 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/FragmentCountMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class FragmentCountMetricMocker extends FragmentCountMetric + { + public function FragmentCountMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():int + { + return _internalValue; + } + + public function set internalValue(value:int):void + { + _internalValue = value; + } + + private var _internalValue:int=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricComplexMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricComplexMocker.as new file mode 100644 index 0000000..24eb256 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricComplexMocker.as @@ -0,0 +1,55 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class MetricComplexMocker extends MetricBase + { + public function MetricComplexMocker(type:String, qosInfoHistory:QoSInfoHistory, returnValid:Boolean = true) + { + super(qosInfoHistory, type); + _returnValid = returnValid; + } + + override protected function getValueForced():MetricValue + { + //returns the last playhead time for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(++internalValue, _returnValid)); + + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + private var internalValue:int=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricFactoryMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricFactoryMocker.as new file mode 100644 index 0000000..b7e6530 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricFactoryMocker.as @@ -0,0 +1,45 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QoSInfoHistoryGenerator; + + public class MetricFactoryMocker extends MetricFactory + { + public function MetricFactoryMocker(qosInfoHistory:QoSInfoHistory = null) + { + super(qosInfoHistory); + } + + /** + * qosInfoHistory is ignored (so it can safely be null) + * the parameters should only contain one MetricValue object (the desired return value of the metric) + */ + override public function buildMetric(type:String, ...args):MetricBase + { + var returnValue:MetricValue = args[0]; + + return new MetricMocker(type, QoSInfoHistoryGenerator.generateSampleQoSInfoHistory(), returnValue); + } + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricMocker.as new file mode 100644 index 0000000..421ef7c --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricMocker.as @@ -0,0 +1,54 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class MetricMocker extends MetricBase + { + public function MetricMocker(type:String, qosInfoHistory:QoSInfoHistory, returnValue:MetricValue = null, v:Vector. = null, ... args) + { + super(qosInfoHistory, type); + _returnValue = returnValue; + _vector = v; + } + + public function set returnValue(value:MetricValue):void + { + _returnValue = value; + } + + override internal function getValue():MetricValue + { + return _returnValue; + } + + public function get vector():Vector. + { + return _vector; + } + + + private var _returnValue:MetricValue; + private var _vector:Vector.=null; + } +} \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/MockHTTPStreamQoSInfo.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricRepositoryMocker.as similarity index 62% rename from lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/MockHTTPStreamQoSInfo.as rename to lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricRepositoryMocker.as index c3afb41..d762966 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/MockHTTPStreamQoSInfo.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/MetricRepositoryMocker.as @@ -1,52 +1,42 @@ -/***************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - ***************************************************** - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - * - *****************************************************/ -package org.osmf.net -{ - [ExcludeClass] - - import org.osmf.net.httpstreaming.HTTPStreamQoSInfo; - - /** - * @private - * - * Mock implementation for HTTP Streaming QOS information. - */ - public class MockHTTPStreamQoSInfo extends HTTPStreamQoSInfo - { - /** - * Default constructor. - */ - public function MockHTTPStreamQoSInfo(desiredRatio:Number) - { - super(0,0,0); - _desiredRatio = desiredRatio; - } - - override public function get downloadRatio():Number - { - return _desiredRatio; - } - - /// Internals - private var _desiredRatio:Number = 0; - } +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistoryGenerator; + + public class MetricRepositoryMocker extends MetricRepository + { + public function MetricRepositoryMocker(metricFactory:MetricFactory) + { + super(metricFactory); + } + + /** + * Second parameter should be the desired return value of the metric (a MetricValue object) + */ + override public function getMetric(type:String, ...parameters):MetricBase + { + var returnValue:MetricValue = parameters[0]; + return new MetricMocker(type, QoSInfoHistoryGenerator.generateSampleQoSInfoHistory(), returnValue); + } + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/RecentSwitchMetricMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/RecentSwitchMetricMocker.as new file mode 100644 index 0000000..88ac5ea --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/RecentSwitchMetricMocker.as @@ -0,0 +1,71 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import org.osmf.net.qos.QoSInfoHistory; + + public class RecentSwitchMetricMocker extends RecentSwitchMetric + { + public function RecentSwitchMetricMocker(qosInfoHistory:QoSInfoHistory) + { + super(qosInfoHistory); + _internalValue=undefined; + _returnValid=false; + } + + override protected function getValueForced():MetricValue + { + //returns the internal value for testing reasons + //sets the validity to valid on invalid + return(new MetricValue(_internalValue, _returnValid)); + + } + + override internal function getValue():MetricValue + { + return getValueForced(); + } + + public function get returnValid():Boolean + { + return _returnValid; + } + + public function set returnValid(value:Boolean):void + { + _returnValid = value; + } + + public function get internalValue():int + { + return _internalValue; + } + + public function set internalValue(value:int):void + { + _internalValue = value; + } + + private var _internalValue:int=0; + private var _returnValid:Boolean; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestActualBitrateMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestActualBitrateMetric.as new file mode 100644 index 0000000..8818c00 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestActualBitrateMetric.as @@ -0,0 +1,194 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestActualBitrateMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + + [Test] + public function testActualBitrateMetric():void + { + metric = new ActualBitrateMetric(qosInfoHistory, 5); + + assertEquals(MetricType.ACTUAL_BITRATE, metric.type); + assertEquals(5, metric.maxFragments); + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + + [Test(expects="ArgumentError")] + public function testActualBitrateMetricZeroFragments():void + { + metric = new ActualBitrateMetric(qosInfoHistory, 0); + } + + + [Test] + public function testGetValueForMoreFragmentsNoSimilarFragmentsOutside():void + { + metric = new ActualBitrateMetric(qosInfoHistory, 5); + assertEquals(MetricType.ACTUAL_BITRATE, metric.type); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 1))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500000, 4040, 6001, 1))); + addQoSInfo(generateQoSInfo(4444, 1, new FragmentDetails(4600000, 4030, 8001, 0))); + addQoSInfo(generateQoSInfo(5555, 0, new FragmentDetails(5400000, 4050, 3001, 1))); + addQoSInfo(generateQoSInfo(6666, 1, new FragmentDetails(3200000, 4070, 5001, 2))); + + + var metricValue:MetricValue = metric.value; + + assertEquals((2400000+3500000+5400000) / (4020+4040+4050)*8/1000, metricValue.value); + assertTrue(metricValue.valid); + } + + [Test] + public function testGetValueForMoreFragments():void + { + metric = new ActualBitrateMetric(qosInfoHistory, 5); + assertEquals(MetricType.ACTUAL_BITRATE, metric.type); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 1))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500000, 4040, 6001, 1))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500001, 4041, 6001, 1))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500002, 4042, 6001, 1))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500003, 4043, 6001, 1))); + addQoSInfo(generateQoSInfo(4444, 1, new FragmentDetails(4600000, 4030, 8001, 0))); + addQoSInfo(generateQoSInfo(5555, 0, new FragmentDetails(5400000, 4050, 3001, 1))); + addQoSInfo(generateQoSInfo(6666, 1, new FragmentDetails(3200000, 4070, 5001, 2))); + + + var metricValue:MetricValue = metric.value; + + assertEquals((3500002+3500003+5400000) / (4042+4043+4050)*8/1000, metricValue.value); + assertTrue(metricValue.valid); + } + + [Test] + public function testGetValueForLessFragmentsAndShortHistory():void + { + metric = new ActualBitrateMetric(qosInfoHistory, 5); + assertEquals(MetricType.ACTUAL_BITRATE, metric.type); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 1))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500000, 4040, 6001, 1))); + + + var metricValue:MetricValue = metric.value; + + assertEquals((2400000+3500000) / (4020+4040)*8.0/1000, metricValue.value); + assertTrue(metricValue.valid); + } + + [Test] + public function testGetValueForIndexNotFound():void + { + metric = new ActualBitrateMetric(qosInfoHistory, 5); + assertEquals(MetricType.ACTUAL_BITRATE, metric.type); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 1))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500000, 4040, 6001, 1))); + addQoSInfo(generateQoSInfo(4444, 1, new FragmentDetails(4600000, 4030, 8001, 0))); + addQoSInfo(generateQoSInfo(5555, 0, new FragmentDetails(5400000, 4050, 3001, 1))); + addQoSInfo(generateQoSInfo(6666, 4, new FragmentDetails(3200000, 4070, 5001, 2))); + + + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, currentIndex:Number, fragmentDetails:FragmentDetails):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 3; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678+timestamp, v, currentIndex, currentIndex, fragmentDetails)); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:ActualBitrateMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestAvailableQualityLevelsMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestAvailableQualityLevelsMetric.as new file mode 100644 index 0000000..41e8dfe --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestAvailableQualityLevelsMetric.as @@ -0,0 +1,155 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestAvailableQualityLevelsMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testValueWhenQoSInfoHistoryIsEmpty():void + { + metric=new AvailableQualityLevelsMetric(qosInfoHistory); + assertEquals(MetricType.AVAILABLE_QUALITY_LEVELS, metric.type); + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + } + + [Test] + public function testValueWhenQoSInfoHistoryIsPopulated():void + { + metric=new AvailableQualityLevelsMetric(qosInfoHistory); + assertEquals(MetricType.AVAILABLE_QUALITY_LEVELS, metric.type); + + var metricValue:MetricValue; + metricValue = metric.value; + + //check initial value + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(1111, 150, 250, 350)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + + var v:Vector. = metricValue.value as Vector.; + assertEquals(3, v.length); + + assertEquals(150, v[0].bitrate); + assertEquals(250, v[1].bitrate); + assertEquals(350, v[2].bitrate); + + assertEquals("test150", v[0].streamName); + assertEquals("test250", v[1].streamName); + assertEquals("test350", v[2].streamName); + + assertEquals(0, v[0].index); + assertEquals(1, v[1].index); + assertEquals(2, v[2].index); + + //check the latest value + addQoSInfo(generateQoSInfo(2222, 151, 251, 351)); + + metricValue = metric.value; + + v = metricValue.value as Vector.; + assertEquals(3, v.length); + + assertEquals(151, v[0].bitrate); + assertEquals(251, v[1].bitrate); + assertEquals(351, v[2].bitrate); + + assertEquals("test151", v[0].streamName); + assertEquals("test251", v[1].streamName); + assertEquals("test351", v[2].streamName); + + assertEquals(0, v[0].index); + assertEquals(1, v[1].index); + assertEquals(2, v[2].index); + } + + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, ... qualityLevels):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< qualityLevels.length; i++) + { + v[i] = new QualityLevel( i, qualityLevels[i], "test" + qualityLevels[i] ); + } + return (new QoSInfo(timestamp, 5678, v, 0, 0, new FragmentDetails(14000, 4000, 568, 2))); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:AvailableQualityLevelsMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBandwidthMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBandwidthMetric.as new file mode 100644 index 0000000..cc655d1 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBandwidthMetric.as @@ -0,0 +1,212 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestBandwidthMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream, 4); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testBandwidthMetricWhenQoSInfoHistoryIsEmpty():void + { + metric=new BandwidthMetric(qosInfoHistory, generateWeights(0.5, 0.5) ); + assertEquals(MetricType.BANDWIDTH, metric.type); + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + [Test(expects="ArgumentError")] + public function testBandwidthMetricWhenQoSInfoHistoryIsNull():void + { + metric=new BandwidthMetric(null, generateWeights(0.5, 0.5) ); + } + + [Test] + public function testBandwidthMetricWhenQoSInfoHistoryIsFilledWithMoreValues():void + { + metric=new BandwidthMetric(qosInfoHistory, generateWeights(0.6, 0.4) ); + assertEquals(MetricType.BANDWIDTH, metric.type); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 0))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500000, 4040, 6001, 1))); + + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals((3500000 / 6001.0 * 0.6 + 2400000 / 4001.0 * 0.4 ) / (0.6 + 0.4), metricValue.value); + assertTrue(metricValue.valid); + } + + [Test] + public function testBandwidthMetricWhenQoSInfoHistoryIsFilledWithLessValues():void + { + metric=new BandwidthMetric(qosInfoHistory, generateWeights(0.6, 0.4, 0.3) ); + assertEquals(MetricType.BANDWIDTH, metric.type); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 0))); + + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals( (2400000 / 4001.0 * 0.6 + 1400000 / 2001.0 * 0.4) / (0.6 + 0.4), metricValue.value); + assertTrue(metricValue.valid); + } + + [Test] + public function testBandwidthMetricWithZeroWeight():void + { + metric=new BandwidthMetric(qosInfoHistory, generateWeights(0.0, 0.4) ); + assertEquals(MetricType.BANDWIDTH, metric.type); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 0))); + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500000, 4040, 6001, 1))); + + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals((3500000 / 6001.0 * 0.0 + 2400000 / 4001.0 * 0.4 ) / (0.0 + 0.4), metricValue.value); + assertTrue(metricValue.valid); + } + + + [Test(expects="ArgumentError")] + public function testBandwidthMetricWithAllZeroWeight():void + { + metric=new BandwidthMetric(qosInfoHistory, generateWeights(0.0, 0.0) ); + + } + + [Test(expects="ArgumentError")] + public function testBandwidthMetricWithNegativeWeight():void + { + metric=new BandwidthMetric(qosInfoHistory, generateWeights(-1.0, 0.4) ); + } + + [Test(expects="ArgumentError")] + public function testBandwidthMetricWithNullWeight():void + { + metric=new BandwidthMetric(qosInfoHistory, null ); + } + + [Test] + public function testGet_weights():void + { + metric=new BandwidthMetric(qosInfoHistory, generateWeights(0.01, 0.4, 0.3) ); + var v:Vector. = metric.weights; + assertNotNull(v); + assertEquals(3, v.length); + assertEquals(0.01, v[0]); + assertEquals(0.4, v[1]); + assertEquals(0.3, v[2]); + } + + [Test] + public function testMetricGetType():void + { + metric=new BandwidthMetric(qosInfoHistory, generateWeights(1) ); + assertEquals(MetricType.BANDWIDTH, metric.type); + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, currentBitrate:Number, fragmentDetails:FragmentDetails):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 3; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678, v, currentBitrate, currentBitrate, fragmentDetails )); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + private var metric:BandwidthMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferFragmentsMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferFragmentsMetric.as new file mode 100644 index 0000000..ec375ad --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferFragmentsMetric.as @@ -0,0 +1,225 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ + +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestBufferFragmentsMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testBufferFragmentsMetricInit():void + { + metric = new BufferFragmentsMetric(qosInfoHistory); + + assertEquals(MetricType.BUFFER_FRAGMENTS, metric.type); + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + [Test] + public function testBufferFragmentsMetricGetValueBufferLessThanFragmentSum():void + { + metric = new BufferFragmentsMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_FRAGMENTS, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 8, 4, new FragmentDetails(300000, 4.1 , 2, 0, "streamname"))); + addQoSInfo(generateQoSInfo(2222, 9, 4, new FragmentDetails(300000, 3.9 , 2, 1, "streamname"))); + addQoSInfo(generateQoSInfo(3333, 9, 4, new FragmentDetails(300000, 4.2 , 2, 1, "streamname"))); + + metricValue = metric.value; + assertEquals(2, metricValue.value); + assertTrue(metricValue.valid); + + } + + [Test] + public function testBufferFragmentsMetricGetValueBufferLengthNegative():void + { + metric = new BufferFragmentsMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_FRAGMENTS, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 8, 4, new FragmentDetails(300000, 4.1 , 2, 0, "streamname"))); + addQoSInfo(generateQoSInfo(2222, 9, 4, new FragmentDetails(300000, 3.9 , 2, 1, "streamname"))); + addQoSInfo(generateQoSInfo(3333, -1, 4, new FragmentDetails(300000, 4.2 , 2, 1, "streamname"))); + + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + } + + [Test] + public function testBufferFragmentsMetricGetValueBufferLengthNaN():void + { + metric = new BufferFragmentsMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_FRAGMENTS, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 8, 4, new FragmentDetails(300000, 4.1 , 2, 0, "streamname"))); + addQoSInfo(generateQoSInfo(2222, 9, 4, new FragmentDetails(300000, 3.9 , 2, 1, "streamname"))); + addQoSInfo(generateQoSInfo(3333, NaN, 4, new FragmentDetails(300000, 4.2 , 2, 1, "streamname"))); + + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + + [Test] + public function testBufferFragmentsMetricGetValueBufferLengthZero():void + { + metric = new BufferFragmentsMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_FRAGMENTS, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 8, 4, new FragmentDetails(300000, 4.1 , 2, 0, "streamname"))); + addQoSInfo(generateQoSInfo(2222, 9, 4, new FragmentDetails(300000, 3.9 , 2, 1, "streamname"))); + addQoSInfo(generateQoSInfo(3333, 0, 4, new FragmentDetails(300000, 4.2 , 2, 1, "streamname"))); + + metricValue = metric.value; + assertEquals(0, metricValue.value); + assertTrue(metricValue.valid); + } + + [Test] + public function testBufferFragmentsMetricGetValueBufferLessThanLastFragment():void + { + metric = new BufferFragmentsMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_FRAGMENTS, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 8, 4, new FragmentDetails(300000, 4.1 , 2, 0, "streamname"))); + addQoSInfo(generateQoSInfo(2222, 9, 4, new FragmentDetails(300000, 3.9 , 2, 1, "streamname"))); + addQoSInfo(generateQoSInfo(3333, 3, 4, new FragmentDetails(300000, 4.2 , 2, 1, "streamname"))); + + metricValue = metric.value; + assertEquals(0, metricValue.value); + assertTrue(metricValue.valid); + } + + [Test] + public function testBufferFragmentsMetricGetValueBufferEqualToSumOfFragments():void + { + metric = new BufferFragmentsMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_FRAGMENTS, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 8, 4, new FragmentDetails(300000, 4.1 , 2, 0, "streamname"))); + addQoSInfo(generateQoSInfo(2222, 9, 4, new FragmentDetails(300000, 3.9 , 2, 1, "streamname"))); + addQoSInfo(generateQoSInfo(3333, 4.2+3.9, 4, new FragmentDetails(300000, 4.2 , 2, 1, "streamname"))); + + metricValue = metric.value; + assertEquals(2, metricValue.value); + assertTrue(metricValue.valid); + } + + + [Test] + public function testBufferFragmentsMetricGetValueBufferLongerThanHistory():void + { + metric = new BufferFragmentsMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_FRAGMENTS, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 8, 4, new FragmentDetails(300000, 4.1 , 2, 0, "streamname"))); + addQoSInfo(generateQoSInfo(2222, 9, 4, new FragmentDetails(300000, 3.9 , 2, 1, "streamname"))); + addQoSInfo(generateQoSInfo(3333, 30, 4, new FragmentDetails(300000, 4.2 , 2, 1, "streamname"))); + + metricValue = metric.value; + assertEquals(3, metricValue.value); + assertTrue(metricValue.valid); + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, bufferLength:Number, bufferTime:Number, lastFragmentDetails:FragmentDetails):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678+timestamp, v, 2, 2, lastFragmentDetails, 25, null, null, bufferLength, bufferTime)); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:BufferFragmentsMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferLengthMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferLengthMetric.as new file mode 100644 index 0000000..381bb26 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferLengthMetric.as @@ -0,0 +1,132 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ + +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestBufferLengthMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testBufferLengthMetricInit():void + { + metric = new BufferLengthMetric(qosInfoHistory); + + assertEquals(MetricType.BUFFER_LENGTH, metric.type); + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + [Test] + public function testBufferLengthMetricGetValue():void + { + metric = new BufferLengthMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_LENGTH, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 3, 4)); + metricValue = metric.value; + assertEquals(3, metricValue.value); + assertTrue(metricValue.valid); + + addQoSInfo(generateQoSInfo(2222, -1, 4)); + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(3333, NaN, 4)); + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(4444, 0, 4)); + metricValue = metric.value; + assertEquals(0, metricValue.value); + assertTrue(metricValue.valid); + + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, bufferLength:Number, bufferTime:Number):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678+timestamp, v, 2, 2, null, 25, null, null, bufferLength, bufferTime)); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:BufferLengthMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferOccupationRatioMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferOccupationRatioMetric.as new file mode 100644 index 0000000..1c05865 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestBufferOccupationRatioMetric.as @@ -0,0 +1,147 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ + +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestBufferOccupationRatioMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testBufferOccupationRatioMetricInit():void + { + metric = new BufferOccupationRatioMetric(qosInfoHistory); + + assertEquals(MetricType.BUFFER_OCCUPATION_RATIO, metric.type); + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + [Test] + public function testBufferOccupationRatioMetricGetValue():void + { + metric = new BufferOccupationRatioMetric(qosInfoHistory); + assertEquals(MetricType.BUFFER_OCCUPATION_RATIO, metric.type); + + var metricValue:MetricValue; + + addQoSInfo(generateQoSInfo(1111, 3, 4)); + metricValue = metric.value; + assertEquals(3/4, metricValue.value); + assertTrue(metricValue.valid); + + addQoSInfo(generateQoSInfo(2222, -1, 4)); + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(3333, NaN, 4)); + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(4444, 0, 4)); + metricValue = metric.value; + assertEquals(0, metricValue.value); + assertTrue(metricValue.valid); + + addQoSInfo(generateQoSInfo(5555, 3, -1)); + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(6666, 3, NaN)); + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(7777, 3, 0)); + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, bufferLength:Number, bufferTime:Number):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678+timestamp, v, 2, 2, null, 25, null, null, bufferLength, bufferTime)); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:BufferOccupationRatioMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestCurrentStatusMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestCurrentStatusMetric.as new file mode 100644 index 0000000..c60a0e9 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestCurrentStatusMetric.as @@ -0,0 +1,134 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestCurrentStatusMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + + [Test] + public function testCurrentStatusMetric():void + { + metric = new CurrentStatusMetric(qosInfoHistory); + + assertEquals(MetricType.CURRENT_STATUS, metric.type); + + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + + [Test] + public function testCurrentStatusMetricQoSPopulated():void + { + metric = new CurrentStatusMetric(qosInfoHistory); + + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(1111, 4, 9)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + assertTrue(metricValue.value is Vector.); + assertEquals(4, metricValue.value[0]); + assertEquals(9, metricValue.value[1]); + + + //test for more than one value in qosinfohistory + addQoSInfo(generateQoSInfo(2222, 5, 10)); + + metricValue = metric.value; + + assertTrue(metricValue.valid); + assertTrue(metricValue.value is Vector.); + assertEquals(5, metricValue.value[0]); + assertEquals(10, metricValue.value[1]); + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, currentIndex:Number, actualIndex:Number):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint = 0; i< 3; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678+timestamp, v, currentIndex, actualIndex, null)); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:CurrentStatusMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestDefaultMetricFactory.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestDefaultMetricFactory.as new file mode 100644 index 0000000..087f2f0 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestDefaultMetricFactory.as @@ -0,0 +1,114 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.assertThat; + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertStrictlyEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.net.ABRTestUtils; + import org.osmf.net.qos.QoSInfoHistory; + + public class TestDefaultMetricFactory + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + var ns:NetStream = new NetStream(conn); + var qosInfoHistory:QoSInfoHistory = new QoSInfoHistory(ns); + factory = new DefaultMetricFactory(qosInfoHistory); + } + + [After] + public function tearDown():void + { + factory = null; + } + + [Test] + public function testBuildMetricsInit():void + { + assertEquals(12, factory.numItems); + assertEquals(12, factory.getItems().length); + + assertTrue(factory.buildMetric(MetricType.ACTUAL_BITRATE, 10) is ActualBitrateMetric); + + assertTrue(factory.buildMetric(MetricType.FRAGMENT_COUNT) is FragmentCountMetric); + + assertTrue(factory.buildMetric(MetricType.AVAILABLE_QUALITY_LEVELS) is AvailableQualityLevelsMetric); + + var weights:Vector. = new Vector.(); + weights.push(0.8); + weights.push(0.2); + assertTrue(factory.buildMetric(MetricType.BANDWIDTH, weights) is BandwidthMetric); + + assertTrue(factory.buildMetric(MetricType.FPS) is FPSMetric); + + assertTrue(factory.buildMetric(MetricType.DROPPED_FPS) is DroppedFPSMetric); + + assertTrue(factory.buildMetric(MetricType.CURRENT_STATUS) is CurrentStatusMetric); + + assertTrue(factory.buildMetric(MetricType.BUFFER_LENGTH) is BufferLengthMetric); + + assertTrue(factory.buildMetric(MetricType.BUFFER_OCCUPATION_RATIO) is BufferOccupationRatioMetric); + + assertTrue(factory.buildMetric(MetricType.BUFFER_FRAGMENTS) is BufferFragmentsMetric); + + assertTrue(factory.buildMetric(MetricType.EMPTY_BUFFER) is EmptyBufferMetric); + + assertTrue(factory.buildMetric(MetricType.RECENT_SWITCH) is RecentSwitchMetric); + } + + [Test] + public function testBuildActualBitrateMetric():void + { + var metric:ActualBitrateMetric = factory.buildMetric(MetricType.ACTUAL_BITRATE, 4) as ActualBitrateMetric; + + assertNotNull(metric); + assertEquals(metric.maxFragments, 4); + } + + [Test] + public function testBuildBandwidthMetric():void + { + var weights:Vector. = new Vector.(); + weights.push(4); + weights.push(3); + weights.push(1); + + var metric:BandwidthMetric = factory.buildMetric(MetricType.BANDWIDTH, weights) as BandwidthMetric; + + assertNotNull(metric); + assertTrue(ABRTestUtils.equalNumberVectors(metric.weights, weights)); + } + + private var factory:MetricFactory; + + private static const MAX_FRAGMENTS:Number = 10; + } +} diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestDroppedFPSMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestDroppedFPSMetric.as new file mode 100644 index 0000000..cfb0f26 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestDroppedFPSMetric.as @@ -0,0 +1,378 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.PlaybackDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestDroppedFPSMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testValueWhenQoSInfoHistoryIsEmpty():void + { + metric=new DroppedFPSMetric(qosInfoHistory); + assertEquals(MetricType.DROPPED_FPS, metric.type); + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + assertEquals(10, metric.desiredSampleLength); + + } + + + [Test(expects="ArgumentError")] + public function testDesiredSampleLengthNegativeValue():void + { + metric=new DroppedFPSMetric(qosInfoHistory, -1); + } + + [Test(expects="ArgumentError")] + public function testDesiredSampleLengthNaN():void + { + metric=new DroppedFPSMetric(qosInfoHistory, NaN); + } + + [Test] + public function testDesiredSampleLengthDifferentValue():void + { + metric=new DroppedFPSMetric(qosInfoHistory, 6.78); + assertEquals(MetricType.DROPPED_FPS, metric.type); + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + assertEquals(6.78, metric.desiredSampleLength); + + } + + [Test] + public function testValueWhenQoSInfoHistoryIsPopulated():void + { + metric=new DroppedFPSMetric(qosInfoHistory, 5); + assertEquals(MetricType.DROPPED_FPS, metric.type); + var timestamp:Number=1000; + + var metricValue:MetricValue; + metricValue = metric.value; + + //check initial value + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + //check one value + addQoSInfo(generateQoSInfo(timestamp++, 0, + 2, 7, + 0, 0, + 0, 0, + 0, 0, + 0, 0)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + assertEquals(7/2, metricValue.value); + + //check bad data + addQoSInfo(generateQoSInfo(timestamp++, 4, + 2, 7, + 0, 0, + 0, 0, + 0, 0, + 0, 0)); + + metricValue = metric.value; + assertFalse(metricValue.valid); + assertEquals(undefined, metricValue.value); + + + //check value when other streams have been played (0 and 1) + addQoSInfo(generateQoSInfo(timestamp++, 1, + 2, 7, + 3, 4, + 5, 40, + 7, 45, + 9, 50)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + assertEquals(4/3, metricValue.value); + + + //check that it sums 2 records, under the limit + addQoSInfo(generateQoSInfo(timestamp++, 1, + 2, 7, + 1, 5, + 5, 40, + 7, 45, + 9, 50)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + assertEquals((4+5)/(3+1), metricValue.value); + + //check that the limit stops the propagation + addQoSInfo(generateQoSInfo(timestamp++, 1, + 1, 7, + 2, 23, + 5, 40, + 7, 45, + 9, 50)); + + addQoSInfo(generateQoSInfo(timestamp++, 1, + 1, 7, + 3, 34, + 5, 40, + 7, 45, + 9, 50)); + + + metricValue = metric.value; + assertTrue(metricValue.valid); + assertEquals((23+34)/(2+3), metricValue.value); + + //check desiredSampleLength limit + addQoSInfo(generateQoSInfo(timestamp++, 1, + 2, 7, + 6, 13, + 5, 40, + 7, 45, + 9, 50)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + + assertEquals(13/6, metricValue.value); + + //check undefined + addQoSInfo(generateQoSInfo(timestamp++, 1, + 2, 7, + 6, 13, + 5, 40, + 7, 45, + 9, 50)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + + assertEquals(13/6, metricValue.value); + + } + + [Test] + public function testValueForShortIntervals():void + { + metric=new DroppedFPSMetric(qosInfoHistory, 5); + assertEquals(MetricType.DROPPED_FPS, metric.type); + var timestamp:Number=2000; + + var metricValue:MetricValue; + metricValue = metric.value; + + //check initial value + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + //check minimum MINIMUM_CONTINUOUS_PLAYBACK_DURATION = 1 + + addQoSInfo(generateQoSInfo(timestamp++, 0, + 0.99, 3, + 0, 0, + 0, 0, + 0, 0, + 0, 0)); + + metricValue = metric.value; + assertFalse(metricValue.valid); + assertEquals(undefined, metricValue.value); + + addQoSInfo(generateQoSInfo(timestamp++, 0, + 4, 3, + 0, 0, + 0, 0, + 0, 0, + 0, 0)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + assertEquals(3 / 4, metricValue.value); + + //check minimum MINIMUM_TOTAL_PLAYBACK_DURATION = 2 + addQoSInfo(generateQoSInfo(timestamp++, 4, + 2, 7, + 0, 0, + 0, 0, + 0, 0, + 1, 4)); + + metricValue = metric.value; + assertFalse(metricValue.valid); + assertEquals(undefined, metricValue.value); + + addQoSInfo(generateQoSInfo(timestamp++, 4, + 2, 7, + 0, 0, + 0, 0, + 0, 0, + 1, 5)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + assertEquals( (4 + 5) / 2, metricValue.value); + + } + + [Test] + public function testValueForNegativeDroppedFrameValue():void + { + metric=new DroppedFPSMetric(qosInfoHistory, 5); + assertEquals(MetricType.DROPPED_FPS, metric.type); + var timestamp:Number=2000; + + var metricValue:MetricValue; + metricValue = metric.value; + + //check initial value + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + //check minimum MINIMUM_CONTINUOUS_PLAYBACK_DURATION = 1 + + addQoSInfo(generateQoSInfo(timestamp++, 0, + 8, -3, + 0, 0, + 0, 0, + 0, 0, + 0, 0)); + + metricValue = metric.value; + assertFalse(metricValue.valid); + assertEquals(undefined, metricValue.value); + } + + [Test] + public function testValueForNegativeDurationValue():void + { + metric=new DroppedFPSMetric(qosInfoHistory, 5); + assertEquals(MetricType.DROPPED_FPS, metric.type); + var timestamp:Number=2000; + + var metricValue:MetricValue; + metricValue = metric.value; + + //check initial value + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + //check minimum MINIMUM_CONTINUOUS_PLAYBACK_DURATION = 1 + + addQoSInfo(generateQoSInfo(timestamp++, 0, + 8, 3, + 0, 0, + 0, 0, + 0, 0, + 0, 0)); + + metricValue = metric.value; + assertTrue(metricValue.valid); + assertEquals(3 / 8, metricValue.value); + + addQoSInfo(generateQoSInfo(timestamp++, 0, + -1, 4, + 0, 0, + 0, 0, + 0, 0, + 0, 0)); + + metricValue = metric.value; + assertFalse(metricValue.valid); + assertEquals(undefined, metricValue.value); + + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, currentIndex:int, ... playbackArgs):QoSInfo + { + var v:Vector. = new Vector.(); + var playbackDetails:Vector. = new Vector.; + var i:int; + for(i=0; i< playbackArgs.length; i+=2) + playbackDetails.push(new PlaybackDetails(i/2, playbackArgs[i], playbackArgs[i+1])); + + for(i=0; i< 5; i++) + { + v[i] = new QualityLevel( i, 150+100*i , "test" + (150+100*i) ); + } + return (new QoSInfo(timestamp, 5678, v, currentIndex, 0, new FragmentDetails(14000, 4000, 568, 2), 0, playbackDetails)); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:DroppedFPSMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestEmptyBufferInterruptionMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestEmptyBufferInterruptionMetric.as new file mode 100644 index 0000000..173aafa --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestEmptyBufferInterruptionMetric.as @@ -0,0 +1,131 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestEmptyBufferInterruptionMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream, 4); + } + + [After] + public function tearDown():void + { + netStream = null; + qosInfoHistory = null; + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testEmptyBufferInterruptionMetricWhenQoSIsEmpty():void + { + metric=new EmptyBufferMetric(qosInfoHistory); + assertEquals(MetricType.EMPTY_BUFFER, metric.type); + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + + [Test] + public function testEmptyBufferInterruptionMetricForQoSPresent():void + { + metric=new EmptyBufferMetric(qosInfoHistory); + assertEquals(MetricType.EMPTY_BUFFER, metric.type); + + addQoSInfo(generateQoSInfo(1111, false)); + //check 1st value + var metricValue:MetricValue; + metricValue = metric.value; + assertFalse(metricValue.value); + assertTrue(metricValue.valid); + + addQoSInfo(generateQoSInfo(2222, true)); + //check 2nd value + metricValue = metric.value; + assertTrue(metricValue.value); + assertTrue(metricValue.valid); + + addQoSInfo(generateQoSInfo(3333, false)); + //check another value + metricValue = metric.value; + assertFalse(metricValue.value); + assertTrue(metricValue.valid); + + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, bufferEmpty:Boolean):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 3; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678, v, 2, 2, null, NaN, null, null, NaN, NaN, bufferEmpty )); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + + private var metric:EmptyBufferMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestFPSMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestFPSMetric.as new file mode 100644 index 0000000..79054d5 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestFPSMetric.as @@ -0,0 +1,133 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestFPSMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream, 4); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testMetricGetType():void + { + metric=new FPSMetric(qosInfoHistory); + + //check first response when history is empty + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(MetricType.FPS, metric.type); + assertEquals(false, metricValue.valid); + assertEquals(undefined, metricValue.value); + + //check response for NaN + addQoSInfo(generateQoSInfo(1111, NaN)); + metricValue = metric.value; + assertEquals(MetricType.FPS, metric.type); + assertEquals(false, metricValue.valid); + assertEquals(undefined, metricValue.value); + + //check response for 0 + addQoSInfo(generateQoSInfo(2222, 0)); + metricValue = metric.value; + assertEquals(MetricType.FPS, metric.type); + assertEquals(false, metricValue.valid); + assertEquals(undefined, metricValue.value); + + //check response for valid value + addQoSInfo(generateQoSInfo(3333, 23.9)); + metricValue = metric.value; + assertEquals(MetricType.FPS, metric.type); + assertEquals(true, metricValue.valid); + assertEquals(23.9, metricValue.value); + + //check that it gets the latest + addQoSInfo(generateQoSInfo(4444, 25.1)); + metricValue = metric.value; + assertEquals(MetricType.FPS, metric.type); + assertEquals(true, metricValue.valid); + assertEquals(25.1, metricValue.value); + + } + + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, fps:Number):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 3; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678, v,1, 2, new FragmentDetails(400000, 4, 3, 0, "test"), fps )); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + + private var metric:FPSMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestFragmentCountMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestFragmentCountMetric.as new file mode 100644 index 0000000..9343f34 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestFragmentCountMetric.as @@ -0,0 +1,148 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flashx.textLayout.debug.assert; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestFragmentCountMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testFragmentCountMetricEmptyQoSInfoHistory():void + { + metric=new FragmentCountMetric(qosInfoHistory); + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + } + + [Test] + public function testFragmentCountMetricPopulatedQoSInfoHistory():void + { + metric=new FragmentCountMetric(qosInfoHistory); + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(3333, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(4444, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + addQoSInfo(generateQoSInfo(5555, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + + metricValue = metric.value; + assertEquals(5, metricValue.value); + assertTrue(metricValue.valid); + + } + + + [Test(expects="ArgumentError")] + public function testFragmentCountMetricNullQoSInfoHistory():void + { + metric=new FragmentCountMetric(null); + } + + [Test] + public function testMetricGetType():void + { + metric=new FragmentCountMetric(qosInfoHistory ); + assertEquals(MetricType.FRAGMENT_COUNT, metric.type); + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, currentBitrate:Number, fragmentDetails:FragmentDetails):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 3; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678, v, currentBitrate, currentBitrate, fragmentDetails )); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + private var metric:FragmentCountMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricBase.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricBase.as new file mode 100644 index 0000000..93127d8 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricBase.as @@ -0,0 +1,175 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertStrictlyEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestMetricBase + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testValueWhenQoSInfoHistoryIsEmpty():void + { + metric = new MetricComplexMocker("test", qosInfoHistory); + assertEquals("test", metric.type); + + //check initial value + var metricValue:MetricValue; + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + } + + [Test(expects="ArgumentError")] + public function testMetricInitWithNullQoSInfoHistory():void + { + metric = new MetricComplexMocker("test", null); + } + + [Test] + public function testValueWhenQoSInfoHistoryIsPopulated():void + { + metric=new MetricComplexMocker("test", qosInfoHistory); + assertEquals("test", metric.type); + + var metricValue:MetricValue; + metricValue = metric.value; + + //check initial value + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + //add a new item in history, this will force refresh + addQoSInfo(generateQoSInfo(1111, 150, 250, 350)); + + metricValue = metric.value; + assertEquals(1,metricValue.value); + assertTrue(metricValue.valid); + + //add a new item in history, this will force refresh + addQoSInfo(generateQoSInfo(2222, 151, 251, 351)); + + metricValue = metric.value; + assertEquals(2,metricValue.value); + assertTrue(metricValue.valid); + + + //get the cached value, this will not force refresh + metricValue = metric.value; + assertEquals(2,metricValue.value); + assertTrue(metricValue.valid); + + } + + [Test] + public function testValueWhenQoSInfoHistoryIsPopulatedAndFlushed():void + { + //create and populate the metric + metric=new MetricComplexMocker("test", qosInfoHistory); + assertEquals("test", metric.type); + + addQoSInfo(generateQoSInfo(1111, 150, 250, 350)); + + var metricValue:MetricValue; + metricValue = metric.value; + + //check initial value + assertEquals(1, metricValue.value); + assertTrue(metricValue.valid); + + //add a new item in history, this will force refresh + addQoSInfo(generateQoSInfo(2222, 150, 250, 350)); + + metricValue = metric.value; + assertEquals(2, metricValue.value); + assertTrue(metricValue.valid); + + //flush QosInfoHistory + qosInfoHistory.flush(); + + //check value, should default to not defined + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, ... qualityLevels):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< qualityLevels.length; i++) + { + v[i] = new QualityLevel( i, qualityLevels[i], "test" + qualityLevels[i] ); + } + return (new QoSInfo(timestamp, 5678, v, 0, 0, new FragmentDetails(14000, 4000, 568, 2))); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:MetricComplexMocker; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricFactory.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricFactory.as new file mode 100644 index 0000000..8cee0f7 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricFactory.as @@ -0,0 +1,282 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertNull; + import org.flexunit.asserts.assertStrictlyEquals; + import org.flexunit.asserts.assertTrue; + import org.flexunit.internals.runners.statements.ExpectException; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QoSInfoHistoryGenerator; + + public class TestMetricFactory + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + var ns:NetStream = new NetStream(conn); + var qosInfoHistory:QoSInfoHistory = new QoSInfoHistory(ns); + factory = new MetricFactory(qosInfoHistory); + } + + [After] + public function tearDown():void + { + factory = null; + } + + [Test] + public function testAddItem():void + { + + //check initial conditions + assertEquals(factory.numItems, 0); + assertNotNull(factory.getItems()); + assertEquals(0,factory.getItems().length); + + // create a MetricFactoryItem + var item:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + + //checks the type of the item + assertEquals(METRIC_TYPE_1, item.type); + + // add the item + factory.addItem(item); + + // check that the item is the only one in the list + assertEquals(factory.numItems, 1); + assertEquals(factory.getItem(METRIC_TYPE_1), item); + } + + [Test] + public function testRemoveItem():void + { + // create a MetricFactoryItem + var item:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + + // add the item + factory.addItem(item); + + // remove the item + factory.removeItem(item); + + // check that the factory has no items + assertEquals(factory.numItems, 0); + assertNull(factory.getItem(METRIC_TYPE_1)); + } + + [Test] + public function testRemoveNonExistingItem():void + { + // create a MetricFactoryItem + var item:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + + var item2:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_3); + + // add the item + factory.addItem(item); + + // remove the item + factory.removeItem(item2); + + // check that the factory still has 1 item + assertEquals(factory.numItems, 1); + } + + + [Test(expects="ArgumentError")] + public function testRemoveNullItem():void + { + // create a MetricFactoryItem + var item:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + + // add the item + factory.addItem(item); + + // remove the item + factory.removeItem(null); + + } + + [Test(expects="ArgumentError")] + public function testAddNullItem():void + { + // add the item + factory.addItem(null); + } + + [Test] + public function testGetItemList():void + { + // create two items + var item1:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + var item2:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_2); + + // add them to the factory + factory.addItem(item1); + factory.addItem(item2); + + // check that the list contains them both + var itemList:Vector. = factory.getItems(); + + assertEquals(itemList.length, 2); + var item1Found:Boolean = false; + var item2Found:Boolean = false; + + for each (var item:MetricFactoryItem in itemList) + { + if (item == item1) + { + item1Found = true; + } + else if (item == item2) + { + item2Found = true; + } + } + + assertTrue(item1Found && item2Found); + } + + [Test] + public function testBuildMetricValid():void + { + // create two items + var item1:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + var item2:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_2); + + // add them to the factory + factory.addItem(item1); + factory.addItem(item2); + + var metric:MetricMocker = factory.buildMetric(METRIC_TYPE_1, null) as MetricMocker; + + assertEquals(metric.type, METRIC_TYPE_1); + } + + [Test] + public function testBuildMetricAddSimilarMetricTwice():void + { + // create two items + var item1:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + var item2:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + + // add them to the factory + factory.addItem(item1); + factory.addItem(item2); + + var metric:MetricMocker = factory.buildMetric(METRIC_TYPE_1, null) as MetricMocker; + + assertEquals(1,factory.numItems); + assertStrictlyEquals(item2,factory.getItem(METRIC_TYPE_1)); + + assertEquals(metric.type, METRIC_TYPE_1); + } + + [Test] + public function testBuildMetricAddSameMetricTwice():void + { + // create two items + var item1:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + + // add them to the factory + factory.addItem(item1); + factory.addItem(item1); + + assertEquals(1,factory.numItems); + var metric:MetricMocker = factory.buildMetric(METRIC_TYPE_1, null) as MetricMocker; + + assertEquals(metric.type, METRIC_TYPE_1); + } + + + [Test] + public function testGetItemByType():void + { + // create a MetricFactoryItem + var item:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + + // add the item + factory.addItem(item); + + // check that the item is the only one in the list + assertEquals(factory.numItems, 1); + assertEquals(factory.getItem(METRIC_TYPE_1), item); + + //check 2 negative tests + assertNull(factory.getItem(METRIC_TYPE_3)); + assertNull(factory.getItem(null)); + + } + + [Test(expects="org.osmf.events.MetricError")] + public function testBuildMetricInvalid():void + { + // create two items + var item1:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_1); + var item2:MetricFactoryItem = getMetricFactoryItem(METRIC_TYPE_2); + + // add them to the factory + factory.addItem(item1); + factory.addItem(item2); + + var metric:MetricMocker = factory.buildMetric(METRIC_TYPE_3, null) as MetricMocker; + } + + [Test(expects="org.osmf.events.MetricError")] + public function testBuildMetricNullType():void + { + + var metric:MetricMocker = factory.buildMetric(null, 4) as MetricMocker; + } + [Test(expects="org.osmf.events.MetricError")] + public function testBuildMetricEmptyType():void + { + + var metric:MetricMocker = factory.buildMetric("", 4) as MetricMocker; + } + + private function getMetricFactoryItem(type:String):MetricFactoryItem + { + return new MetricFactoryItem + ( type + , function(qosInfoHistory:QoSInfoHistory, ...args):MetricBase + { + return new MetricMocker(type, QoSInfoHistoryGenerator.generateSampleQoSInfoHistory()); + } + ); + } + + private var factory:MetricFactory; + + private static const METRIC_TYPE_1:String = "com.example.metrics.sample1"; + private static const METRIC_TYPE_2:String = "com.example.metrics.sample2"; + private static const METRIC_TYPE_3:String = "com.example.metrics.sample3"; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricFactoryItem.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricFactoryItem.as new file mode 100644 index 0000000..3f163e4 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricFactoryItem.as @@ -0,0 +1,93 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertStrictlyEquals; + import org.flexunit.asserts.assertTrue; + import org.flexunit.internals.runners.statements.ExpectException; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QoSInfoHistoryGenerator; + + public class TestMetricFactoryItem + { + [Before] + public function setUp():void + { + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testMetricFactoryItemGet():void + { + var f:Function = function(qosInfoHistory:QoSInfoHistory, ...args):MetricBase + { + return new MetricMocker(METRIC_TYPE_1, QoSInfoHistoryGenerator.generateEmptyQoSInfoHistory()); + }; + + metricFactoryItem = new MetricFactoryItem(METRIC_TYPE_1, f); + + assertEquals(METRIC_TYPE_1, metricFactoryItem.type); + assertStrictlyEquals(f, metricFactoryItem.metricCreationFunction); + + assertTrue(metricFactoryItem.metricCreationFunction(null) is MetricBase); + } + + + [Test(expects="ArgumentError")] + public function testMetricFactoryItemInitTypeNull():void + { + metricFactoryItem = new MetricFactoryItem(null, + function(qosInfoHistory:QoSInfoHistory, ...args):MetricBase + { + return new MetricMocker(METRIC_TYPE_1, qosInfoHistory); + }); + } + + [Test(expects="ArgumentError")] + public function testMetricFactoryItemInitFunctionNull():void + { + metricFactoryItem = new MetricFactoryItem(METRIC_TYPE_1,null); + } + + private var metricFactoryItem:MetricFactoryItem; + + private static const METRIC_TYPE_1:String = "com.example.metrics.sample1"; + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricRepository.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricRepository.as new file mode 100644 index 0000000..c522c7f --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricRepository.as @@ -0,0 +1,258 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.utils.getTimer; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertStrictlyEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.TimeEvent; + + public class TestMetricRepository + { + [Before] + public function setUp():void + { + metricRepository = new MetricRepository(new MetricFactoryMocker()); + + metric1Value = new MetricValue("metric1value", true); + metric2Value = new MetricValue("metric2value", true); + } + + [After] + public function tearDown():void + { + metricRepository = null; + } + + /** + * Tests that the getMetric function returns the desired metric (type and params) + */ + [Test] + public function testGetMetric():void + { + var metric:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value) as MetricMocker; + + assertNotNull(metric); + assertEquals(metric.type, METRIC_TYPE_1); + assertEquals(metric.value, metric1Value); + } + + /** + * Tests that the getMetric returns correct init error + */ + [Test(expects="ArgumentError")] + public function testInitMetricRepository():void + { + metricRepository = new MetricRepository(null); + } + + /** + * Tests that the same object is returned if we request the same metric type with the same params + * twice (no duplication of objects) + */ + [Test] + public function testGetMetricNoDuplication():void + { + //create complex parameter + var v:Vector. = new Vector.(); + v[0] = metric1Value; + v[1] = metric2Value; + + var metric1:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, v) as MetricMocker; + var metric1bis:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, v) as MetricMocker; + + assertNotNull(metric1); + assertNotNull(metric1bis); + assertStrictlyEquals(metric1, metric1bis); + } + + /** + * Tests that the same object is returned if we request the same metric type with the same params + * twice (no duplication of objects) + */ + [Test] + public function testGetMetricNoDuplicationDifferentObjects():void + { + //create complex parameter + var v:Vector. = new Vector.(); + v.push(metric1Value); + v.push(metric2Value); + var u:Vector. = new Vector.(); + u.push(metric1Value); + u.push(metric2Value); + + var metric1:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, v) as MetricMocker; + var metric1bis:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, u) as MetricMocker; + + assertNotNull(metric1); + assertNotNull(metric1bis); + assertStrictlyEquals(metric1, metric1bis); + } + + /** + * Tests that two different objects are returned if we request 2 metrics with the same + * type, but with different params + */ + [Test] + public function testGetMetricSameTypeDifferentParams():void + { + //create complex parameter + var v:Vector. = new Vector.(); + v.push(metric1Value); + v.push(metric2Value); + + var metric1:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, v) as MetricMocker; + var metric2:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric2Value, v) as MetricMocker; + + assertNotNull(metric1); + assertNotNull(metric2); + assertTrue(metric1 != metric2); + } + + /** + * Tests that two different objects are returned if we request 2 metrics with the same + * type, but with different params + */ + [Test] + public function testGetMetricSameTypeDifferentParamsComplex():void + { + //create complex parameter + var v:Vector. = new Vector.(); + v.push(metric1Value); + v.push(metric2Value); + var u:Vector. = new Vector.(); + u.push(metric1Value); + u.push(metric1Value); + + var a:Array = new Array(); + a.push(u); + a.push(metric1Value); + + var metric1:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, u) as MetricMocker; + var metric2:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, v) as MetricMocker; + + assertNotNull(metric1); + assertNotNull(metric2); + assertTrue(metric1 != metric2); + } + + /** + * Tests that two different objects are returned if we request 2 metrics with the same + * type, but with different params + */ + [Test] + public function testGetMetricSameTypeDifferentParamsComplexArray():void + { + //create complex parameter + var u:Vector. = new Vector.(); + u.push(metric1Value); + u.push(metric1Value); + + var a:Array = new Array(); + + a.push(u); + a.push(metric1Value); + + + var metric1:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, u, a) as MetricMocker; + + //modify array by changing the vector inside + u = new Vector.(); + a = new Array(); + u.push(metric1Value); + u.push(metric2Value); + a.push(u); + a.push(metric1Value); + + var metric2:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, u, a) as MetricMocker; + + assertNotNull(metric1); + assertNotNull(metric2); + assertTrue(metric1 != metric2); + } + + /** + * Tests that two different objects are returned if we request 2 metrics with the same + * type, and with same params + */ + [Test] + public function testGetMetricSameTypeSameParamsComplex():void + { + //create complex parameter + var v:Vector. = new Vector.(); + v.push(metric1Value); + v.push(metric2Value); + var u:Vector. = new Vector.(); + u.push(metric1Value); + u.push(metric2Value); + + var metric1:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, u) as MetricMocker; + var metric2:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, metric1Value, v) as MetricMocker; + + assertNotNull(metric1); + assertNotNull(metric2); + assertStrictlyEquals(metric1, metric2); + } + + /** + * Tests that two different objects are returned if we request 2 metrics with the same + * type, and with null parameters + */ + [Test] + public function testGetMetricSameTypeSameParamsNull():void + { + var metric1:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, null, null) as MetricMocker; + var metric2:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, null, null) as MetricMocker; + + assertNotNull(metric1); + assertNotNull(metric2); + assertStrictlyEquals(metric1, metric2); + } + + /** + * Tests that two different objects are returned if we request 2 metrics with the same + * type, and with different and null parameters + */ + [Test] + public function testGetMetricSameTypeDifferentParamsNull():void + { + var metric1:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, null, 3) as MetricMocker; + var metric2:MetricMocker = metricRepository.getMetric(METRIC_TYPE_1, null, 4) as MetricMocker; + + assertNotNull(metric1); + assertNotNull(metric2); + assertTrue(metric1 != metric2); + } + + private var metricRepository:MetricRepository; + + private static const METRIC_TYPE_1:String = "com.example.metrics.sample"; + private static const MAX_RETRIEVING_TIME:int=1; + private static const MAX_CREATING_TIME:int=4; + + private var metric1Value:MetricValue; + private var metric2Value:MetricValue; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricValue.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricValue.as new file mode 100644 index 0000000..95ec267 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestMetricValue.as @@ -0,0 +1,109 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNull; + import org.flexunit.asserts.assertTrue; + + public class TestMetricValue + { + [Before] + public function setUp():void + { + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testMetricValueNumber():void + { + metricValue = new MetricValue(101.3456); + assertEquals(101.3456, metricValue.value); + assertEquals(true, metricValue.valid); + } + + [Test] + public function testMetricValueString():void + { + metricValue = new MetricValue("testvalue"); + assertEquals("testvalue", metricValue.value); + assertEquals(true, metricValue.valid); + } + + [Test] + public function testMetricValueNull():void + { + metricValue = new MetricValue(null); + assertNull(metricValue.value); + assertEquals(true, metricValue.valid); + } + + [Test] + public function testMetricValueBool():void + { + metricValue = new MetricValue(true); + assertTrue(metricValue.value); + assertEquals(true, metricValue.valid); + } + + [Test] + public function testMetricValueUndefined():void + { + metricValue = new MetricValue(undefined); + assertEquals(undefined, metricValue.value); + } + + [Test] + public function testMetricValidityValid():void + { + metricValue = new MetricValue(10, true); + assertEquals(10,metricValue.value); + assertTrue(metricValue.valid); + } + [Test] + public function testMetricValidityInvalid():void + { + metricValue = new MetricValue(11, false); + assertEquals(11, metricValue.value); + assertFalse(metricValue.valid); + } + + private var metricValue:MetricValue; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestRecentSwitchMetric.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestRecentSwitchMetric.as new file mode 100644 index 0000000..6f5a4f6 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/metrics/TestRecentSwitchMetric.as @@ -0,0 +1,197 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.metrics +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestRecentSwitchMetric + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + } + + [After] + public function tearDown():void + { + netStream = null; + qosInfoHistory = null; + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + + [Test] + public function testRecentSwitchMetric():void + { + metric = new RecentSwitchMetric(qosInfoHistory); + + assertEquals(MetricType.RECENT_SWITCH, metric.type); + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(1400000, 4010, 2001, 0))); + + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 1))); + + metricValue = metric.value; + assertEquals(1, metricValue.value); + assertTrue(metricValue.valid); + + addQoSInfo(generateQoSInfo(3333, 1, new FragmentDetails(3500000, 4040, 6001, 0))); + + metricValue = metric.value; + assertEquals(-1, metricValue.value); + assertTrue(metricValue.valid); + + + addQoSInfo(generateQoSInfo(4444, 4, new FragmentDetails(3500000, 4040, 6001, 4))); + + metricValue = metric.value; + assertEquals(4, metricValue.value); + assertTrue(metricValue.valid); + + addQoSInfo(generateQoSInfo(5555, 2, new FragmentDetails(3500000, 4040, 6001, 2))); + + metricValue = metric.value; + assertEquals(-2, metricValue.value); + assertTrue(metricValue.valid); + + addQoSInfo(generateQoSInfo(6666, 2, new FragmentDetails(3500000, 4040, 6001, 2))); + + metricValue = metric.value; + assertEquals(0, metricValue.value); + assertTrue(metricValue.valid); + + } + + + [Test] + public function testRecentSwitchMetricForNullFirstFragmentDetails():void + { + metric = new RecentSwitchMetric(qosInfoHistory); + + assertEquals(MetricType.RECENT_SWITCH, metric.type); + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(1111, 0, null)); + + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + + addQoSInfo(generateQoSInfo(2222, 0, new FragmentDetails(2400000, 4020, 4001, 1))); + + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + } + + + [Test] + public function testRecentSwitchMetricForNullSecondFragmentDetails():void + { + metric = new RecentSwitchMetric(qosInfoHistory); + + assertEquals(MetricType.RECENT_SWITCH, metric.type); + var metricValue:MetricValue = metric.value; + + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + addQoSInfo(generateQoSInfo(1111, 0, new FragmentDetails(2400000, 4020, 4001, 1))); + + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + + addQoSInfo(generateQoSInfo(2222, 1, null)); + + metricValue = metric.value; + assertEquals(undefined, metricValue.value); + assertFalse(metricValue.valid); + + } + + //helper different from qosinfo tests functions + + private function generateQoSInfo(timestamp:Number, currentIndex:Number, fragmentDetails:FragmentDetails):QoSInfo + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< 3; i++) + { + v[i] = new QualityLevel( i, 150+ 100*i, "test" + (150+ 100*i) ); + } + return (new QoSInfo(timestamp, 5678+timestamp, v, currentIndex, currentIndex, fragmentDetails)); + } + + //helper identical to qosinfo tests functions + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private var metric:RecentSwitchMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + + + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/qos/QoSInfoHistoryGenerator.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/qos/QoSInfoHistoryGenerator.as new file mode 100644 index 0000000..3ce36be --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/qos/QoSInfoHistoryGenerator.as @@ -0,0 +1,56 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.qos +{ + import flash.net.NetConnection; + import flash.net.NetStream; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + + public class QoSInfoHistoryGenerator + { + public static function generateSampleQoSInfoHistory():QoSInfoHistory + { + var qosInfoHistory:QoSInfoHistory = generateEmptyQoSInfoHistory(); + + var qosInfo:QoSInfo = new QoSInfo(SAMPLE_MACHINE_TIME); + + qosInfoHistory.addQoSInfo(qosInfo); + + return qosInfoHistory; + } + + public static function generateEmptyQoSInfoHistory():QoSInfoHistory + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + + var ns:NetStream = new NetStream(conn); + + var qosInfoHistory:QoSInfoHistory = new QoSInfoHistory(ns); + + return qosInfoHistory; + } + + private static const SAMPLE_MACHINE_TIME:Number = 100; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/qos/TestQoSInfoHistory.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/qos/TestQoSInfoHistory.as new file mode 100644 index 0000000..39242e2 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/qos/TestQoSInfoHistory.as @@ -0,0 +1,316 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.qos +{ + import flash.net.NetConnection; + import flash.net.NetStream; + import flash.net.NetStreamInfo; + + import mx.netmon.NetworkMonitor; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertNull; + import org.flexunit.asserts.assertStrictlyEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.net.qos.FragmentDetails; + import org.osmf.net.qos.PlaybackDetails; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestQoSInfoHistory + { + [Before] + public function setUp():void + { + netConnection = new NetConnection(); + netConnection.connect(null); + netStream = new NetStream(netConnection); + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testInitQoSInfoHistoryDefault():void + { + qosInfoHistory = new QoSInfoHistory(netStream); + assertEquals(10, qosInfoHistory.maxHistoryLength); + assertEquals(0, qosInfoHistory.length); + assertNull(qosInfoHistory.getLatestQoSInfo()); + + } + + [Test(expects="ArgumentError")] + public function testInitQosInfoHistoryZeroMaxLength():void + { + qosInfoHistory = new QoSInfoHistory(netStream, 0); + } + + [Test] + public function testQoSInfoHistoryWrap():void + { + qosInfoHistory = new QoSInfoHistory(netStream,3); + + + var qos:QoSInfo; + + addQoSInfo(generateQoSInfo(1111)); + assertEquals(1, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(2222)); + assertEquals(2, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(3333)); + assertEquals(3, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(4444)); + assertEquals(3, qosInfoHistory.length); + + assertEquals(4444, qosInfoHistory.getHistory(3)[0].timestamp); + assertEquals(3333, qosInfoHistory.getHistory(3)[1].timestamp); + assertEquals(2222, qosInfoHistory.getHistory(3)[2].timestamp); + + } + + [Test] + public function testQoSInfoHistoryFlush():void + { + qosInfoHistory = new QoSInfoHistory(netStream,3); + + //fill the QoSInfoHistory + var qos:QoSInfo; + + addQoSInfo(generateQoSInfo(1111)); + assertEquals(1, qosInfoHistory.length); + + assertEquals(qosInfoHistory.getHistory()[0],qosInfoHistory.getLatestQoSInfo()); + + addQoSInfo(generateQoSInfo(2222)); + assertEquals(2, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(3333)); + assertEquals(3, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(4444)); + assertEquals(3, qosInfoHistory.length); + + assertEquals(4444, qosInfoHistory.getHistory(3)[0].timestamp); + assertEquals(3333, qosInfoHistory.getHistory(3)[1].timestamp); + assertEquals(2222, qosInfoHistory.getHistory(3)[2].timestamp); + + //flush the QoSInfoHistory + qosInfoHistory.flush(); + + assertEquals(0,qosInfoHistory.length); + assertEquals(0,qosInfoHistory.getHistory(3).length); + + } + + [Test] + public function testQoSInfoHistorySlice():void + { + qosInfoHistory = new QoSInfoHistory(netStream,3); + + var qos:QoSInfo; + + addQoSInfo(generateQoSInfo(1111)); + assertEquals(1, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(2222)); + assertEquals(2, qosInfoHistory.length); + + //get slices + assertEquals(1, qosInfoHistory.getHistory(1).length); + + assertEquals(2, qosInfoHistory.getHistory().length); + + //next assert checks for slice limit + assertEquals(2, qosInfoHistory.getHistory(16777215+1).length); + + //next assert checks for default responses + assertEquals(2, qosInfoHistory.getHistory(0).length); + + //assert that the last pushed element is first always + assertEquals(2222, qosInfoHistory.getHistory(0)[0].timestamp); + assertEquals(2222, qosInfoHistory.getHistory()[0].timestamp); + assertEquals(2222, qosInfoHistory.getHistory(1)[0].timestamp); + + //check for more elements than available in the history + assertEquals(2, qosInfoHistory.getHistory(4).length); + assertEquals(2222, qosInfoHistory.getHistory(4)[0].timestamp); + assertEquals(1111, qosInfoHistory.getHistory(4)[1].timestamp); + } + + + [Test] + public function testQoSInfoHistoryIncreaseLength():void + { + qosInfoHistory = new QoSInfoHistory(netStream,3); + + var qos:QoSInfo; + + addQoSInfo(generateQoSInfo(1111)); + assertEquals(1, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(2222)); + assertEquals(2, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(3333)); + assertEquals(3, qosInfoHistory.length); + + //action + qosInfoHistory.maxHistoryLength = 4; + + assertEquals(4, qosInfoHistory.maxHistoryLength); + assertEquals(3, qosInfoHistory.length); + + + assertEquals(3, qosInfoHistory.getHistory().length); + assertEquals(3333, qosInfoHistory.getHistory()[0].timestamp); + assertEquals(2222, qosInfoHistory.getHistory()[1].timestamp); + assertEquals(1111, qosInfoHistory.getHistory()[2].timestamp); + + } + + [Test] + public function testQoSInfoHistoryDecreaseLength():void + { + qosInfoHistory = new QoSInfoHistory(netStream,3); + + var qos:QoSInfo; + + addQoSInfo(generateQoSInfo(1111)); + assertEquals(1, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(2222)); + assertEquals(2, qosInfoHistory.length); + addQoSInfo(generateQoSInfo(3333)); + assertEquals(3, qosInfoHistory.length); + + //action + qosInfoHistory.maxHistoryLength = 2; + + assertEquals(2, qosInfoHistory.maxHistoryLength); + assertEquals(2, qosInfoHistory.length); + + + assertEquals(2, qosInfoHistory.getHistory().length); + assertEquals(3333, qosInfoHistory.getHistory()[0].timestamp); + assertEquals(2222, qosInfoHistory.getHistory()[1].timestamp); + } + + + + [Test] + public function testInitQoSInfoDefault():void + { + var qos:QoSInfo = new QoSInfo(); + assertTrue(isNaN(qos.timestamp)); + assertTrue(isNaN(qos.playheadTime)); + + + assertNull(qos.availableQualityLevels); + + assertEquals(-1, qos.currentIndex); + assertEquals(-1, qos.actualIndex); + + assertNull(qos.lastDownloadedFragmentDetails); + assertTrue(isNaN(qos.maxFPS)); + assertNull(qos.playbackDetailsRecord); + assertNull(qos.nsInfo); + + assertTrue(isNaN(qos.bufferLength)); + assertTrue(isNaN(qos.bufferTime)); + + assertFalse(qos.emptyBufferOccurred); + } + + [Test] + public function testInitQoSInfoWithInformation():void + { + var qos:QoSInfo = generateQoSInfo(1234); + + assertEquals(1234, qos.timestamp); + assertEquals(5678, qos.playheadTime); + assertEquals(0, qos.actualIndex); + assertNotNull(qos.availableQualityLevels); + assertEquals(2,qos.availableQualityLevels.length); + assertEquals("test1",qos.availableQualityLevels[0].streamName); + assertEquals(0,qos.availableQualityLevels[0].index); + assertEquals(611,qos.availableQualityLevels[0].bitrate); + assertEquals("test2",qos.availableQualityLevels[1].streamName); + assertEquals(1,qos.availableQualityLevels[1].index); + assertEquals(711,qos.availableQualityLevels[1].bitrate); + assertNotNull(qos.lastDownloadedFragmentDetails); + assertEquals(14000, qos.lastDownloadedFragmentDetails.size); + assertEquals(568, qos.lastDownloadedFragmentDetails.downloadDuration); + assertEquals(4000, qos.lastDownloadedFragmentDetails.playDuration); + assertEquals(2, qos.lastDownloadedFragmentDetails.index); + assertEquals(31.3, qos.maxFPS); + assertNotNull(qos.nsInfo); + assertTrue(qos.nsInfo is NetStreamInfo); + assertEquals(29.7, qos.nsInfo.currentBytesPerSecond); + assertNotNull(qos.playbackDetailsRecord); + assertTrue(qos.playbackDetailsRecord is Vector.); + assertEquals(2, qos.playbackDetailsRecord.length); + assertEquals(2.2, qos.playbackDetailsRecord[1].duration); + assertEquals(8.3, qos.bufferLength); + assertEquals(9.5, qos.bufferTime); + assertTrue(qos.emptyBufferOccurred); + + } + + private function addQoSInfo(qos:QoSInfo):void + { + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false, false, qos)); + } + + private function generateQoSInfo(timestamp:Number):QoSInfo + { + var q:Vector. = new Vector.(); + q[0]= new QualityLevel(0,611,"test1"); + q[1]= new QualityLevel(1,711,"test2"); + + var nsi:NetStreamInfo = new NetStreamInfo(29.7,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28); + var playbackDetails:Vector. = new Vector.(); + playbackDetails.push(new PlaybackDetails(0,2.03,22)); + playbackDetails.push(new PlaybackDetails(1,2.2,20)); + + return (new QoSInfo(timestamp, 5678, q, 0, 0, new FragmentDetails(14000, 4000, 568, 2), 31.3, playbackDetails, nsi, 8.3, 9.5, true)); + } + + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + private var netConnection:NetConnection; + + + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/RuleMocker.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/RuleMocker.as new file mode 100644 index 0000000..f70cf8b --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/RuleMocker.as @@ -0,0 +1,70 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.rules +{ + import org.osmf.net.metrics.MetricFactory; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.qos.QoSInfoHistoryGenerator; + + public class RuleMocker extends RuleBase + { + public function RuleMocker(returnValue:Recommendation) + { + super(new MetricRepository(new MetricFactory(QoSInfoHistoryGenerator.generateEmptyQoSInfoHistory()))); + _returnValue = returnValue; + } + + override public function getRecommendation():Recommendation + { + return _returnValue; + } + + public function set returnValue(value:Recommendation):void + { + _returnValue = value; + } + + + private var _returnValue:Recommendation; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestAfterUpSwitchBufferBandwidthRule.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestAfterUpSwitchBufferBandwidthRule.as new file mode 100644 index 0000000..932cc1a --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestAfterUpSwitchBufferBandwidthRule.as @@ -0,0 +1,501 @@ +/***************************************************** + * + * Copyright 2012 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2012 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.rules +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.net.metrics.ActualBitrateMetric; + import org.osmf.net.metrics.ActualBitrateMetricMocker; + import org.osmf.net.metrics.AvailableQualityLevelsMetric; + import org.osmf.net.metrics.AvailableQualityLevelsMetricMocker; + import org.osmf.net.metrics.BandwidthMetric; + import org.osmf.net.metrics.BandwidthMetricMocker; + import org.osmf.net.metrics.BufferFragmentsMetric; + import org.osmf.net.metrics.BufferFragmentsMetricMocker; + import org.osmf.net.metrics.CurrentStatusMetric; + import org.osmf.net.metrics.CurrentStatusMetricMocker; + import org.osmf.net.metrics.DefaultMetricFactory; + import org.osmf.net.metrics.DefaultMetricFactoryMocker; + import org.osmf.net.metrics.FragmentCountMetric; + import org.osmf.net.metrics.FragmentCountMetricMocker; + import org.osmf.net.metrics.MetricFactory; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.metrics.MetricType; + import org.osmf.net.metrics.RecentSwitchMetricMocker; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestAfterUpSwitchBufferBandwidthRule + { + [Before] + public function setUp():void + { + + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + metricFactory = new DefaultMetricFactoryMocker(qosInfoHistory); + metricRepository = new MetricRepository(metricFactory); + + + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1)) as BandwidthMetricMocker; + + fragmentCountMetric = metricRepository.getMetric(MetricType.FRAGMENT_COUNT) as FragmentCountMetricMocker; + bufferFragmentsMetric = metricRepository.getMetric(MetricType.BUFFER_FRAGMENTS) as BufferFragmentsMetricMocker; + + actualBitrateMetric = metricRepository.getMetric(MetricType.ACTUAL_BITRATE) as ActualBitrateMetricMocker; + bufferFragmentsMetric = metricRepository.getMetric(MetricType.BUFFER_FRAGMENTS) as BufferFragmentsMetricMocker; + availableQualityLevelsMetric = metricRepository.getMetric(MetricType.AVAILABLE_QUALITY_LEVELS) as AvailableQualityLevelsMetricMocker; + currentStatusMetric = metricRepository.getMetric(MetricType.CURRENT_STATUS) as CurrentStatusMetricMocker; + recentSwitchMetric = metricRepository.getMetric(MetricType.RECENT_SWITCH) as RecentSwitchMetricMocker; + + } + + [After] + public function tearDown():void + { + netStream = null; + qosInfoHistory = null; + metricFactory = null; + metricRepository = null; + + + bandwidthMetric = null; + + fragmentCountMetric = null; + bufferFragmentsMetric = null; + + actualBitrateMetric = null; + bufferFragmentsMetric = null; + availableQualityLevelsMetric = null; + currentStatusMetric = null; + recentSwitchMetric = null; + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testAfterUpSwitchBandwidthBufferRuleInit():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.6); + assertEquals(0.6, rule.minBandwidthToBitrateRatio); + assertEquals(4, rule.bufferFragmentsThreshold); + assertEquals(1, rule.weights.length); + } + + [Test] + public function testAfterUpSwitchBandwidthBufferRuleInitRatioZero():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0); + assertEquals(0, rule.minBandwidthToBitrateRatio); + assertEquals(4, rule.bufferFragmentsThreshold); + assertEquals(1, rule.weights.length); + } + + [Test(expects="ArgumentError")] + public function testAfterUpSwitchBandwidthBufferRuleInitRatioNaN():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, NaN); + } + + [Test(expects="ArgumentError")] + public function testAfterUpSwitchBandwidthBufferRuleInitRatioNegative():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, -0.1); + } + + + [Test] + public function testAfterUpSwitchBandwidthBufferRule_Set_minBandwidthToBitrateRatio():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.6); + assertEquals(0.6, rule.minBandwidthToBitrateRatio); + + rule.minBandwidthToBitrateRatio = 0.7; + + assertEquals(0.7, rule.minBandwidthToBitrateRatio); + } + + [Test] + public function testAfterUpSwitchBandwidthBufferRule_Set_minBandwidthToBitrateRatioZero():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.6); + assertEquals(0.6, rule.minBandwidthToBitrateRatio); + + rule.minBandwidthToBitrateRatio = 0; + + assertEquals(0, rule.minBandwidthToBitrateRatio); + } + + [Test(expects="ArgumentError")] + public function testAfterUpSwitchBandwidthBufferRule_Set_minBandwidthToBitrateRatioNaN():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.6); + assertEquals(0.6, rule.minBandwidthToBitrateRatio); + + rule.minBandwidthToBitrateRatio = NaN; + } + + [Test(expects="ArgumentError")] + public function testAfterUpSwitchBandwidthBufferRule_Set_minBandwidthToBitrateRatioNegative():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.6); + assertEquals(0.6, rule.minBandwidthToBitrateRatio); + + rule.minBandwidthToBitrateRatio = -0.1; + } + + + [Test] + public function testGetRecommendationInvalidRecentSwitchMetric():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.624); + + recentSwitchMetric.internalValue = -2; + recentSwitchMetric.returnValid = false; + + bandwidthMetric.internalValue = 8000.1; + bandwidthMetric.returnValid = true; + + fragmentCountMetric.internalValue = 10; + fragmentCountMetric.returnValid = true; + + actualBitrateMetric.internalValue = 501; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:int=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.AFTER_UP_SWITCH_BUFFER_BANDWIDTH, recommendation.ruleType); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testGetRecommendationRecentSwitchMetricZero():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.624); + + recentSwitchMetric.internalValue = 0; + recentSwitchMetric.returnValid = true; + + bandwidthMetric.internalValue = 8000.1; + bandwidthMetric.returnValid = true; + + fragmentCountMetric.internalValue = 10; + fragmentCountMetric.returnValid = true; + + actualBitrateMetric.internalValue = 501; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:int = 0; i < 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.AFTER_UP_SWITCH_BUFFER_BANDWIDTH, recommendation.ruleType); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testGetRecommendationRecentSwitchMetricNegative():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.624); + + recentSwitchMetric.internalValue = -2; + recentSwitchMetric.returnValid = true; + + bandwidthMetric.internalValue = (800.1 - 0.1) * 1000 / 8 * 0.624; + bandwidthMetric.returnValid = true; + + fragmentCountMetric.internalValue = 10; + fragmentCountMetric.returnValid = true; + + actualBitrateMetric.internalValue = 800.1; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:int=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.AFTER_UP_SWITCH_BUFFER_BANDWIDTH, recommendation.ruleType); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testGetRecommendationRecentSwitchMetricPositive_BandwidthInvalid():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.624); + + recentSwitchMetric.internalValue = 2; + recentSwitchMetric.returnValid = true; + + bandwidthMetric.internalValue = (800.1 - 0.1) * 1000 / 8 * 0.624; + bandwidthMetric.returnValid = false; + + fragmentCountMetric.internalValue = 10; + fragmentCountMetric.returnValid = true; + + actualBitrateMetric.internalValue = 800.1; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:int = 0; i < 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.AFTER_UP_SWITCH_BUFFER_BANDWIDTH, recommendation.ruleType); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testGetRecommendationRecentSwitchMetricPositive_ActualBitrateValid_LowBandwidth():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.624); + + recentSwitchMetric.internalValue = 2; + recentSwitchMetric.returnValid = true; + + bandwidthMetric.internalValue = (800.1 - 0.1) * 1000 / 8 * 0.624; + bandwidthMetric.returnValid = true; + + fragmentCountMetric.internalValue = 10; + fragmentCountMetric.returnValid = true; + + actualBitrateMetric.internalValue = 800.1; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:int = 0; i < 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.AFTER_UP_SWITCH_BUFFER_BANDWIDTH, recommendation.ruleType); + assertEquals((800.1 - 0.1) * 0.624, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + } + + [Test] + public function testGetRecommendationRecentSwitchMetricPositive_ActualBitrateValid_EqualBandwidth():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.624); + + recentSwitchMetric.internalValue = 2; + recentSwitchMetric.returnValid = true; + + bandwidthMetric.internalValue = (800.1 + 0.0) * 1000.0 / 8.0 * 0.624; + bandwidthMetric.returnValid = true; + + fragmentCountMetric.internalValue = 10; + fragmentCountMetric.returnValid = true; + + actualBitrateMetric.internalValue = 800.1; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for( var i:int = 0; i < 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.AFTER_UP_SWITCH_BUFFER_BANDWIDTH, recommendation.ruleType); + assertEquals((800.1 + 0.0) * 0.624, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testGetRecommendationRecentSwitchMetricPositive_ActualBitrateValid_HighBandwidth():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.624); + + recentSwitchMetric.internalValue = 2; + recentSwitchMetric.returnValid = true; + + bandwidthMetric.internalValue = (800.1 + 0.1) * 1000.0 / 8.0 * 0.624; + bandwidthMetric.returnValid = true; + + fragmentCountMetric.internalValue = 10; + fragmentCountMetric.returnValid = true; + + actualBitrateMetric.internalValue = 800.1; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:int = 0; i < 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.AFTER_UP_SWITCH_BUFFER_BANDWIDTH, recommendation.ruleType); + assertEquals((800.1 + 0.1) * 1000.0 / 8.0 * 0.624 / 1000.0 * 8.0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testGetRecommendationRecentSwitchMetricPositive_ActualBitrateInvalid_CurrentStatusValid_AvailableQualityValid_LowBandwidth():void + { + rule = new AfterUpSwitchBufferBandwidthRule(metricRepository, 4, 0.624); + + recentSwitchMetric.internalValue = 2; + recentSwitchMetric.returnValid = true; + + bandwidthMetric.internalValue = (350.0 - 0.1) * 1000.0 / 8.0 * 0.624 ; + bandwidthMetric.returnValid = true; + + fragmentCountMetric.internalValue = 10; + fragmentCountMetric.returnValid = true; + + actualBitrateMetric.internalValue = 800.1; + actualBitrateMetric.returnValid = false; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:int = 0; i < 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.AFTER_UP_SWITCH_BUFFER_BANDWIDTH, recommendation.ruleType); + assertEquals((350.0 - 0.1) * 1000.0 / 8.0 * 0.624 / 1000.0 * 8.0, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + } + + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:int=0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + private var rule:AfterUpSwitchBufferBandwidthRule; + + //metrics for super + private var bandwidthMetric:BandwidthMetricMocker; + private var fragmentCountMetric:FragmentCountMetricMocker; + private var bufferFragmentsMetric:BufferFragmentsMetricMocker; + + private var actualBitrateMetric:ActualBitrateMetricMocker; + private var currentStatusMetric:CurrentStatusMetricMocker; + private var availableQualityLevelsMetric:AvailableQualityLevelsMetricMocker; + private var recentSwitchMetric:RecentSwitchMetricMocker; + + + + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + private var metricFactory:MetricFactory; + private var metricRepository:MetricRepository; + + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestBandwidthRule.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestBandwidthRule.as new file mode 100644 index 0000000..7c4613b --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestBandwidthRule.as @@ -0,0 +1,228 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.rules +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.events.QoSInfoEvent; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.net.metrics.BandwidthMetric; + import org.osmf.net.metrics.BandwidthMetricMocker; + import org.osmf.net.metrics.DefaultMetricFactory; + import org.osmf.net.metrics.DefaultMetricFactoryMocker; + import org.osmf.net.metrics.FragmentCountMetric; + import org.osmf.net.metrics.FragmentCountMetricMocker; + import org.osmf.net.metrics.MetricFactory; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.metrics.MetricType; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + + public class TestBandwidthRule + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + metricFactory = new DefaultMetricFactoryMocker(qosInfoHistory); + metricRepository = new MetricRepository(metricFactory); + + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(0.7, 0.3) ) as BandwidthMetricMocker; + fragmentCountMetric = metricRepository.getMetric(MetricType.FRAGMENT_COUNT) as FragmentCountMetricMocker; + + } + + [After] + public function tearDown():void + { + fragmentCountMetric = null; + bandwidthMetric = null; + metricRepository = null; + metricFactory = null; + qosInfoHistory = null; + netStream = null; + } + + + [Test(expects="ArgumentError")] + public function testBandwidthRuleInitWithNoFragments():void + { + + rule = new BandwidthRule(metricRepository, new []); + } + + [Test(expects="ArgumentError")] + public function testBandwidthRuleInitWithNegativeWeight():void + { + rule = new BandwidthRule(metricRepository, new [1, -0.1, -0.01, -0.001]); + } + + + [Test(expects="ArgumentError")] + public function testBandwidthRuleInitWithNaNWeight():void + { + rule = new BandwidthRule(metricRepository, new [NaN, NaN, NaN, NaN]); + } + + [Test(expects="ArgumentError")] + public function testBandwidthRuleInitWithZeroWeight():void + { + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BandwidthRule(metricRepository, new [0, 0, 0, 0]); + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=2; + fragmentCountMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.BANDWIDTH, recommendation.ruleType); + assertEquals(8000.1 * 8 / 1000, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + assertEquals(4, rule.weights.length); + } + + [Test] + public function testBandwidthRuleInvalidMetric():void + { + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BandwidthRule(metricRepository, generateWeights(1, 0.9, 0.9*0.9)); + + //both rules return invalid + + bandwidthMetric.internalValue=undefined; + bandwidthMetric.returnValid=false; + + fragmentCountMetric.internalValue=undefined; + fragmentCountMetric.returnValid=false; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + + //check: bandwidth returns invalid + + bandwidthMetric.internalValue=undefined; + bandwidthMetric.returnValid=false; + + fragmentCountMetric.internalValue=1; + fragmentCountMetric.returnValid=true; + + recommendation = rule.getRecommendation(); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + + //check: fragment count returns invalid + + bandwidthMetric.internalValue=690; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=undefined; + fragmentCountMetric.returnValid=false; + + recommendation = rule.getRecommendation(); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testBandwidthRuleValidMetric():void + { + // add sample qos info + netStream.dispatchEvent(new QoSInfoEvent(QoSInfoEvent.QOS_UPDATE, false,false , new QoSInfo())); + + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1, 0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BandwidthRule(metricRepository, generateWeights(1, 0.9, 0.9*0.9)); + + //less fragments than needed + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=2; + fragmentCountMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(8000.1 * 8 / 1000, recommendation.bitrate); + assertEquals((1 + 0.9) / (1 + 0.9 + 0.9*0.9 ), recommendation.confidence); + + //more fragments than needed + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=10; + fragmentCountMetric.returnValid=true; + + recommendation = rule.getRecommendation(); + assertEquals(8000.1 * 8 / 1000, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + + // fragments exactly as needed + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=3; + fragmentCountMetric.returnValid=true; + + recommendation = rule.getRecommendation(); + assertEquals(8000.1 * 8 / 1000, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + + } + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + private var rule:BandwidthRule; + + private var bandwidthMetric:BandwidthMetricMocker; + private var fragmentCountMetric:FragmentCountMetricMocker; + + private var metric:FragmentCountMetric; + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + private var metricFactory:MetricFactory; + private var metricRepository:MetricRepository; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestBufferBandwidthRule.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestBufferBandwidthRule.as new file mode 100644 index 0000000..11a21b0 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestBufferBandwidthRule.as @@ -0,0 +1,523 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.rules +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.net.metrics.ActualBitrateMetric; + import org.osmf.net.metrics.ActualBitrateMetricMocker; + import org.osmf.net.metrics.AvailableQualityLevelsMetric; + import org.osmf.net.metrics.AvailableQualityLevelsMetricMocker; + import org.osmf.net.metrics.BandwidthMetric; + import org.osmf.net.metrics.BandwidthMetricMocker; + import org.osmf.net.metrics.BufferFragmentsMetric; + import org.osmf.net.metrics.BufferFragmentsMetricMocker; + import org.osmf.net.metrics.CurrentStatusMetric; + import org.osmf.net.metrics.CurrentStatusMetricMocker; + import org.osmf.net.metrics.DefaultMetricFactory; + import org.osmf.net.metrics.DefaultMetricFactoryMocker; + import org.osmf.net.metrics.FragmentCountMetric; + import org.osmf.net.metrics.FragmentCountMetricMocker; + import org.osmf.net.metrics.MetricFactory; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.metrics.MetricType; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestBufferBandwidthRule + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + metricFactory = new DefaultMetricFactoryMocker(qosInfoHistory); + metricRepository = new MetricRepository(metricFactory); + + + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + fragmentCountMetric = metricRepository.getMetric(MetricType.FRAGMENT_COUNT) as FragmentCountMetricMocker; + bufferFragmentsMetric = metricRepository.getMetric(MetricType.BUFFER_FRAGMENTS) as BufferFragmentsMetricMocker; + + actualBitrateMetric = metricRepository.getMetric(MetricType.ACTUAL_BITRATE) as ActualBitrateMetricMocker; + bufferFragmentsMetric = metricRepository.getMetric(MetricType.BUFFER_FRAGMENTS) as BufferFragmentsMetricMocker; + availableQualityLevelsMetric = metricRepository.getMetric(MetricType.AVAILABLE_QUALITY_LEVELS) as AvailableQualityLevelsMetricMocker; + currentStatusMetric = metricRepository.getMetric(MetricType.CURRENT_STATUS) as CurrentStatusMetricMocker; + } + + [After] + public function tearDown():void + { + fragmentCountMetric = null; + bandwidthMetric = null; + metricRepository = null; + metricFactory = null; + qosInfoHistory = null; + netStream = null; + } + + + [Test(expects="ArgumentError")] + public function testBandwidthBufferRuleInitWithNegativeBufferThreshold():void + { + rule = new BufferBandwidthRule(metricRepository, new [7, 3], -1 ); + } + + [Test(expects="ArgumentError")] + public function testBandwidthBufferRuleInitWithBufferThresholdNaN():void + { + rule = new BufferBandwidthRule(metricRepository, new [7, 3], NaN ); + } + + [Test] + public function testBandwidthBufferRuleInitWithBufferThresholdZero():void + { + rule = new BufferBandwidthRule(metricRepository, new [7, 3], 0 ); + assertEquals(0, rule.bufferFragmentsThreshold); + } + + [Test] + public function testBandwidthBufferRuleSetGetBufferFragmentsThreshold():void + { + rule = new BufferBandwidthRule(metricRepository, new [7, 3], 3 ); + rule.bufferFragmentsThreshold = 4; + assertEquals(4, rule.bufferFragmentsThreshold); + } + + [Test(expects="ArgumentError")] + public function testBandwidthBufferRuleSetGetBufferFragmentsThresholdNaN():void + { + rule = new BufferBandwidthRule(metricRepository, new [7, 3], 3 ); + rule.bufferFragmentsThreshold=NaN; + } + + [Test(expects="ArgumentError")] + public function testBandwidthBufferRuleSetGetBufferFragmentsThresholdNegative():void + { + rule = new BufferBandwidthRule(metricRepository, new [7, 3], 3 ); + rule.bufferFragmentsThreshold=-1; + } + + [Test] + public function testBandwidthBufferRuleSetGetBufferFragmentsThresholdZero():void + { + rule = new BufferBandwidthRule(metricRepository, new [7, 3], 3 ); + rule.bufferFragmentsThreshold=0; + assertEquals(0, rule.bufferFragmentsThreshold); + + } + + [Test] + public function testBandwidthBufferRuleInvalidMetrics():void + { + var i:int; + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BufferBandwidthRule(metricRepository, generateWeights(1,0.9, 0.9*0.9), 3 ); + + //actualbitrate metric return invalid, currentstatus returns invalid + // to simulate a correct super call, make other metrics correct + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=10; + fragmentCountMetric.returnValid=true; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=false; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=false; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(i=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + + + //actualbitrate metric return invalid, available quality return invalid + + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=10; + fragmentCountMetric.returnValid=true; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=false; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(i=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=false; + + recommendation = rule.getRecommendation(); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + public function testBandwidthBufferRuleInvalidSuperMetrics():void + { + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BufferBandwidthRule(metricRepository, generateWeights(1,0.9, 0.9*0.9), 3 ); + + //actualbitrate metric return valid, currentstatus and available quality return valid + // to simulate a correct super call + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=false; + + fragmentCountMetric.internalValue=10; + fragmentCountMetric.returnValid=false; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=true; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + + } + + [Test] + public function testBandwidthBufferRuleValidMetricActualLessThanRecommended():void + { + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BufferBandwidthRule(metricRepository, generateWeights(1,0.9, 0.9*0.9), 3 ); + + //actualbitrate metric return valid, currentstatus and available quality return valid + // to simulate a correct super call + + bandwidthMetric.internalValue=800000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=10; + fragmentCountMetric.returnValid=true; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=true; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(800000.1 * 8 / 1000, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + + } + + [Test] + public function testBandwidthBufferRuleValidActualBitrateMetricRecommendedLessThanActualAndBufferHasFragments():void + { + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BufferBandwidthRule(metricRepository, generateWeights(1,0.9, 0.9*0.9), 3 ); + + //actualbitrate metric return valid, currentstatus and available quality return valid + // to simulate a correct super call + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=2; + fragmentCountMetric.returnValid=true; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=true; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + bufferFragmentsMetric.internalValue=3; + bufferFragmentsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(8000.1 * 8 / 1000 , recommendation.bitrate); + assertEquals((1 + 0.9) / (1 + 0.9 + 0.9*0.9 ), recommendation.confidence); + } + + + [Test] + public function testBandwidthBufferRuleValidActualBitrateMetricRecommendedLessThanActualAndBufferHasMoreFragments():void + { + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BufferBandwidthRule(metricRepository, generateWeights(1,0.9, 0.9*0.9), 3 ); + + //actualbitrate metric return valid, currentstatus and available quality return valid + // to simulate a correct super call + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=2; + fragmentCountMetric.returnValid=true; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=true; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + bufferFragmentsMetric.internalValue=4; + bufferFragmentsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(501, recommendation.bitrate); + assertEquals((1 + 0.9) / (1 + 0.9 + 0.9*0.9 ), recommendation.confidence); + } + + [Test] + public function testBandwidthBufferRuleInvalidActualBitrateMetricRecommendedLessThanActualAndBufferHasFragments():void + { + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BufferBandwidthRule(metricRepository, generateWeights(1,0.9, 0.9*0.9), 3 ); + + //actualbitrate metric return valid, currentstatus and available quality return valid + // to simulate a correct super call + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=2; + fragmentCountMetric.returnValid=true; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=false; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(3); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + bufferFragmentsMetric.internalValue=3; + bufferFragmentsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(8000.1/1000*8, recommendation.bitrate); + assertEquals((1 + 0.9) / (1 + 0.9 + 0.9*0.9 ), recommendation.confidence); + } + + [Test] + public function testBandwidthBufferRuleValidMetricRecommendedLessThanActualAndBufferDoesNotHaveFragments():void + { + + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BufferBandwidthRule(metricRepository, generateWeights(1,0.9, 0.9*0.9), 3 ); + + //actualbitrate metric return valid, currentstatus and available quality return valid + // to simulate a correct super call + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=2; + fragmentCountMetric.returnValid=true; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=true; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + bufferFragmentsMetric.internalValue=1; + bufferFragmentsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(8000.1/1000*8, recommendation.bitrate); + assertEquals((1 + 0.9) / (1 + 0.9 + 0.9*0.9 ), recommendation.confidence); + + } + + + [Test] + public function testBandwidthBufferRuleValidMetricRecommendedLessThanActualAndBufferFragmentMetricIsInvalid():void + { + + //create metric needed by specific rule + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + rule = new BufferBandwidthRule(metricRepository, generateWeights(1,0.9, 0.9*0.9), 3 ); + + //actualbitrate metric return valid, currentstatus and available quality return valid + // to simulate a correct super call + + bandwidthMetric.internalValue=8000.1; + bandwidthMetric.returnValid=true; + + fragmentCountMetric.internalValue=2; + fragmentCountMetric.returnValid=true; + + actualBitrateMetric.internalValue=501; + actualBitrateMetric.returnValid=true; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + bufferFragmentsMetric.internalValue=1; + bufferFragmentsMetric.returnValid=false; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(8000.1 * 8 / 1000, recommendation.bitrate); + assertEquals((1 + 0.9) / (1 + 0.9 + 0.9*0.9 ), recommendation.confidence); + + } + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + private var rule:BufferBandwidthRule; + + //metrics for super + private var bandwidthMetric:BandwidthMetricMocker; + private var fragmentCountMetric:FragmentCountMetricMocker; + private var bufferFragmentsMetric:BufferFragmentsMetricMocker; + + private var actualBitrateMetric:ActualBitrateMetricMocker; + private var currentStatusMetric:CurrentStatusMetricMocker; + private var availableQualityLevelsMetric:AvailableQualityLevelsMetricMocker; + + + + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + private var metricFactory:MetricFactory; + private var metricRepository:MetricRepository; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestDroppedFPSRule.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestDroppedFPSRule.as new file mode 100644 index 0000000..634f180 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestDroppedFPSRule.as @@ -0,0 +1,536 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.rules +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.asserts.assertEquals; + import org.osmf.net.metrics.ActualBitrateMetricMocker; + import org.osmf.net.metrics.AvailableQualityLevelsMetric; + import org.osmf.net.metrics.AvailableQualityLevelsMetricMocker; + import org.osmf.net.metrics.CurrentStatusMetric; + import org.osmf.net.metrics.CurrentStatusMetricMocker; + import org.osmf.net.metrics.DefaultMetricFactoryMocker; + import org.osmf.net.metrics.DroppedFPSMetricMocker; + import org.osmf.net.metrics.FPSMetricMocker; + import org.osmf.net.metrics.MetricFactory; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.metrics.MetricType; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestDroppedFPSRule + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + var qosInfoHistory:QoSInfoHistory = new QoSInfoHistory(netStream); + var metricFactory:DefaultMetricFactoryMocker = new DefaultMetricFactoryMocker(qosInfoHistory) + metricRepository = new MetricRepository(metricFactory); + + droppedFPSMetric = metricRepository.getMetric(MetricType.DROPPED_FPS, DESIRED_SAMPLE_LENGTH) as DroppedFPSMetricMocker; + fpsMetric = metricRepository.getMetric(MetricType.FPS) as FPSMetricMocker; + availableQualityLevelsMetric = metricRepository.getMetric(MetricType.AVAILABLE_QUALITY_LEVELS) as AvailableQualityLevelsMetricMocker; + + actualBitrateMetric = metricRepository.getMetric(MetricType.ACTUAL_BITRATE) as ActualBitrateMetricMocker; + currentStatusMetric = metricRepository.getMetric(MetricType.CURRENT_STATUS) as CurrentStatusMetricMocker; + } + + [After] + public function tearDown():void + { + currentStatusMetric = null; + droppedFPSMetric = null; + metricRepository = null; + netStream = null; + } + + [Test(expects="ArgumentError")] + public function testInitInvalidMaximumDroppedFPSRatioNaN():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, 5, Number.NaN); + } + + [Test(expects="ArgumentError")] + public function testInitInvalidMaximumDroppedFPSRatioLessThanZero():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, 5, -0.1); + } + + [Test(expects="ArgumentError")] + public function testInitInvalidMaximumDroppedFPSRatioOverOne():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, 5, 1.1); + } + + [Test(expects="ArgumentError")] + public function testInitInvalidDesiredSampleLengthNaN():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, NaN, 0.1); + } + + [Test(expects="ArgumentError")] + public function testInitInvalidDesiredSampleLengthLessThanZero():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, -1, 0.1); + } + + [Test(expects="ArgumentError")] + public function testInitInvalidInvalidDesiredSampleLengthZero():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, 0, 1.1); + } + + [Test] + public function testDroppedFPSRuleInit():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + assertEquals(DESIRED_SAMPLE_LENGTH, dfpsRule.desiredSampleLength); + assertEquals(0.2, dfpsRule.maximumDroppedFPSRatio); + } + + + [Test] + public function testDroppedFPSRuleGetRecommendationValidMetric():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 - 0.01; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals((29.7 * 0.2 - 0.01) / (29.7*0.2), recommendation.confidence); + assertEquals(433.3 * (1 - (29.7 * 0.2 - 0.01) / 29.7) , recommendation.bitrate); //actualBitrate * (1 - droppedFPS / fps); + } + + [Test] + public function testDroppedFPSRuleGetRecommendationValidMetricLowFPS():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 + 0.01; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(1, recommendation.confidence); + assertEquals(433.3 * (1 - (29.7 * 0.2 + 0.01) / 29.7) , recommendation.bitrate); //actualBitrate * (1 - droppedFPS / fps); + } + + [Test] + public function testDroppedFPSRuleGetRecommendationValidMetricRatioZero():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 0; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(0, recommendation.confidence); + assertEquals(0, recommendation.bitrate); //actualBitrate * (1 - droppedFPS / fps); + } + + [Test] + public function testDroppedFPSRuleGetRecommendationValidMetricBorderFPS():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 ; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(1, recommendation.confidence); + assertEquals(433.3 * (1 - (29.7 * 0.2) / 29.7) , recommendation.bitrate); //actualBitrate * (1 - droppedFPS / fps); + + } + + + [Test] + public function testDroppedFPSRuleGetRecommendationCurrentIndexDifferentFromActualIndex():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(1); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 ; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(0, recommendation.confidence); + assertEquals(0, recommendation.bitrate); //actualBitrate * (1 - droppedFPS / fps); + + } + + [Test] + public function testDroppedFPSRuleGetRecommendationInvalidActualBitrateMetric():void + { + //valid current status and available quality metrics + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = false; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 + 0.01; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(1, recommendation.confidence); + assertEquals(350 * (1 - (29.7 * 0.2 + 0.01) / 29.7) , recommendation.bitrate); + } + + [Test] + public function testDroppedFPSRuleGetRecommendationInvalidCurrentStatusMetric():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = false; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 + 0.01; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(0, recommendation.confidence); + assertEquals(0, recommendation.bitrate); + } + + [Test] + public function testDroppedFPSRuleGetRecommendationInvalidFPSMetric():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = false; + + droppedFPSMetric.internalValue = 29.7 * 0.2 + 0.01; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(0, recommendation.confidence); + assertEquals(0 , recommendation.bitrate); + } + + [Test] + public function testDroppedFPSRuleGetRecommendationInvalidDroppedFPSMetric():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 + 0.01; + droppedFPSMetric.returnValid = false; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(0, recommendation.confidence); + assertEquals(0 , recommendation.bitrate); + } + + + //todo + [Test] + public function testDroppedFPSRuleGetRecommendationInvalidCurrentStatusMetricAndActualBitrate():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = false; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = false; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 + 0.01; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(0, recommendation.confidence); + assertEquals(0, recommendation.bitrate); + } + + //todo + [Test] + public function testDroppedFPSRuleGetRecommendationInvalidActualBitrateAndAvailableQualityLevelMetric():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = false; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=false; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.7 * 0.2 + 0.01; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(0, recommendation.confidence); + assertEquals(0, recommendation.bitrate); + } + + + + [Test] + public function testDroppedFPSRuleGetRecommendationMoreDroppedFramesThanMax():void + { + var dfpsRule:DroppedFPSRule = new DroppedFPSRule(metricRepository, DESIRED_SAMPLE_LENGTH, 0.2); + + actualBitrateMetric.internalValue = 433.3; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + fpsMetric.internalValue = 29.7; + fpsMetric.returnValid = true; + + droppedFPSMetric.internalValue = 29.71; + droppedFPSMetric.returnValid = true; + + var recommendation:Recommendation = dfpsRule.getRecommendation(); + assertEquals(RuleType.DROPPED_FPS, recommendation.ruleType); + assertEquals(1, recommendation.confidence); + assertEquals(0 , recommendation.bitrate); //actualBitrate * (1 - droppedFPS / fps); + } + + private var droppedFPSMetric:DroppedFPSMetricMocker; + private var fpsMetric:FPSMetricMocker; + private var currentStatusMetric:CurrentStatusMetricMocker; + private var actualBitrateMetric:ActualBitrateMetricMocker; + private var availableQualityLevelsMetric:AvailableQualityLevelsMetricMocker; + + + private var netStream:NetStream; + private var metricRepository:MetricRepository; + + private static const DESIRED_SAMPLE_LENGTH:Number = 5; + private static const DESIRED_RATIO:Number = 0.1; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestEmptyBufferRule.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestEmptyBufferRule.as new file mode 100644 index 0000000..622ec92 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestEmptyBufferRule.as @@ -0,0 +1,362 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.rules +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.Assert; + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.net.metrics.ActualBitrateMetric; + import org.osmf.net.metrics.ActualBitrateMetricMocker; + import org.osmf.net.metrics.AvailableQualityLevelsMetric; + import org.osmf.net.metrics.AvailableQualityLevelsMetricMocker; + import org.osmf.net.metrics.BandwidthMetric; + import org.osmf.net.metrics.BandwidthMetricMocker; + import org.osmf.net.metrics.BufferFragmentsMetric; + import org.osmf.net.metrics.BufferFragmentsMetricMocker; + import org.osmf.net.metrics.CurrentStatusMetric; + import org.osmf.net.metrics.CurrentStatusMetricMocker; + import org.osmf.net.metrics.DefaultMetricFactory; + import org.osmf.net.metrics.DefaultMetricFactoryMocker; + import org.osmf.net.metrics.EmptyBufferMetricMocker; + import org.osmf.net.metrics.FragmentCountMetric; + import org.osmf.net.metrics.FragmentCountMetricMocker; + import org.osmf.net.metrics.MetricFactory; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.metrics.MetricType; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestEmptyBufferRule + { + [Before] + public function setUp():void + { + + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + metricFactory = new DefaultMetricFactoryMocker(qosInfoHistory); + metricRepository = new MetricRepository(metricFactory); + + + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + fragmentCountMetric = metricRepository.getMetric(MetricType.FRAGMENT_COUNT) as FragmentCountMetricMocker; + bufferFragmentsMetric = metricRepository.getMetric(MetricType.BUFFER_FRAGMENTS) as BufferFragmentsMetricMocker; + + actualBitrateMetric = metricRepository.getMetric(MetricType.ACTUAL_BITRATE) as ActualBitrateMetricMocker; + bufferFragmentsMetric = metricRepository.getMetric(MetricType.BUFFER_FRAGMENTS) as BufferFragmentsMetricMocker; + availableQualityLevelsMetric = metricRepository.getMetric(MetricType.AVAILABLE_QUALITY_LEVELS) as AvailableQualityLevelsMetricMocker; + currentStatusMetric = metricRepository.getMetric(MetricType.CURRENT_STATUS) as CurrentStatusMetricMocker; + emptyBufferInterruptionMetric = metricRepository.getMetric(MetricType.EMPTY_BUFFER) as EmptyBufferMetricMocker; + + } + + [After] + public function tearDown():void + { + + bandwidthMetric = null; + + fragmentCountMetric = null; + bufferFragmentsMetric = null; + + actualBitrateMetric = null; + bufferFragmentsMetric = null; + availableQualityLevelsMetric = null; + currentStatusMetric = null; + emptyBufferInterruptionMetric = null; + + metricRepository = null; + metricFactory = null; + qosInfoHistory = null; + netStream = null; + + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testEmptyBufferInterruptionRuleInit():void + { + rule = new EmptyBufferRule(metricRepository, 0.4); + assertEquals(0.4, rule.scaleDownFactor); + } + + [Test(expects="ArgumentError")] + public function testEmptyBufferInterruptionRuleInitNaN():void + { + rule = new EmptyBufferRule(metricRepository, NaN); + } + + [Test(expects="ArgumentError")] + public function testEmptyBufferInterruptionRuleInitGreaterThanOne():void + { + rule = new EmptyBufferRule(metricRepository, 1.01); + } + + [Test(expects="ArgumentError")] + public function testEmptyBufferInterruptionRuleInitNegative():void + { + rule = new EmptyBufferRule(metricRepository, -0.1); + } + + [Test] + public function testEmptyBufferInterruptionRuleInitOne():void + { + rule = new EmptyBufferRule(metricRepository, 1); + assertEquals(1, rule.scaleDownFactor); + + } + + [Test] + public function testEmptyBufferInterruptionRuleInitZero():void + { + rule = new EmptyBufferRule(metricRepository, 0); + assertEquals(0, rule.scaleDownFactor); + + } + + [Test] + public function testEmptyBufferInterruptionRuleSet_scaleDownFactor():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + rule.scaleDownFactor = 0.8; + assertEquals(0.8, rule.scaleDownFactor); + rule.scaleDownFactor = 0; + assertEquals(0, rule.scaleDownFactor); + rule.scaleDownFactor = 1; + assertEquals(1, rule.scaleDownFactor); + } + + [Test(expects = "ArgumentError")] + public function testEmptyBufferInterruptionRuleSet_scaleDownFactorNaN():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + rule.scaleDownFactor = NaN; + } + + [Test(expects = "ArgumentError")] + public function testEmptyBufferInterruptionRuleSet_scaleDownFactorNegative():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + rule.scaleDownFactor = -0.1; + } + + [Test(expects = "ArgumentError")] + public function testEmptyBufferInterruptionRuleSet_scaleDownFactorGreaterThanOne():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + rule.scaleDownFactor = 1.1; + } + + + + [Test] + public function testEmptyBufferInterruptionRule_GetRecommendation_InvalidEmptyBufferInterruptMetric():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + + emptyBufferInterruptionMetric = metricRepository.getMetric(MetricType.EMPTY_BUFFER) as EmptyBufferMetricMocker; + emptyBufferInterruptionMetric.returnValid=false; + emptyBufferInterruptionMetric.internalValue=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.EMPTY_BUFFER, recommendation.ruleType); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testEmptyBufferInterruptionRule_GetRecommendation_FalseEmptyBufferInterruptMetric():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + + emptyBufferInterruptionMetric = metricRepository.getMetric(MetricType.EMPTY_BUFFER) as EmptyBufferMetricMocker; + emptyBufferInterruptionMetric.returnValid=true; + emptyBufferInterruptionMetric.internalValue=false; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.EMPTY_BUFFER, recommendation.ruleType); + assertEquals(0, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + } + + [Test] + public function testEmptyBufferInterruptionRule_GetRecommendation_TrueEmptyBufferInterruptMetric_ValidActualBitrate():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + + emptyBufferInterruptionMetric = metricRepository.getMetric(MetricType.EMPTY_BUFFER) as EmptyBufferMetricMocker; + emptyBufferInterruptionMetric.returnValid=true; + emptyBufferInterruptionMetric.internalValue=true; + + actualBitrateMetric.returnValid=true; + actualBitrateMetric.internalValue=333; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.EMPTY_BUFFER, recommendation.ruleType); + assertEquals(333*0.5, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + } + + [Test] + public function testEmptyBufferInterruptionRule_GetRecommendation_EmptyBuffer_InvalidActualBitrate_ValidCurrent_ValidAvailableQuality():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + + emptyBufferInterruptionMetric = metricRepository.getMetric(MetricType.EMPTY_BUFFER) as EmptyBufferMetricMocker; + emptyBufferInterruptionMetric.returnValid=true; + emptyBufferInterruptionMetric.internalValue=true; + + actualBitrateMetric.returnValid=false; + actualBitrateMetric.internalValue=333; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(3); + currentStatusMetric.internalValue.push(3); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + var i:int; + for(i=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.EMPTY_BUFFER, recommendation.ruleType); + assertEquals(450*0.5, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + } + + [Test] + public function testEmptyBufferInterruptionRule_GetRecommendation_EmptyBuffer_InvalidActualBitrate_InvalidCurrent_ValidAvailableQuality():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + + emptyBufferInterruptionMetric = metricRepository.getMetric(MetricType.EMPTY_BUFFER) as EmptyBufferMetricMocker; + emptyBufferInterruptionMetric.returnValid=true; + emptyBufferInterruptionMetric.internalValue=true; + + actualBitrateMetric.returnValid=false; + actualBitrateMetric.internalValue=333; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(3); + currentStatusMetric.internalValue.push(3); + currentStatusMetric.returnValid=false; + + availableQualityLevelsMetric.internalValue = new Vector.(); + var i:int; + for(i=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=true; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.EMPTY_BUFFER, recommendation.ruleType); + assertEquals(0, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + } + + [Test] + public function testEmptyBufferInterruptionRule_GetRecommendation_EmptyBuffer_InvalidActualBitrate_ValidCurrent_InvalidAvailableQuality():void + { + rule = new EmptyBufferRule(metricRepository, 0.5); + + emptyBufferInterruptionMetric = metricRepository.getMetric(MetricType.EMPTY_BUFFER) as EmptyBufferMetricMocker; + emptyBufferInterruptionMetric.returnValid=true; + emptyBufferInterruptionMetric.internalValue=true; + + actualBitrateMetric.returnValid=false; + actualBitrateMetric.internalValue=333; + + currentStatusMetric.internalValue=new Vector.(); + currentStatusMetric.internalValue.push(3); + currentStatusMetric.internalValue.push(3); + currentStatusMetric.returnValid=true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + var i:int; + for(i=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid=false; + + var recommendation:Recommendation = rule.getRecommendation(); + assertEquals(RuleType.EMPTY_BUFFER, recommendation.ruleType); + assertEquals(0, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + } + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + private var rule:EmptyBufferRule; + + //metrics for super + private var bandwidthMetric:BandwidthMetricMocker; + private var fragmentCountMetric:FragmentCountMetricMocker; + private var bufferFragmentsMetric:BufferFragmentsMetricMocker; + + private var actualBitrateMetric:ActualBitrateMetricMocker; + private var currentStatusMetric:CurrentStatusMetricMocker; + private var availableQualityLevelsMetric:AvailableQualityLevelsMetricMocker; + private var emptyBufferInterruptionMetric:EmptyBufferMetricMocker; + + + + + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + private var metricFactory:MetricFactory; + private var metricRepository:MetricRepository; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestRecommendation.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestRecommendation.as new file mode 100644 index 0000000..2dabaf6 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestRecommendation.as @@ -0,0 +1,128 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.rules +{ + import flexunit.framework.Assert; + + import org.flexunit.asserts.assertEquals; + + public class TestRecommendation + { + [Before] + public function setUp():void + { + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testGet():void + { + recommendation = new Recommendation(RULE_TYPE, 467.8, 0.88); + assertEquals(RULE_TYPE, recommendation.ruleType); + assertEquals(467.8, recommendation.bitrate); + assertEquals(0.88, recommendation.confidence); + } + + + [Test] + public function testRecommendationInitValidConfidence():void + { + recommendation = new Recommendation(RULE_TYPE, 467.8, 0); + assertEquals(RULE_TYPE, recommendation.ruleType); + assertEquals(467.8, recommendation.bitrate); + assertEquals(0, recommendation.confidence); + + recommendation = new Recommendation(RULE_TYPE, 467.8, 1); + assertEquals(467.8, recommendation.bitrate); + assertEquals(1, recommendation.confidence); + + recommendation = new Recommendation(RULE_TYPE, 467.8, 0.2); + assertEquals(467.8, recommendation.bitrate); + assertEquals(0.2, recommendation.confidence); + } + + [Test] + public function testRecommendationInitValidBitrate():void + { + recommendation = new Recommendation(RULE_TYPE, 0, 0.5); + assertEquals(0, recommendation.bitrate); + assertEquals(0.5, recommendation.confidence); + + recommendation = new Recommendation(RULE_TYPE, 467, 0.5); + assertEquals(467, recommendation.bitrate); + assertEquals(0.5, recommendation.confidence); + + recommendation = new Recommendation(RULE_TYPE, 467.8, 0.5); + assertEquals(467.8, recommendation.bitrate); + assertEquals(0.5, recommendation.confidence); + } + + [Test(expects="ArgumentError")] + public function testRecommendationInvalidConfidenceNaN():void + { + recommendation = new Recommendation(RULE_TYPE, 400, Number.NaN); + } + [Test(expects="ArgumentError")] + public function testRecommendationInvalidConfidenceNegative():void + { + recommendation = new Recommendation(RULE_TYPE, 400, -0.1); + } + [Test(expects="ArgumentError")] + public function testRecommendationInvalidConfidenceOverOne():void + { + recommendation = new Recommendation(RULE_TYPE, 400, 1.1); + } + + [Test(expects="ArgumentError")] + public function testRecommendationInvalidBitrateNegative():void + { + recommendation = new Recommendation(RULE_TYPE, -0.1, 0.5); + } + [Test(expects="ArgumentError")] + public function testRecommendationInvalidBitrateNaN():void + { + recommendation = new Recommendation(RULE_TYPE, Number.NaN, 0.5); + } + [Test(expects="ArgumentError")] + public function testRecommendationInvalidRuleType():void + { + recommendation = new Recommendation(null, 400, 0.5); + } + + private var recommendation:Recommendation; + private static const RULE_TYPE:String = "sample_rule_type"; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestRuleUtils.as b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestRuleUtils.as new file mode 100644 index 0000000..53c6109 --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/net/rules/TestRuleUtils.as @@ -0,0 +1,212 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net.rules +{ + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertTrue; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.net.metrics.ActualBitrateMetric; + import org.osmf.net.metrics.ActualBitrateMetricMocker; + import org.osmf.net.metrics.AvailableQualityLevelsMetric; + import org.osmf.net.metrics.AvailableQualityLevelsMetricMocker; + import org.osmf.net.metrics.BandwidthMetric; + import org.osmf.net.metrics.BandwidthMetricMocker; + import org.osmf.net.metrics.BufferFragmentsMetric; + import org.osmf.net.metrics.BufferFragmentsMetricMocker; + import org.osmf.net.metrics.CurrentStatusMetric; + import org.osmf.net.metrics.CurrentStatusMetricMocker; + import org.osmf.net.metrics.DefaultMetricFactory; + import org.osmf.net.metrics.DefaultMetricFactoryMocker; + import org.osmf.net.metrics.FragmentCountMetric; + import org.osmf.net.metrics.FragmentCountMetricMocker; + import org.osmf.net.metrics.MetricFactory; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.metrics.MetricType; + import org.osmf.net.qos.QoSInfo; + import org.osmf.net.qos.QoSInfoHistory; + import org.osmf.net.qos.QualityLevel; + + public class TestRuleUtils + { + [Before] + public function setUp():void + { + var conn:NetConnection = new NetConnection(); + conn.connect(null); + netStream = new NetStream(conn); + qosInfoHistory = new QoSInfoHistory(netStream); + metricFactory = new DefaultMetricFactoryMocker(qosInfoHistory); + metricRepository = new MetricRepository(metricFactory); + + + bandwidthMetric = metricRepository.getMetric(MetricType.BANDWIDTH, generateWeights(1,0.9, 0.9*0.9) ) as BandwidthMetricMocker; + + fragmentCountMetric = metricRepository.getMetric(MetricType.FRAGMENT_COUNT) as FragmentCountMetricMocker; + bufferFragmentsMetric = metricRepository.getMetric(MetricType.BUFFER_FRAGMENTS) as BufferFragmentsMetricMocker; + + actualBitrateMetric = metricRepository.getMetric(MetricType.ACTUAL_BITRATE) as ActualBitrateMetricMocker; + bufferFragmentsMetric = metricRepository.getMetric(MetricType.BUFFER_FRAGMENTS) as BufferFragmentsMetricMocker; + availableQualityLevelsMetric = metricRepository.getMetric(MetricType.AVAILABLE_QUALITY_LEVELS) as AvailableQualityLevelsMetricMocker; + currentStatusMetric = metricRepository.getMetric(MetricType.CURRENT_STATUS) as CurrentStatusMetricMocker; + } + + [After] + public function tearDown():void + { + fragmentCountMetric = null; + bandwidthMetric = null; + metricRepository = null; + metricFactory = null; + qosInfoHistory = null; + netStream = null; + } + + + [Test] + public function testComputeActualBitrateWhenActualBitrateMetricIsValid():void + { + + actualBitrateMetric.internalValue = 846; + actualBitrateMetric.returnValid = true; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid = true; + + var bitrate:Number = RuleUtils.computeActualBitrate(actualBitrateMetric, availableQualityLevelsMetric, currentStatusMetric); + assertEquals(846, bitrate); + } + + + [Test] + public function testComputeActualBitrateWhenActualBitrateMetricIsInvalidAndCurrentStatusIsValidAndAvailableQualityLevelsMetricIsValid():void + { + + actualBitrateMetric.internalValue = 846; + actualBitrateMetric.returnValid = false; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid = true; + + var bitrate:Number = RuleUtils.computeActualBitrate(actualBitrateMetric, availableQualityLevelsMetric, currentStatusMetric); + assertEquals(350, bitrate); + } + + + [Test] + public function testComputeActualBitrateWhenActualBitrateMetricIsInvalidAndCurrentStatusIsInvalidAndAvailableQualityLevelsMetricIsValid():void + { + + actualBitrateMetric.internalValue = 846; + actualBitrateMetric.returnValid = false; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = false; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid = true; + + var bitrate:Number = RuleUtils.computeActualBitrate(actualBitrateMetric, availableQualityLevelsMetric, currentStatusMetric); + assertTrue(isNaN(bitrate)); + } + + [Test] + public function testComputeActualBitrateWhenActualBitrateMetricIsInvalidAndCurrentStatusIsValidAndAvailableQualityLevelsMetricIsInvalid():void + { + + actualBitrateMetric.internalValue = 846; + actualBitrateMetric.returnValid = false; + + currentStatusMetric.internalValue = new Vector.(); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.internalValue.push(2); + currentStatusMetric.returnValid = true; + + availableQualityLevelsMetric.internalValue = new Vector.(); + for(var i:uint=0; i< 5; i++) + { + availableQualityLevelsMetric.internalValue.push( + new QualityLevel( i, 100 * i + 150, "test" + (100 * i + 150) )); + } + availableQualityLevelsMetric.returnValid = false; + + var bitrate:Number = RuleUtils.computeActualBitrate(actualBitrateMetric, availableQualityLevelsMetric, currentStatusMetric); + assertTrue(isNaN(bitrate)); + } + + private function generateWeights(... weights):Vector. + { + var v:Vector. = new Vector.(); + for(var i:uint=0; i< weights.length; i++) + { + v[i] = weights[i] ; + } + return (v); + } + + + //metrics for input + private var bandwidthMetric:BandwidthMetricMocker; + private var fragmentCountMetric:FragmentCountMetricMocker; + private var bufferFragmentsMetric:BufferFragmentsMetricMocker; + + private var actualBitrateMetric:ActualBitrateMetricMocker; + private var currentStatusMetric:CurrentStatusMetricMocker; + private var availableQualityLevelsMetric:AvailableQualityLevelsMetricMocker; + + + + private var qosInfoHistory:QoSInfoHistory; + private var netStream:NetStream; + private var metricFactory:MetricFactory; + private var metricRepository:MetricRepository; + } +} \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestDVRTrait.as b/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestDVRTrait.as index ce5b9f0..91dcf64 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestDVRTrait.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestDVRTrait.as @@ -1,63 +1,63 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.traits -{ - import org.flexunit.Assert; - import org.osmf.events.DVREvent; - - public class TestDVRTrait - { - [Before] - public function setUp():void - { - dvrTrait = createInterfaceObject() as DVRTrait; - } - - [After] - public function tearDown():void - { - } - - [BeforeClass] - public static function setUpBeforeClass():void - { - } - - [AfterClass] - public static function tearDownAfterClass():void - { - } - - protected function createInterfaceObject(...args):Object - { - return new DVRTrait(); - } - - [Test] - public function testIsRecording():void - { - Assert.assertFalse(dvrTrait.isRecording); - } - - private var dvrTrait:DVRTrait; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.traits +{ + import org.flexunit.Assert; + import org.osmf.events.DVREvent; + + public class TestDVRTrait + { + [Before] + public function setUp():void + { + dvrTrait = createInterfaceObject() as DVRTrait; + } + + [After] + public function tearDown():void + { + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + protected function createInterfaceObject(...args):Object + { + return new DVRTrait(); + } + + [Test] + public function testIsRecording():void + { + Assert.assertFalse(dvrTrait.isRecording); + } + + private var dvrTrait:DVRTrait; + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestLoadTrait.as b/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestLoadTrait.as index 4a15225..a43af44 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestLoadTrait.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestLoadTrait.as @@ -176,15 +176,6 @@ package org.osmf.traits loadTrait.load(); } - [Ignore] - [Test(expects="flash.errors.IllegalOperationError")] - public function testUnloadWithInvalidResource():void - { - var loadTrait:LoadTrait = createLoadTrait(unhandledResource); - - loadTrait.unload(); - } - protected final function createLoadTrait(resource:MediaResourceBase=null):LoadTrait { return createInterfaceObject(createLoader(), resource) as LoadTrait; diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestTraitEventDispatcher.as b/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestTraitEventDispatcher.as index 8bc73a0..804a812 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestTraitEventDispatcher.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/traits/TestTraitEventDispatcher.as @@ -1,318 +1,318 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.traits -{ - import __AS3__.vec.Vector; - - import flash.display.Sprite; - import flash.events.Event; - import flash.utils.getDefinitionByName; - import flash.utils.getQualifiedClassName; - - import flexunit.framework.Assert; - - import org.osmf.events.AudioEvent; - import org.osmf.events.BufferEvent; - import org.osmf.events.DRMEvent; - import org.osmf.events.DVREvent; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.events.DynamicStreamEvent; - import org.osmf.events.MediaError; - import org.osmf.events.PlayEvent; - import org.osmf.events.SeekEvent; - import org.osmf.events.TimeEvent; - import org.osmf.utils.DynamicMediaElement; - - public class TestTraitEventDispatcher - { - [Before] - public function setUp():void - { - caughtEvents = new Vector.(); - dispatcher = new TraitEventDispatcher(); - } - - [After] - public function tearDown():void - { - dispatcher = null - } - - [BeforeClass] - public static function setUpBeforeClass():void - { - } - - [AfterClass] - public static function tearDownAfterClass():void - { - } - - [Test] - public function testWithoutElement():void - { - //Test Trait events without a mediaElement. - dispatcher.addEventListener(AudioEvent.MUTED_CHANGE, catchEvents); - dispatcher.removeEventListener(AudioEvent.MUTED_CHANGE, catchEvents); - - //Test Non-trait events - dispatcher.addEventListener(Event.ENTER_FRAME, catchEvents); - - dispatcher.dispatchEvent(new Event(Event.ENTER_FRAME)); - - Assert.assertEquals(1, caughtEvents.length); - Assert.assertEquals(Event.ENTER_FRAME, caughtEvents[0].type); - - dispatcher.removeEventListener(Event.ENTER_FRAME, catchEvents); - - dispatcher.dispatchEvent(new Event(Event.ENTER_FRAME)); - - Assert.assertEquals(1, caughtEvents.length); - - } - - - private function testWithElement(events:Vector., properties:Vector., traitType:String):void - { - var itr:Number = 0; - var itr2:Number = 0; - - for (itr = 0; itr < events.length; itr++) - { - dispatcher.addEventListener(events[itr].type, catchEvents); - } - - var media:DynamicMediaElement = new DynamicMediaElement([traitType], null, null, true); - dispatcher.media = media; - - - var trait:MediaTraitBase = media.getTrait(traitType) ; - - for (itr = 0; itr < events.length; itr++) - { - trait.dispatchEvent(events[itr]); - } - - Assert.assertEquals(events.length, caughtEvents.length); - - for (itr = 0; itr < events.length; itr++) - { - Assert.assertEquals(caughtEvents[itr].type, events[itr].type ); - Assert.assertTrue(caughtEvents[itr] is (getDefinitionByName(getQualifiedClassName(events[itr])) as Class) ); - for (itr2 = 0; itr2 < properties.length; itr2++) - { - Assert.assertEquals(events[itr][properties[itr2]], caughtEvents[itr][properties[itr2]]); - } - } - - //Negative case - no events dispatched - - DynamicMediaElement(dispatcher.media).doRemoveTrait(traitType); - - for (itr = 0; itr < events.length; itr++) - { - trait.dispatchEvent(events[itr]); - } - - Assert.assertEquals(events.length, caughtEvents.length); - - //Now Readd - media.doAddTrait(traitType, trait); - //But remove the element - dispatcher.media = null; - - for (itr = 0; itr < events.length; itr++) - { - trait.dispatchEvent(events[itr]); - } - - Assert.assertEquals(events.length, caughtEvents.length); - - dispatcher.media = media; - - //clear out the events: - caughtEvents.splice(0, caughtEvents.length); - - for (itr = 0; itr < events.length; itr++) - { - trait.dispatchEvent(events[itr]); - } - - Assert.assertEquals(events.length, caughtEvents.length); - for (itr = 0; itr < events.length; itr++) - { - Assert.assertTrue(caughtEvents[itr] is (getDefinitionByName(getQualifiedClassName(events[itr])) as Class) ); - Assert.assertEquals(caughtEvents[itr].type, events[itr].type ); - for (itr2 = 0; itr2 < properties.length; itr2++) - { - Assert.assertEquals(events[itr][properties[itr2]], caughtEvents[itr][properties[itr2]]); - } - } - - } - - [Test] - public function testAudioEvents():void - { - var muteEvent:AudioEvent = new AudioEvent(AudioEvent.MUTED_CHANGE, false, false, true, 0, 0); - var volumeEvent:AudioEvent = new AudioEvent(AudioEvent.VOLUME_CHANGE, false, false, false, .2, 0); - var panEvent:AudioEvent = new AudioEvent(AudioEvent.PAN_CHANGE, false, false, true, 0, -.2); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(muteEvent,volumeEvent,panEvent); - properties.push("muted","volume","pan"); - - testWithElement(events, properties, MediaTraitType.AUDIO); - } - - [Test] - public function testDisplayObjectEvents():void - { - var event1:DisplayObjectEvent = new DisplayObjectEvent(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, false, false, new Sprite(), new Sprite(), 150, 150, 300, 500); - var event2:DisplayObjectEvent = new DisplayObjectEvent(DisplayObjectEvent.MEDIA_SIZE_CHANGE, false, false, new Sprite(), new Sprite(), 100, 100, 200, 200); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(event1,event2); - - properties.push("newDisplayObject", "oldDisplayObject", "oldWidth", "oldHeight", "newHeight", "newWidth"); - - testWithElement(events, properties, MediaTraitType.DISPLAY_OBJECT); - } - - [Test] - public function testBufferEvents():void - { - var event1:BufferEvent = new BufferEvent(BufferEvent.BUFFER_TIME_CHANGE, false, false, true, 200); - var event2:BufferEvent = new BufferEvent(BufferEvent.BUFFERING_CHANGE, false, false, false, 100); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(event1,event2); - var ev:BufferEvent; - properties.push("buffering", "bufferTime"); - - testWithElement(events, properties, MediaTraitType.BUFFER); - } - - [Test] - public function testSeekEvents():void - { - var event1:SeekEvent = new SeekEvent(SeekEvent.SEEKING_CHANGE, false, false, true, 12); - var event2:SeekEvent = new SeekEvent(SeekEvent.SEEKING_CHANGE, false, false, false, 15 ); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(event1,event2); - - properties.push("time"); - - testWithElement(events, properties, MediaTraitType.SEEK); - } - - [Test] - public function testPlayEvents():void - { - var event1:PlayEvent = new PlayEvent(PlayEvent.CAN_PAUSE_CHANGE, false, false, PlayState.PAUSED, false); - var event2:PlayEvent = new PlayEvent(PlayEvent.PLAY_STATE_CHANGE, false, false, PlayState.PLAYING, true ); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(event1,event2); - - properties.push("playState", "canPause"); - - testWithElement(events, properties, MediaTraitType.PLAY); - } - - [Test] - public function testTimeEvents():void - { - var event1:TimeEvent = new TimeEvent(TimeEvent.COMPLETE, false, false, 3); - //Trait doesn't dispatch this, but MP does - //var event2:TimeEvent = new TimeEvent(TimeEvent.CURRENT_TIME_CHANGE, false, false, 1 ); - var event3:TimeEvent = new TimeEvent(TimeEvent.DURATION_CHANGE, false, false, 3 ); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(event1,event3); - - properties.push("time"); - - testWithElement(events, properties, MediaTraitType.TIME); - } - - [Test] - public function testDRMEvents():void - { - var event1:DRMEvent = new DRMEvent(DRMEvent.DRM_STATE_CHANGE, DRMState.AUTHENTICATION_COMPLETE, false, false, new Date(1), new Date(2), 4, "server1", null, null ); - var event2:DRMEvent = new DRMEvent(DRMEvent.DRM_STATE_CHANGE, DRMState.AUTHENTICATING, false, false, new Date(8), new Date(9), 4, "server1", null, null ); - var event3:DRMEvent = new DRMEvent(DRMEvent.DRM_STATE_CHANGE, DRMState.AUTHENTICATION_NEEDED, false, false, new Date(11), new Date(12), 4, "server1", null, null ); - var event4:DRMEvent = new DRMEvent(DRMEvent.DRM_STATE_CHANGE, DRMState.AUTHENTICATION_ERROR, false, false, new Date(11), new Date(12), 4, "server1", null, new MediaError(1, "detail") ); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(event1,event2, event3, event4); - - properties.push("drmState", "mediaError", "endDate", "period", "serverURL", "startDate", "token"); - - testWithElement(events, properties, MediaTraitType.DRM); - } - - [Test] - public function testDVREvents():void - { - var event1:DVREvent = new DVREvent(DVREvent.IS_RECORDING_CHANGE); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(event1); - - testWithElement(events, properties, MediaTraitType.DVR); - } - - [Test] - public function testDynamicStreamEvents():void - { - var event1:DynamicStreamEvent = new DynamicStreamEvent(DynamicStreamEvent.AUTO_SWITCH_CHANGE, false, false, false, false); - var event2:DynamicStreamEvent = new DynamicStreamEvent(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, false, false, false, true ); - var event3:DynamicStreamEvent = new DynamicStreamEvent(DynamicStreamEvent.SWITCHING_CHANGE, false, false, true, true ); - - var events:Vector. = new Vector.(); - var properties:Vector. = new Vector.(); - events.push(event1, event2, event3); - - properties.push("autoSwitch", "switching"); - - testWithElement(events, properties, MediaTraitType.DYNAMIC_STREAM); - } - - private function catchEvents(event:Event):void - { - caughtEvents.push(event); - } - - private var caughtEvents:Vector.; - private var dispatcher:TraitEventDispatcher; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.traits +{ + import __AS3__.vec.Vector; + + import flash.display.Sprite; + import flash.events.Event; + import flash.utils.getDefinitionByName; + import flash.utils.getQualifiedClassName; + + import flexunit.framework.Assert; + + import org.osmf.events.AudioEvent; + import org.osmf.events.BufferEvent; + import org.osmf.events.DRMEvent; + import org.osmf.events.DVREvent; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.events.DynamicStreamEvent; + import org.osmf.events.MediaError; + import org.osmf.events.PlayEvent; + import org.osmf.events.SeekEvent; + import org.osmf.events.TimeEvent; + import org.osmf.utils.DynamicMediaElement; + + public class TestTraitEventDispatcher + { + [Before] + public function setUp():void + { + caughtEvents = new Vector.(); + dispatcher = new TraitEventDispatcher(); + } + + [After] + public function tearDown():void + { + dispatcher = null + } + + [BeforeClass] + public static function setUpBeforeClass():void + { + } + + [AfterClass] + public static function tearDownAfterClass():void + { + } + + [Test] + public function testWithoutElement():void + { + //Test Trait events without a mediaElement. + dispatcher.addEventListener(AudioEvent.MUTED_CHANGE, catchEvents); + dispatcher.removeEventListener(AudioEvent.MUTED_CHANGE, catchEvents); + + //Test Non-trait events + dispatcher.addEventListener(Event.ENTER_FRAME, catchEvents); + + dispatcher.dispatchEvent(new Event(Event.ENTER_FRAME)); + + Assert.assertEquals(1, caughtEvents.length); + Assert.assertEquals(Event.ENTER_FRAME, caughtEvents[0].type); + + dispatcher.removeEventListener(Event.ENTER_FRAME, catchEvents); + + dispatcher.dispatchEvent(new Event(Event.ENTER_FRAME)); + + Assert.assertEquals(1, caughtEvents.length); + + } + + + private function testWithElement(events:Vector., properties:Vector., traitType:String):void + { + var itr:Number = 0; + var itr2:Number = 0; + + for (itr = 0; itr < events.length; itr++) + { + dispatcher.addEventListener(events[itr].type, catchEvents); + } + + var media:DynamicMediaElement = new DynamicMediaElement([traitType], null, null, true); + dispatcher.media = media; + + + var trait:MediaTraitBase = media.getTrait(traitType) ; + + for (itr = 0; itr < events.length; itr++) + { + trait.dispatchEvent(events[itr]); + } + + Assert.assertEquals(events.length, caughtEvents.length); + + for (itr = 0; itr < events.length; itr++) + { + Assert.assertEquals(caughtEvents[itr].type, events[itr].type ); + Assert.assertTrue(caughtEvents[itr] is (getDefinitionByName(getQualifiedClassName(events[itr])) as Class) ); + for (itr2 = 0; itr2 < properties.length; itr2++) + { + Assert.assertEquals(events[itr][properties[itr2]], caughtEvents[itr][properties[itr2]]); + } + } + + //Negative case - no events dispatched + + DynamicMediaElement(dispatcher.media).doRemoveTrait(traitType); + + for (itr = 0; itr < events.length; itr++) + { + trait.dispatchEvent(events[itr]); + } + + Assert.assertEquals(events.length, caughtEvents.length); + + //Now Readd + media.doAddTrait(traitType, trait); + //But remove the element + dispatcher.media = null; + + for (itr = 0; itr < events.length; itr++) + { + trait.dispatchEvent(events[itr]); + } + + Assert.assertEquals(events.length, caughtEvents.length); + + dispatcher.media = media; + + //clear out the events: + caughtEvents.splice(0, caughtEvents.length); + + for (itr = 0; itr < events.length; itr++) + { + trait.dispatchEvent(events[itr]); + } + + Assert.assertEquals(events.length, caughtEvents.length); + for (itr = 0; itr < events.length; itr++) + { + Assert.assertTrue(caughtEvents[itr] is (getDefinitionByName(getQualifiedClassName(events[itr])) as Class) ); + Assert.assertEquals(caughtEvents[itr].type, events[itr].type ); + for (itr2 = 0; itr2 < properties.length; itr2++) + { + Assert.assertEquals(events[itr][properties[itr2]], caughtEvents[itr][properties[itr2]]); + } + } + + } + + [Test] + public function testAudioEvents():void + { + var muteEvent:AudioEvent = new AudioEvent(AudioEvent.MUTED_CHANGE, false, false, true, 0, 0); + var volumeEvent:AudioEvent = new AudioEvent(AudioEvent.VOLUME_CHANGE, false, false, false, .2, 0); + var panEvent:AudioEvent = new AudioEvent(AudioEvent.PAN_CHANGE, false, false, true, 0, -.2); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(muteEvent,volumeEvent,panEvent); + properties.push("muted","volume","pan"); + + testWithElement(events, properties, MediaTraitType.AUDIO); + } + + [Test] + public function testDisplayObjectEvents():void + { + var event1:DisplayObjectEvent = new DisplayObjectEvent(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, false, false, new Sprite(), new Sprite(), 150, 150, 300, 500); + var event2:DisplayObjectEvent = new DisplayObjectEvent(DisplayObjectEvent.MEDIA_SIZE_CHANGE, false, false, new Sprite(), new Sprite(), 100, 100, 200, 200); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(event1,event2); + + properties.push("newDisplayObject", "oldDisplayObject", "oldWidth", "oldHeight", "newHeight", "newWidth"); + + testWithElement(events, properties, MediaTraitType.DISPLAY_OBJECT); + } + + [Test] + public function testBufferEvents():void + { + var event1:BufferEvent = new BufferEvent(BufferEvent.BUFFER_TIME_CHANGE, false, false, true, 200); + var event2:BufferEvent = new BufferEvent(BufferEvent.BUFFERING_CHANGE, false, false, false, 100); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(event1,event2); + var ev:BufferEvent; + properties.push("buffering", "bufferTime"); + + testWithElement(events, properties, MediaTraitType.BUFFER); + } + + [Test] + public function testSeekEvents():void + { + var event1:SeekEvent = new SeekEvent(SeekEvent.SEEKING_CHANGE, false, false, true, 12); + var event2:SeekEvent = new SeekEvent(SeekEvent.SEEKING_CHANGE, false, false, false, 15 ); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(event1,event2); + + properties.push("time"); + + testWithElement(events, properties, MediaTraitType.SEEK); + } + + [Test] + public function testPlayEvents():void + { + var event1:PlayEvent = new PlayEvent(PlayEvent.CAN_PAUSE_CHANGE, false, false, PlayState.PAUSED, false); + var event2:PlayEvent = new PlayEvent(PlayEvent.PLAY_STATE_CHANGE, false, false, PlayState.PLAYING, true ); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(event1,event2); + + properties.push("playState", "canPause"); + + testWithElement(events, properties, MediaTraitType.PLAY); + } + + [Test] + public function testTimeEvents():void + { + var event1:TimeEvent = new TimeEvent(TimeEvent.COMPLETE, false, false, 3); + //Trait doesn't dispatch this, but MP does + //var event2:TimeEvent = new TimeEvent(TimeEvent.CURRENT_TIME_CHANGE, false, false, 1 ); + var event3:TimeEvent = new TimeEvent(TimeEvent.DURATION_CHANGE, false, false, 3 ); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(event1,event3); + + properties.push("time"); + + testWithElement(events, properties, MediaTraitType.TIME); + } + + [Test] + public function testDRMEvents():void + { + var event1:DRMEvent = new DRMEvent(DRMEvent.DRM_STATE_CHANGE, DRMState.AUTHENTICATION_COMPLETE, false, false, new Date(1), new Date(2), 4, "server1", null, null ); + var event2:DRMEvent = new DRMEvent(DRMEvent.DRM_STATE_CHANGE, DRMState.AUTHENTICATING, false, false, new Date(8), new Date(9), 4, "server1", null, null ); + var event3:DRMEvent = new DRMEvent(DRMEvent.DRM_STATE_CHANGE, DRMState.AUTHENTICATION_NEEDED, false, false, new Date(11), new Date(12), 4, "server1", null, null ); + var event4:DRMEvent = new DRMEvent(DRMEvent.DRM_STATE_CHANGE, DRMState.AUTHENTICATION_ERROR, false, false, new Date(11), new Date(12), 4, "server1", null, new MediaError(1, "detail") ); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(event1,event2, event3, event4); + + properties.push("drmState", "mediaError", "endDate", "period", "serverURL", "startDate", "token"); + + testWithElement(events, properties, MediaTraitType.DRM); + } + + [Test] + public function testDVREvents():void + { + var event1:DVREvent = new DVREvent(DVREvent.IS_RECORDING_CHANGE); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(event1); + + testWithElement(events, properties, MediaTraitType.DVR); + } + + [Test] + public function testDynamicStreamEvents():void + { + var event1:DynamicStreamEvent = new DynamicStreamEvent(DynamicStreamEvent.AUTO_SWITCH_CHANGE, false, false, false, false); + var event2:DynamicStreamEvent = new DynamicStreamEvent(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, false, false, false, true ); + var event3:DynamicStreamEvent = new DynamicStreamEvent(DynamicStreamEvent.SWITCHING_CHANGE, false, false, true, true ); + + var events:Vector. = new Vector.(); + var properties:Vector. = new Vector.(); + events.push(event1, event2, event3); + + properties.push("autoSwitch", "switching"); + + testWithElement(events, properties, MediaTraitType.DYNAMIC_STREAM); + } + + private function catchEvents(event:Event):void + { + caughtEvents.push(event); + } + + private var caughtEvents:Vector.; + private var dispatcher:TraitEventDispatcher; + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/utils/DynamicDRMTrait.as b/lib/osmf/framework/OSMFTest/src/org/osmf/utils/DynamicDRMTrait.as index a4f108e..3f91058 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/utils/DynamicDRMTrait.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/utils/DynamicDRMTrait.as @@ -1,73 +1,73 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.events.DRMEvent; - import org.osmf.events.MediaError; - import org.osmf.traits.DRMState; - import org.osmf.traits.DRMTrait; - - public class DynamicDRMTrait extends DRMTrait - { - public function DynamicDRMTrait() - { - super(); - } - - override public function authenticate(username:String=null, password:String=null):void - { - invokeDrmStateChange(DRMState.AUTHENTICATING, null, null); - if (username == null) - { - invokeDrmStateChange(DRMState.AUTHENTICATION_ERROR, null, null); - } - else - { - invokeDrmStateChange(DRMState.AUTHENTICATION_COMPLETE, null, null); - } - } - - override public function authenticateWithToken(token:Object):void - { - invokeDrmStateChange(DRMState.AUTHENTICATING, token, null); - if (token == null) - { - invokeDrmStateChange(DRMState.AUTHENTICATION_ERROR, null, null); - } - else - { - invokeDrmStateChange(DRMState.AUTHENTICATION_COMPLETE, token, null); - } - } - - public function invokeDrmStateChange(state:String, token:Object, error:MediaError, start:Date = null, end:Date = null, period:Number = NaN, serverURL:String = null):void - { - setStartDate(start); - setEndDate(end); - setPeriod(period); - setDrmState(state); - dispatchEvent(new DRMEvent(DRMEvent.DRM_STATE_CHANGE, state,false, false, start, end, period, serverURL, token, error)); - } - - - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.events.DRMEvent; + import org.osmf.events.MediaError; + import org.osmf.traits.DRMState; + import org.osmf.traits.DRMTrait; + + public class DynamicDRMTrait extends DRMTrait + { + public function DynamicDRMTrait() + { + super(); + } + + override public function authenticate(username:String=null, password:String=null):void + { + invokeDrmStateChange(DRMState.AUTHENTICATING, null, null); + if (username == null) + { + invokeDrmStateChange(DRMState.AUTHENTICATION_ERROR, null, null); + } + else + { + invokeDrmStateChange(DRMState.AUTHENTICATION_COMPLETE, null, null); + } + } + + override public function authenticateWithToken(token:Object):void + { + invokeDrmStateChange(DRMState.AUTHENTICATING, token, null); + if (token == null) + { + invokeDrmStateChange(DRMState.AUTHENTICATION_ERROR, null, null); + } + else + { + invokeDrmStateChange(DRMState.AUTHENTICATION_COMPLETE, token, null); + } + } + + public function invokeDrmStateChange(state:String, token:Object, error:MediaError, start:Date = null, end:Date = null, period:Number = NaN, serverURL:String = null):void + { + setStartDate(start); + setEndDate(end); + setPeriod(period); + setDrmState(state); + dispatchEvent(new DRMEvent(DRMEvent.DRM_STATE_CHANGE, state,false, false, start, end, period, serverURL, token, error)); + } + + + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/utils/DynamicDVRTrait.as b/lib/osmf/framework/OSMFTest/src/org/osmf/utils/DynamicDVRTrait.as index fd16af3..53b647c 100644 --- a/lib/osmf/framework/OSMFTest/src/org/osmf/utils/DynamicDVRTrait.as +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/utils/DynamicDVRTrait.as @@ -1,39 +1,39 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.utils -{ - import org.osmf.traits.DVRTrait; - - public class DynamicDVRTrait extends DVRTrait - { - public function DynamicDVRTrait(isRecording:Boolean=false) - { - super(isRecording); - } - - public function set isRecording(value:Boolean):void - { - setIsRecording(value); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.utils +{ + import org.osmf.traits.DVRTrait; + + public class DynamicDVRTrait extends DVRTrait + { + public function DynamicDVRTrait(isRecording:Boolean=false) + { + super(isRecording); + } + + public function set isRecording(value:Boolean):void + { + setIsRecording(value); + } + } } \ No newline at end of file diff --git a/lib/osmf/framework/OSMFTest/src/org/osmf/utils/TestURL.as b/lib/osmf/framework/OSMFTest/src/org/osmf/utils/TestURL.as new file mode 100644 index 0000000..6cf87fa --- /dev/null +++ b/lib/osmf/framework/OSMFTest/src/org/osmf/utils/TestURL.as @@ -0,0 +1,81 @@ +/***************************************************** +* +* Copyright 2012 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2012 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flexunit.framework.Assert; + + /** + * Centralized test class for URLs. + **/ + public class TestURL + { + [Test] + public function testNormalizePathForURL_1():void + { + var testUrl:String = "http://10.131.237.104/vod/"; + var expectedUrl:String = "http://10.131.237.104/vod/"; + + var normalizedUrl:String = URL.normalizePathForURL(testUrl, true); + Assert.assertEquals(expectedUrl, normalizedUrl); + } + + [Test] + public function testNormalizePathForURL_2():void + { + var testUrl:String = "http://10.131.237.104/vod/mlm_params.f4m"; + var expectedUrl:String = "http://10.131.237.104/vod/"; + + var normalizedUrl:String = URL.normalizePathForURL(testUrl, true); + Assert.assertEquals(expectedUrl, normalizedUrl); + } + + [Test] + public function testNormalizePathForURL_3():void + { + var testUrl:String = "http://10.131.237.104/vod/mlm_params.f4m?debug=1&path=/check/fm-1485/"; + var expectedUrl:String = "http://10.131.237.104/vod/"; + + var normalizedUrl:String = URL.normalizePathForURL(testUrl, true); + Assert.assertEquals(expectedUrl, normalizedUrl); + } + + [Test] + public function testNormalizePathForURL_4():void + { + var testUrl:String = "http://10.131.237.104/vod/"; + var expectedUrl:String = "http://10.131.237.104/vod/"; + + var normalizedUrl:String = URL.normalizePathForURL(testUrl, false); + Assert.assertEquals(expectedUrl, normalizedUrl); + } + + [Test] + public function testNormalizePathForURL_5():void + { + var testUrl:String = "http://10.131.237.104/vod"; + var expectedUrl:String = "http://10.131.237.104/vod/"; + + var normalizedUrl:String = URL.normalizePathForURL(testUrl, false); + Assert.assertEquals(expectedUrl, normalizedUrl); + } + } +} \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/StrobeMediaPlayback-build-config.xml b/lib/osmf/player/StrobeMediaPlayback/StrobeMediaPlayback-build-config.xml index 289f9b4..d166f4e 100644 --- a/lib/osmf/player/StrobeMediaPlayback/StrobeMediaPlayback-build-config.xml +++ b/lib/osmf/player/StrobeMediaPlayback/StrobeMediaPlayback-build-config.xml @@ -1 +1 @@ - false CONFIG::DEBUG false en_US src false true ${flexlib}/libs/air/airglobal.swc false assets/assets.swc ${flexlib}/libs ${flexlib}/locale/{locale} ../../framework/OSMF/#output.bin#/OSMF.swc true Bindable Managed ChangeEvent NonCommittingChangeEvent Transient true true true true true false false true 20 1000 flash.fonts.JREFontManager flash.fonts.AFEFontManager flash.fonts.BatikFontManager false true true true true true true true true true true false false false true false false false false true true false true true true false true true false false true false false true true false true 10.2.0 true StrobeMediaPlayback Strobe Media Playback Adrian Silaghi Adrian Silaghi EN \ No newline at end of file + false CONFIG::DEBUG false en_US src false true ${flexlib}/libs/air/airglobal.swc false assets/assets.swc ${flexlib}/libs ${flexlib}/locale/{locale} #osmf.swc.path# true Bindable Managed ChangeEvent NonCommittingChangeEvent Transient true true true true true false false true 20 1000 flash.fonts.JREFontManager flash.fonts.AFEFontManager flash.fonts.BatikFontManager false true true true true true true true true true true false false false true false false false false true true false true true true false true true false false true false false true true false true 10.2.0 true StrobeMediaPlayback Strobe Media Playback Adrian Silaghi Adrian Silaghi EN \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/advertisement-demo.html b/lib/osmf/player/StrobeMediaPlayback/html-template/advertisement-demo.html index 3d0ca18..f3075b0 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/advertisement-demo.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/advertisement-demo.html @@ -1,286 +1,286 @@ - - - - - Advertisement Demo - - - - - - - -

OSMF Reference Plug-in Demo for Advertisements

-

- This reference plug-in makes it easy to add simple advertisement experiences to an OSMF-based video player. -

-

- It provides sample code for both linear and non-linear ad insertions, and it can serve as a starting point for plug-ins that are required to integrate with advertisement backends. -

-
-
- Alternative content -
-
- - -
-

Demo Outline

-

- You can select from a set of predefined advertisement scenarios and you can insert either linear or overlay ads using the provided interactive controls. -

-

- All the advertisements except the pre-rolls are being pre-buffered, so you should experience seamless playback for mid-rolls. (post-rolls need to be pre-buffered as well, but pre-buffering for post-rolls is not implemented yet). -

-

- Take a closer look at the Stage Video instance count which is being displayed in the info overlay (top-left corner). On desktops you should see 4 available StageVideo instances and you should see them being picked up as you add more overlay ads. -

- -
-
-

Details

-

- The Advertisement Reference plug-in is intended to to demonstrate best practices related to ad insertion in OSMF-based players. - -

-

- The plug-in provides both a JavaScript based API as well as a very simple configuration API (flashvars) which can be used when embedding the player. -

-

- You can view the source to learn about how the current configuration and JavaScript API work. -

-

FlashVars configuration

-

- To activate the plug-in, you simply load the plug-in as normal, but add a reference to the swf: -

-

-        plugin_ads: "AdvertisementPlugin.swf"
-            
- -

- For setting the pre-roll, mid-roll and the post-roll ads, all you need is to add the paths to the ads and the time when the mid-roll ad or the overlay ad needs to be displayed. -

-

- Note that this plug-in can be configured to load only one mid-roll ad and one overlay ad using the flashvars configuration. - Feel free to extend it as needed, or to use the JavaScript API described below. -

-
	
-		ads_preroll: "http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv",
-		ads_postroll: "http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv",
-		ads_midroll: "http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv",
-		ads_midrollTime: 20,
-		ads_overlay: "http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv",
-		ads_overlayTime: 25
-			
-

-

The JavaScript API

-

- For using the JavaScript API exposed by the plugin you need to get the reference to the StrobeMediaPlayback instance and simply interact with the plugin. -

-

- The following snippet will insert an overlay ad, at some random position. -

-
	
-		player.strobeMediaPlayback.displayNonLiniarAd (
-			"http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv", {
-				right: options.width/2 * Math.random(),
-				bottom: options.height/2 * Math.random(),
-				scaleMode: "none"});
-			
-

- The following snippet will interrupt the current media playback and will play a linear ad instead: -

-
	
-		player.strobeMediaPlayback.displayLiniarAd("http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv");
-			
- -
-
-

Known Limitations

-
    -
  1. - Strobe Media Playback needs to disable the scrubBar while the linear ads are being played back. (not implemented yet) -
  2. -
  3. - Strobe Media Playback needs to display a widget during linear ad playback. This can be something like this: "Advertisement. Video will resume in 10 seconds..." -
  4. -
  5. - The plugin does not handle the ordering (depth) of the advertisements at this point. While using the plugin you should be aware that the advertisement that - is added last will be added on top of the other medias/ads that are being currently played. -
  6. -
  7. - With the current implementation of this plug-in, it should be pretty simple to create any kind of interactive ads you can imagine. This is just a start. -
  8. -
-
- - + + + + + Advertisement Demo + + + + + + + +

OSMF Reference Plug-in Demo for Advertisements

+

+ This reference plug-in makes it easy to add simple advertisement experiences to an OSMF-based video player. +

+

+ It provides sample code for both linear and non-linear ad insertions, and it can serve as a starting point for plug-ins that are required to integrate with advertisement backends. +

+
+
+ Alternative content +
+
+ + +
+

Demo Outline

+

+ You can select from a set of predefined advertisement scenarios and you can insert either linear or overlay ads using the provided interactive controls. +

+

+ All the advertisements except the pre-rolls are being pre-buffered, so you should experience seamless playback for mid-rolls. (post-rolls need to be pre-buffered as well, but pre-buffering for post-rolls is not implemented yet). +

+

+ Take a closer look at the Stage Video instance count which is being displayed in the info overlay (top-left corner). On desktops you should see 4 available StageVideo instances and you should see them being picked up as you add more overlay ads. +

+ +
+
+

Details

+

+ The Advertisement Reference plug-in is intended to to demonstrate best practices related to ad insertion in OSMF-based players. + +

+

+ The plug-in provides both a JavaScript based API as well as a very simple configuration API (flashvars) which can be used when embedding the player. +

+

+ You can view the source to learn about how the current configuration and JavaScript API work. +

+

FlashVars configuration

+

+ To activate the plug-in, you simply load the plug-in as normal, but add a reference to the swf: +

+

+        plugin_ads: "AdvertisementPlugin.swf"
+            
+ +

+ For setting the pre-roll, mid-roll and the post-roll ads, all you need is to add the paths to the ads and the time when the mid-roll ad or the overlay ad needs to be displayed. +

+

+ Note that this plug-in can be configured to load only one mid-roll ad and one overlay ad using the flashvars configuration. + Feel free to extend it as needed, or to use the JavaScript API described below. +

+
	
+		ads_preroll: "http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv",
+		ads_postroll: "http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv",
+		ads_midroll: "http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv",
+		ads_midrollTime: 20,
+		ads_overlay: "http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv",
+		ads_overlayTime: 25
+			
+

+

The JavaScript API

+

+ For using the JavaScript API exposed by the plugin you need to get the reference to the StrobeMediaPlayback instance and simply interact with the plugin. +

+

+ The following snippet will insert an overlay ad, at some random position. +

+
	
+		player.strobeMediaPlayback.displayNonLiniarAd (
+			"http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv", {
+				right: options.width/2 * Math.random(),
+				bottom: options.height/2 * Math.random(),
+				scaleMode: "none"});
+			
+

+ The following snippet will interrupt the current media playback and will play a linear ad instead: +

+
	
+		player.strobeMediaPlayback.displayLiniarAd("http://gcdn.2mdn.net/MotifFiles/html/1379578/PID_938961_1237818260000_women.flv");
+			
+ +
+
+

Known Limitations

+
    +
  1. + Strobe Media Playback needs to disable the scrubBar while the linear ads are being played back. (not implemented yet) +
  2. +
  3. + Strobe Media Playback needs to display a widget during linear ad playback. This can be something like this: "Advertisement. Video will resume in 10 seconds..." +
  4. +
  5. + The plugin does not handle the ordering (depth) of the advertisements at this point. While using the plugin you should be aware that the advertisement that + is added last will be added on top of the other medias/ads that are being currently played. +
  6. +
  7. + With the current implementation of this plug-in, it should be pretty simple to create any kind of interactive ads you can imagine. This is just a start. +
  8. +
+
+ + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/debug-mobile.html b/lib/osmf/player/StrobeMediaPlayback/html-template/debug-mobile.html index 3c6e46c..fade3c7 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/debug-mobile.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/debug-mobile.html @@ -1,291 +1,291 @@ - - - - Strobe Media Playback - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
-
-

- Alternative content -

-
-
- - -

logs (the last 50 lines). New logs will be displayed if they match: -

-
-
-
-
- -
- Press F11 to make the browser window enter/exit full screen. -
-
- - - - - - - - - - - - - - - - - -
- - -
- Key Statistics -
-
- - -
- Rendering Info -
-
- - -
- Dynamic Streaming Info -
-
- - -
- Buffer Info -
-
- - -
- PlaybackOptimizationMetrics -
- - -
- StrobeMediaPlayer -
-
- - -
- NetStream -
- - -
- NetStreamInfo -
-
- - - - -
- Resource Metadata -
-
-
-
- - + + + + Strobe Media Playback + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+
+

+ Alternative content +

+
+
+ + +

logs (the last 50 lines). New logs will be displayed if they match: +

+
+
+
+
+ +
+ Press F11 to make the browser window enter/exit full screen. +
+
+ + + + + + + + + + + + + + + + + +
+ + +
+ Key Statistics +
+
+ + +
+ Rendering Info +
+
+ + +
+ Dynamic Streaming Info +
+
+ + +
+ Buffer Info +
+
+ + +
+ PlaybackOptimizationMetrics +
+ + +
+ StrobeMediaPlayer +
+
+ + +
+ NetStream +
+ + +
+ NetStreamInfo +
+
+ + + + +
+ Resource Metadata +
+
+
+
+ + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/debug.html b/lib/osmf/player/StrobeMediaPlayback/html-template/debug.html index b9da02f..3f112ad 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/debug.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/debug.html @@ -1,279 +1,279 @@ - - - - Strobe Media Playback - - - - - - - - - - - - - -
- - - - - - - -
-
-

- Alternative content -

-
-
- - -

logs (the last 50 lines). New logs will be displayed if they match: -

-
-
-
-
- -
- Press F11 to make the browser window enter/exit full screen. -
-
- - - - - - - - - - - - - - - - - -
- - -
- Key Statistics -
-
- - -
- Rendering Info -
-
- - -
- Dynamic Streaming Info -
-
- - -
- Buffer Info -
-
- - -
- PlaybackOptimizationMetrics -
- - -
- StrobeMediaPlayer -
-
- - -
- NetStream -
- - -
- NetStreamInfo -
-
- - - - -
- Resource Metadata -
-
-
-
- - + + + + Strobe Media Playback + + + + + + + + + + + + + +
+ + + + + + + +
+
+

+ Alternative content +

+
+
+ + +

logs (the last 50 lines). New logs will be displayed if they match: +

+
+
+
+
+ +
+ Press F11 to make the browser window enter/exit full screen. +
+
+ + + + + + + + + + + + + + + + + +
+ + +
+ Key Statistics +
+
+ + +
+ Rendering Info +
+
+ + +
+ Dynamic Streaming Info +
+
+ + +
+ Buffer Info +
+
+ + +
+ PlaybackOptimizationMetrics +
+ + +
+ StrobeMediaPlayer +
+
+ + +
+ NetStream +
+ + +
+ NetStreamInfo +
+
+ + + + +
+ Resource Metadata +
+
+
+
+ + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/embed-samples.html b/lib/osmf/player/StrobeMediaPlayback/html-template/embed-samples.html index 299ce33..480d91a 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/embed-samples.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/embed-samples.html @@ -1,64 +1,64 @@ - - - - - Flash/Strobe Media Playback - iframe embed sample - - -

Strobe Media Playback for Flash and HTML5 <video>

-

<iframe> embed code

-

The simplest embed strategy is using iframes. This is likely to become a standard across major video sites.

-

Sample embed code

-
	
-        <:iframe src="embed.html?
-			src=http://players.edgesuite.net/videos/big_buck_bunny/bbb_448x252.mp4" 
-			class="strobemediaplayback-video-player" type="text/html" 
-			width="833" 
-			height="641">
-        <:/iframe>			
-		
-

Live Demos

- Basic embed code sample -
- -
-

jQuery plugin

-

As a web designer, you might want to use our jQuery plugin instead of the iframe. Like this you have complete control over the video playback and the experience arround the player.

-

Using the jQuery snippet also saves a HTTP request, so if you have control over the pages where the video is hosted this approach is much better.

-

Sample embed code

-
        	
-            <div id="strobemediaplayback" style="width:640px; height:480px"></div>
-			<script type="text/javascript" src="lib/swfobject.js"></script>
-            <script type="text/javascript" src="lib/jquery/jquery-1.4.2.js"></script>
-            <script type="text/javascript" src="jquery.strobemediaplayback.js"></script>
-            
-            <script type="text/javascript">
-            $(function(){
-                var options = {
-                    src: "http://players.edgesuite.net/videos/big_buck_bunny/bbb_448x252.mp4",
-                    width: 640,
-                    height: 480
-                };
-                // Now we are ready to generate the video tags
-                $("#strobemediaplayback").strobemediaplayback(options);
-            });
-            </script>		
-		
-

Live Demos

- jQuery basic sample -
- jQuery basic sample - favor HTML5 <video> playback - embed.html?favorFlashOverHtml5Video=false -
-

Custom Chrome

-

Instead of using the default browser chrome it is possible to use a custom control bar. Like this you have full control over the playback controls look and feel.

- - -

Live Demos

- Favor Flash over HTML5 video (default) -
- Favor Html5 video over Flash -
- - - - + + + + + Flash/Strobe Media Playback - iframe embed sample + + +

Strobe Media Playback for Flash and HTML5 <video>

+

<iframe> embed code

+

The simplest embed strategy is using iframes. This is likely to become a standard across major video sites.

+

Sample embed code

+
	
+        <:iframe src="embed.html?
+			src=http://players.edgesuite.net/videos/big_buck_bunny/bbb_448x252.mp4" 
+			class="strobemediaplayback-video-player" type="text/html" 
+			width="833" 
+			height="641">
+        <:/iframe>			
+		
+

Live Demos

+ Basic embed code sample +
+ +
+

jQuery plugin

+

As a web designer, you might want to use our jQuery plugin instead of the iframe. Like this you have complete control over the video playback and the experience arround the player.

+

Using the jQuery snippet also saves a HTTP request, so if you have control over the pages where the video is hosted this approach is much better.

+

Sample embed code

+
        	
+            <div id="strobemediaplayback" style="width:640px; height:480px"></div>
+			<script type="text/javascript" src="lib/swfobject.js"></script>
+            <script type="text/javascript" src="lib/jquery/jquery-1.4.2.js"></script>
+            <script type="text/javascript" src="jquery.strobemediaplayback.js"></script>
+            
+            <script type="text/javascript">
+            $(function(){
+                var options = {
+                    src: "http://players.edgesuite.net/videos/big_buck_bunny/bbb_448x252.mp4",
+                    width: 640,
+                    height: 480
+                };
+                // Now we are ready to generate the video tags
+                $("#strobemediaplayback").strobemediaplayback(options);
+            });
+            </script>		
+		
+

Live Demos

+ jQuery basic sample +
+ jQuery basic sample - favor HTML5 <video> playback - embed.html?favorFlashOverHtml5Video=false +
+

Custom Chrome

+

Instead of using the default browser chrome it is possible to use a custom control bar. Like this you have full control over the playback controls look and feel.

+ + +

Live Demos

+ Favor Flash over HTML5 video (default) +
+ Favor Html5 video over Flash +
+ + + + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/embed.html b/lib/osmf/player/StrobeMediaPlayback/html-template/embed.html index 1285e88..ef7f6eb 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/embed.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/embed.html @@ -1,58 +1,58 @@ - - - - - Flash/Strobe Media Playback - - - - - - - - - - - - -
Alternative content
- - + + + + + Flash/Strobe Media Playback + + + + + + + + + + + + +
Alternative content
+ + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/hello-world-javascript.html b/lib/osmf/player/StrobeMediaPlayback/html-template/hello-world-javascript.html index fa2fae9..d7bca81 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/hello-world-javascript.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/hello-world-javascript.html @@ -1,75 +1,75 @@ - - - - Strobe Media Playback - - - - -
-
- ... : ... -
- Play/Pause
-
-
-

Alternative content

-
- + + + + Strobe Media Playback + + + + +
+
+ ... : ... +
+
Play/Pause
+ +
+

Alternative content

+
+ \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/hello-world-jquery-plugin.html b/lib/osmf/player/StrobeMediaPlayback/html-template/hello-world-jquery-plugin.html index e5b5145..f24cfc0 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/hello-world-jquery-plugin.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/hello-world-jquery-plugin.html @@ -1,140 +1,140 @@ - - - - - Flash/Strobe Media Playback - - - - - - - - - - - -
Alternative content
- - -
-
- ... : ... -
-
Play/Pause
- - - - + + + + + Flash/Strobe Media Playback + + + + + + + + + + + +
Alternative content
+ + +
+
+ ... : ... +
+ Play/Pause
+ + + + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/index.template.html b/lib/osmf/player/StrobeMediaPlayback/html-template/index.template.html index d6eeb5f..d37258a 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/index.template.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/index.template.html @@ -1,143 +1,143 @@ - - - - Strobe Media Playback - - - - - - - - - - - - - - -
- - - Strobe Media Playback - - osmf logo - -
- - - - - - - -
-
-

- Alternative content -

-
-
-

- Click on one of the links below to have it loaded -

-

- -

-
- Player Setup - - + + + + Strobe Media Playback + + + + + + + + + + + + + + +
+ + + Strobe Media Playback + + osmf logo + +
+ + + + + + + +
+
+

+ Alternative content +

+
+
+

+ Click on one of the links below to have it loaded +

+

+ +

+
+ Player Setup + + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/jquery-custom-chrome.html b/lib/osmf/player/StrobeMediaPlayback/html-template/jquery-custom-chrome.html index c039a33..b08f7d3 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/jquery-custom-chrome.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/jquery-custom-chrome.html @@ -1,162 +1,162 @@ - - - - - Flash/Strobe Media Playback - - - - - - - - - -
-
-
-
- Alternative Content -
- - -
- -
- -
-
-
-
-
-
-
- - -
- 0:00 / 0:00 -
-
-
-
-
-
- ... -
-
- ... -
- -
-

MP4 files, for Chrome & Safari

- http://osmf.org/dev/videos/cathy1_SD.mp4 -
- http://osmf.org/dev/videos/cathy1_HD.mp4 -
- http://osmf.org/dev/videos/cathy2_SD.mp4 -
- http://osmf.org/dev/videos/cathy2_HD.mp4 -
- http://media.w3.org/2010/05/sintel/trailer.mp4 -
- http://players.edgesuite.net/videos/big_buck_bunny/bbb_448x252.mp4 -

OGG files, for Firefox HTML5 only

- http://media.w3.org/2010/05/sintel/trailer.ogv -
- http://players.edgesuite.net/videos/big_buck_bunny/bbb_448x252.ogg -
- + + + + + Flash/Strobe Media Playback + + + + + + + + + +
+
+
+
+ Alternative Content +
+ + +
+ +
+ +
+
+
+
+
+
+
+ + +
+ 0:00 / 0:00 +
+
+
+
+
+
+ ... +
+
+ ... +
+ +
+

MP4 files, for Chrome & Safari

+ http://osmf.org/dev/videos/cathy1_SD.mp4 +
+ http://osmf.org/dev/videos/cathy1_HD.mp4 +
+ http://osmf.org/dev/videos/cathy2_SD.mp4 +
+ http://osmf.org/dev/videos/cathy2_HD.mp4 +
+ http://media.w3.org/2010/05/sintel/trailer.mp4 +
+ http://players.edgesuite.net/videos/big_buck_bunny/bbb_448x252.mp4 +

OGG files, for Firefox HTML5 only

+ http://media.w3.org/2010/05/sintel/trailer.ogv +
+ http://players.edgesuite.net/videos/big_buck_bunny/bbb_448x252.ogg +
+ diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/jquery-embed-sample.html b/lib/osmf/player/StrobeMediaPlayback/html-template/jquery-embed-sample.html index b499d28..f7571cb 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/jquery-embed-sample.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/jquery-embed-sample.html @@ -1,42 +1,42 @@ - - - - - Flash/Strobe Media Playback - - - - - - - - - -
Alternative content
- - + + + + + Flash/Strobe Media Playback + + + + + + + + + +
Alternative content
+ + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/jquery.strobemediaplayback.css b/lib/osmf/player/StrobeMediaPlayback/html-template/jquery.strobemediaplayback.css index ba276ef..48febf6 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/jquery.strobemediaplayback.css +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/jquery.strobemediaplayback.css @@ -1,269 +1,269 @@ -body { - background: #000000; -} - -.smp { - width: 24px; - height: 24px; - background: transparent url(jquery.strobemediaplayback.png) no-repeat; - display: block; -} - -.play { - background-position: 0 0; -} - -a.play:hover { - background-position: 0 -24px; -} - -a.play:active { - background-position: 0 -48px; -} - -.pause { - background-position: -24px 0; -} - -a.pause:hover { - background-position: -24px -24px; -} - -a.pause:active { - background-position: -24px -48px; -} - -.volume.low { - background-position: -24px -72px; -} - -a.volume.low:hover { - background-position: -24px -96px; -} - -a.volume.low:active { - background-position: -24px -120px; -} - -.volume.med { - background-position: -48px -72px; -} - -a.volume.med:hover { - background-position: -48px -96px; -} - -a.volume.med:active { - background-position: -48px -120px; -} - -.volume.high { - background-position: -72px -72px; -} - -a.volume.high:hover { - background-position: -72px -96px; -} - -a.volume.high:active { - background-position: -72px -120px; -} - -.volume.mute { - background-position: 0 -72px; -} - -a.volume.mute:hover { - background-position: 0 -96px; -} - -a.volume.mute:active { - background-position: 0 -120px; -} - -.fullscreen { - background-position: -48px -0px; -} - -a.fullscreen:hover { - background-position: -48px -24px; -} - -a.fullscreen:active { - background-position: -48px -48px; -} - -.fullscreen.on { - background-position: -72px -0px; -} - -a.fullscreen.on:hover { - background-position: -72px -24px; -} - -a.fullscreen.on:active { - background-position: -72px -48px; -} - -.playoverlay { - display:none; - z-index: 1001; - width: 116px; - height: 107px; - background: transparent url(jquery.strobemediaplayback.png) no-repeat; - background-position: -92px 0; -} - -a.playoverlay:hover, a.playoverlay:active { - background-position: -92px -107px; -} - -.strobeMediaPlaybackControlBar { - background-color: #000000; - color: #E8E8E8; - height: 30px; - opacity: 0.9; - position: absolute; - border: 1px solid #404040; - outline: 1px solid #101010; - outline-offset: 1px; - z-index: 1000; - /*bottom: 2px;*/ - width: 100%; - left: 2px; -} - -.smp { - position: absolute; - margin: 3px; - margin-top: 3.5px; - border: none; -} - -.time { - margin: 7px; - margin-top: 8px; - font-size: 11px; - border: none; -} - -.fullscreen { - right: 5px; -} - -.volume { - right: 5px; -} - -.time { - font-family: sans-serif; - position: absolute; - right: 55px; -} - -.play, .pause { - float: left; -} - -.smp-video { - border: none; -} - -#html5MediaPlayback { - position: relative; - width: 640px; - height: 362px; - top: 0px; - left: 0px; - background-color: #000000; -} - -.video-progress2 { - opacity: 1; - left: 40px; - display: block; - position: absolute; - padding: 0px; - margin: 0px; - height: 10px; - border: none; - margin-top: 12px; - -} - -.video-track { - margin-top: 0; - width: 100%; - border: 1px solid #404040; - outline: 1px solid #897048; - outline-offset: 1px; - background: #777777; - height: 4px; - display: block; - position: absolute; - z-index: 1; - padding-right: 9px; - overflow:hidden; -} - -.played { - display: block; - background-color: #00ADFC; - width: 0; - left: 0; - position: absolute; - z-index: 2; - height: inherit; -} - -.buffered { - display: block; - background-color: #557A8E; - width: 2px; - left: 0; - position: absolute; - z-index: 2; - height: inherit; - border-right: 1px solid #ffffff; -} -.buffered.done { - border: none; -} - -.slider { - display: block; - position: absolute; - width: 12px; - height: 12px; - left: 0; - z-index: 3; - margin: 0px; - border: 1px solid #000000; - outline: 1px solid #897048; - outline-offset: 1px; - background-color: #D6D6D6; - padding: 0 1px; - margin-top: -3.5px; - opacity: 1; -} - -a.slider:hover, a.slider:active { - /*border: 4px solid #000000;*/ - background-color: #E8E8E8; - -moz-box-shadow: 0px 0px 5px #ffffff; - -webkit-box-shadow: 0px 0px 5px #ffffff; - box-shadow: 0px 0px 5px #ffffff; - outline: none; -} - -.smp-error { - display:none; - position:absolute; - top:10%; - padding: 30px; -} - -.disabled { - opacity:0.4; - display:none; -} +body { + background: #000000; +} + +.smp { + width: 24px; + height: 24px; + background: transparent url(jquery.strobemediaplayback.png) no-repeat; + display: block; +} + +.play { + background-position: 0 0; +} + +a.play:hover { + background-position: 0 -24px; +} + +a.play:active { + background-position: 0 -48px; +} + +.pause { + background-position: -24px 0; +} + +a.pause:hover { + background-position: -24px -24px; +} + +a.pause:active { + background-position: -24px -48px; +} + +.volume.low { + background-position: -24px -72px; +} + +a.volume.low:hover { + background-position: -24px -96px; +} + +a.volume.low:active { + background-position: -24px -120px; +} + +.volume.med { + background-position: -48px -72px; +} + +a.volume.med:hover { + background-position: -48px -96px; +} + +a.volume.med:active { + background-position: -48px -120px; +} + +.volume.high { + background-position: -72px -72px; +} + +a.volume.high:hover { + background-position: -72px -96px; +} + +a.volume.high:active { + background-position: -72px -120px; +} + +.volume.mute { + background-position: 0 -72px; +} + +a.volume.mute:hover { + background-position: 0 -96px; +} + +a.volume.mute:active { + background-position: 0 -120px; +} + +.fullscreen { + background-position: -48px -0px; +} + +a.fullscreen:hover { + background-position: -48px -24px; +} + +a.fullscreen:active { + background-position: -48px -48px; +} + +.fullscreen.on { + background-position: -72px -0px; +} + +a.fullscreen.on:hover { + background-position: -72px -24px; +} + +a.fullscreen.on:active { + background-position: -72px -48px; +} + +.playoverlay { + display:none; + z-index: 1001; + width: 116px; + height: 107px; + background: transparent url(jquery.strobemediaplayback.png) no-repeat; + background-position: -92px 0; +} + +a.playoverlay:hover, a.playoverlay:active { + background-position: -92px -107px; +} + +.strobeMediaPlaybackControlBar { + background-color: #000000; + color: #E8E8E8; + height: 30px; + opacity: 0.9; + position: absolute; + border: 1px solid #404040; + outline: 1px solid #101010; + outline-offset: 1px; + z-index: 1000; + /*bottom: 2px;*/ + width: 100%; + left: 2px; +} + +.smp { + position: absolute; + margin: 3px; + margin-top: 3.5px; + border: none; +} + +.time { + margin: 7px; + margin-top: 8px; + font-size: 11px; + border: none; +} + +.fullscreen { + right: 5px; +} + +.volume { + right: 5px; +} + +.time { + font-family: sans-serif; + position: absolute; + right: 55px; +} + +.play, .pause { + float: left; +} + +.smp-video { + border: none; +} + +#html5MediaPlayback { + position: relative; + width: 640px; + height: 362px; + top: 0px; + left: 0px; + background-color: #000000; +} + +.video-progress2 { + opacity: 1; + left: 40px; + display: block; + position: absolute; + padding: 0px; + margin: 0px; + height: 10px; + border: none; + margin-top: 12px; + +} + +.video-track { + margin-top: 0; + width: 100%; + border: 1px solid #404040; + outline: 1px solid #897048; + outline-offset: 1px; + background: #777777; + height: 4px; + display: block; + position: absolute; + z-index: 1; + padding-right: 9px; + overflow:hidden; +} + +.played { + display: block; + background-color: #00ADFC; + width: 0; + left: 0; + position: absolute; + z-index: 2; + height: inherit; +} + +.buffered { + display: block; + background-color: #557A8E; + width: 2px; + left: 0; + position: absolute; + z-index: 2; + height: inherit; + border-right: 1px solid #ffffff; +} +.buffered.done { + border: none; +} + +.slider { + display: block; + position: absolute; + width: 12px; + height: 12px; + left: 0; + z-index: 3; + margin: 0px; + border: 1px solid #000000; + outline: 1px solid #897048; + outline-offset: 1px; + background-color: #D6D6D6; + padding: 0 1px; + margin-top: -3.5px; + opacity: 1; +} + +a.slider:hover, a.slider:active { + /*border: 4px solid #000000;*/ + background-color: #E8E8E8; + -moz-box-shadow: 0px 0px 5px #ffffff; + -webkit-box-shadow: 0px 0px 5px #ffffff; + box-shadow: 0px 0px 5px #ffffff; + outline: none; +} + +.smp-error { + display:none; + position:absolute; + top:10%; + padding: 30px; +} + +.disabled { + opacity:0.4; + display:none; +} diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/jsdemo.css b/lib/osmf/player/StrobeMediaPlayback/html-template/jsdemo.css index cf3715b..5727389 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/jsdemo.css +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/jsdemo.css @@ -1,67 +1,67 @@ -.smp-controls -{ - width: 640px; - font-size: 0.9em; -} -.smp-top-container -{ - width: 630px; - padding: 5px; -} - -.smp-volume -{ - width: 10%; - height: 9px; - - padding-left: 30px; - display: inline-block; -} - -.smp-time -{ - float: right; -} - -.smp-mbr-indicator -{ - float: right; - margin-right: 10px; -} - -.smp-mbr-items -{ - position:absolute; - top: 370px; - left: 310px; - width: 250px; - z-index:200; - background-color: black; - display: inline; -} - -.smp-mbr-item -{ - display:block; - margin:0; - padding:0; -} - -.smp-mbr-auto -{ -; -} - -.smp-progress -{ - width: 630px; - padding: 0 5px; - font-size: 8px; -} - -.smp-mbr-items button -{ - width: 100%; - text-align: right; -} +.smp-controls +{ + width: 640px; + font-size: 0.9em; +} +.smp-top-container +{ + width: 630px; + padding: 5px; +} + +.smp-volume +{ + width: 10%; + height: 9px; + + padding-left: 30px; + display: inline-block; +} + +.smp-time +{ + float: right; +} + +.smp-mbr-indicator +{ + float: right; + margin-right: 10px; +} + +.smp-mbr-items +{ + position:absolute; + top: 370px; + left: 310px; + width: 250px; + z-index:200; + background-color: black; + display: inline; +} + +.smp-mbr-item +{ + display:block; + margin:0; + padding:0; +} + +.smp-mbr-auto +{ +; +} + +.smp-progress +{ + width: 630px; + padding: 0 5px; + font-size: 8px; +} + +.smp-mbr-items button +{ + width: 100%; + text-align: right; +} \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/jsdemo.html b/lib/osmf/player/StrobeMediaPlayback/html-template/jsdemo.html index 555d7e2..f6a15b4 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/jsdemo.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/jsdemo.html @@ -1,611 +1,611 @@ - - - - Strobe Media Playback - - - - - - - - - - - - - - - - - - - - - - - - - -
Strobe Media Playback
- - - - - - - - - -
-
-

Alternative content

-
-
-
- - - - - -
-
- 0:00 / 0:00 - - -
- -
-
-
-
-
-
- -
-
-
-

At the left we can see...

-

At the right we can see the...

-

...the head-snarlers

-

Everything is safe. Perfectly safe.

-

Emo?

-

Watch out!

-

Are you hurt?

-

I don't think so. You?

-

I'm Ok.

-

Get up. Emo, it's not safe here.

-

Let's go.

-

What's next?

-

You'll see!

-

(howling wind)

-

Emo. This way.

-

Follow me!

-

(buzzing wires and chattery conversations)

-

Hurry Emo!

-

(louder telephone voices)

-

(phone ringing)

-

You're not paying attention!

-

I just want to answer the... ...phone.

-

Emo, look, I mean listen.

-

You have to learn to listen.

-

This is not some game.

-

You, i mean we, we could easily die out here.

-

Listen, listen to the sounds of the machine.

-

Listen to your breathing.

-

(Buzzing wires)

-

(laughing)

-

(oriental dance music)

-

Well, don't you ever get tired of this?

-

Tired?!?

-

Emo, the machine is like clockwork.

-

One move out of place...

-

...and you're ground to a pulp.

-

But isn't it -

-

Pulp, Emo! Is that what you want, pulp?

-

Emo, your goal in life...

-

...pulp?

-

(loud metal sounds)

-

Emo, close your eyes.

-

Why? - Now!

-

Ok.

-

Good.

-

What do you see at your left side, Emo?

-

Nothing. - Really?

-

No, nothing at all.

-

And at your right, what do you see at your right side, Emo?

-

The same Proog, exactly the same...

-

...nothing! - Great.

-

(sound of camera flash)

-

(engine drone)

-

Listen Proog! Do you hear that! (amusement park music)

-

Can we go here?

-

There? It isn't safe, Emo.

-

But... - Trust me, it's not.

-

Maybe I could...

-

No.

-

NO!

-

Any further questions, Emo?

-

No.

-

Emo?

-

Emo, why...

-

Emo...

-

...why can't you see the beauty of this place?

-

The way it works.

-

How perfect it is.

-

No, Proog, I don't see.

-

I don't see because there's nothing there.

-

And why should I trust my life to something that isn't there?

-

Well can you tell me that?

-

Answer me!

-

Proog...

-

...you're a sick man!

-

Stay away from me!

-

No! Emo! It's a trap!

-

Hah, it's a trap.

-

At the left side you can see|the hanging gardens of Babylon!

-

How's that for a trap?

-

No, Emo.

-

At the right side you can see... ...well guess what...

-

...the colossus of Rhodes!

-

No!

-

The colossus of Rhodes and it is here just for you Proog.

-

It is there...

-

I'm telling you, Emo...

-

...it is.

-

(howling wind)

- -
-
- - - -
-
- - -
-
-
-
-
-
- -
- - -
-
- - + + + + Strobe Media Playback + + + + + + + + + + + + + + + + + + + + + + + + + +
Strobe Media Playback
+ + + + + + + + + +
+
+

Alternative content

+
+
+
+ + + + + +
+
+ 0:00 / 0:00 + + +
+ +
+
+
+
+
+
+ +
+
+
+

At the left we can see...

+

At the right we can see the...

+

...the head-snarlers

+

Everything is safe. Perfectly safe.

+

Emo?

+

Watch out!

+

Are you hurt?

+

I don't think so. You?

+

I'm Ok.

+

Get up. Emo, it's not safe here.

+

Let's go.

+

What's next?

+

You'll see!

+

(howling wind)

+

Emo. This way.

+

Follow me!

+

(buzzing wires and chattery conversations)

+

Hurry Emo!

+

(louder telephone voices)

+

(phone ringing)

+

You're not paying attention!

+

I just want to answer the... ...phone.

+

Emo, look, I mean listen.

+

You have to learn to listen.

+

This is not some game.

+

You, i mean we, we could easily die out here.

+

Listen, listen to the sounds of the machine.

+

Listen to your breathing.

+

(Buzzing wires)

+

(laughing)

+

(oriental dance music)

+

Well, don't you ever get tired of this?

+

Tired?!?

+

Emo, the machine is like clockwork.

+

One move out of place...

+

...and you're ground to a pulp.

+

But isn't it -

+

Pulp, Emo! Is that what you want, pulp?

+

Emo, your goal in life...

+

...pulp?

+

(loud metal sounds)

+

Emo, close your eyes.

+

Why? - Now!

+

Ok.

+

Good.

+

What do you see at your left side, Emo?

+

Nothing. - Really?

+

No, nothing at all.

+

And at your right, what do you see at your right side, Emo?

+

The same Proog, exactly the same...

+

...nothing! - Great.

+

(sound of camera flash)

+

(engine drone)

+

Listen Proog! Do you hear that! (amusement park music)

+

Can we go here?

+

There? It isn't safe, Emo.

+

But... - Trust me, it's not.

+

Maybe I could...

+

No.

+

NO!

+

Any further questions, Emo?

+

No.

+

Emo?

+

Emo, why...

+

Emo...

+

...why can't you see the beauty of this place?

+

The way it works.

+

How perfect it is.

+

No, Proog, I don't see.

+

I don't see because there's nothing there.

+

And why should I trust my life to something that isn't there?

+

Well can you tell me that?

+

Answer me!

+

Proog...

+

...you're a sick man!

+

Stay away from me!

+

No! Emo! It's a trap!

+

Hah, it's a trap.

+

At the left side you can see|the hanging gardens of Babylon!

+

How's that for a trap?

+

No, Emo.

+

At the right side you can see... ...well guess what...

+

...the colossus of Rhodes!

+

No!

+

The colossus of Rhodes and it is here just for you Proog.

+

It is there...

+

I'm telling you, Emo...

+

...it is.

+

(howling wind)

+ +
+
+ + + +
+
+ + +
+
+
+
+
+
+ +
+ + +
+
+ + \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/lib/StrobeMediaPlayer.js b/lib/osmf/player/StrobeMediaPlayback/html-template/lib/StrobeMediaPlayer.js index 3a4e6d9..ecbe87f 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/lib/StrobeMediaPlayer.js +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/lib/StrobeMediaPlayer.js @@ -1,100 +1,100 @@ -var strobeMediaPlayback = function () { - var settings = { - "tablet": { - "startSize": {"width":480, "height":268}, - "wmode": "direct" - }, - "smartphone": { - "startSize": {"width":120, "height":67}, - "wmode": "direct" - }, - "default": { - "startSize": {"width":480, "height":268}, - "wmode": "direct" - } - }; - - var flashvars = {}; - - function getSettingByDeviceType(setting, deviceType, defaultValue) { - if (deviceType in settings) { - return (settings[deviceType][setting] ? settings[deviceType][setting] : defaultValue); - } - else { - return (settings["default"][setting] ? settings["default"][setting] : defaultValue); - } - } - - return { - settings: function(object) { - settings = $.extend(true, settings, object); - }, - flashvars: function(object) { - flashvars = $.extend(true, flashvars, object); - }, - draw: function(element) { - if (element && flashvars && flashvars["src"]) { - var agent = window.location.hash.replace(/^#/, ""); - - function onDeviceDetection(device) { - var startSize = getSettingByDeviceType("startSize", device.getProfile().type, ""); - if (device.profileDetected() && device.useFlash()) { - if (device.getProfile().type == "tablet" || device.getProfile().type == "smartphone"){ - flashvars.skin = "skins/"+device.getProfile().type+"-skin.xml"; - flashvars.controlBarType = device.getProfile().type; - flashvars.playButtonOverlay = false; - } - var params = settings[(device.getProfile().type in settings ? device.getProfile().type : "default")]; - params["movie"] = "StrobeMediaPlayback.swf"; - params["allowfullscreen"] = "true"; - params["allowscriptaccess"] = "always"; - - var attributes = {}; - - $("#" + element).parent().css("width",startSize["width"]); - $("#" + element).parent().css("height",startSize["height"]); - - swfobject.embedSWF( - "StrobeMediaPlayback.swf", - element, - startSize["width"], - startSize["height"], - "10.1.0", - "", - flashvars, - params, - attributes - ); - } - else { - var html5divs = - '
' + - '
' + - '
' + - '
Play/Pause
' + - '
0:00
' + - '
' + - '' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
0:00
' + - '
Full View
' + - '
' + - '' + - '
'; - $("#" + element).html(html5divs); - $("#" + element + " .html5player").strobemediaplaybackhtml5(); - } - } - - new DeviceDetection(agent).addCallback(onDeviceDetection).addProfiles(profiles).detect(); - } - } - } +var strobeMediaPlayback = function () { + var settings = { + "tablet": { + "startSize": {"width":480, "height":268}, + "wmode": "direct" + }, + "smartphone": { + "startSize": {"width":120, "height":67}, + "wmode": "direct" + }, + "default": { + "startSize": {"width":480, "height":268}, + "wmode": "direct" + } + }; + + var flashvars = {}; + + function getSettingByDeviceType(setting, deviceType, defaultValue) { + if (deviceType in settings) { + return (settings[deviceType][setting] ? settings[deviceType][setting] : defaultValue); + } + else { + return (settings["default"][setting] ? settings["default"][setting] : defaultValue); + } + } + + return { + settings: function(object) { + settings = $.extend(true, settings, object); + }, + flashvars: function(object) { + flashvars = $.extend(true, flashvars, object); + }, + draw: function(element) { + if (element && flashvars && flashvars["src"]) { + var agent = window.location.hash.replace(/^#/, ""); + + function onDeviceDetection(device) { + var startSize = getSettingByDeviceType("startSize", device.getProfile().type, ""); + if (device.profileDetected() && device.useFlash()) { + if (device.getProfile().type == "tablet" || device.getProfile().type == "smartphone"){ + flashvars.skin = "skins/"+device.getProfile().type+"-skin.xml"; + flashvars.controlBarType = device.getProfile().type; + flashvars.playButtonOverlay = false; + } + var params = settings[(device.getProfile().type in settings ? device.getProfile().type : "default")]; + params["movie"] = "StrobeMediaPlayback.swf"; + params["allowfullscreen"] = "true"; + params["allowscriptaccess"] = "always"; + + var attributes = {}; + + $("#" + element).parent().css("width",startSize["width"]); + $("#" + element).parent().css("height",startSize["height"]); + + swfobject.embedSWF( + "StrobeMediaPlayback.swf", + element, + startSize["width"], + startSize["height"], + "10.1.0", + "", + flashvars, + params, + attributes + ); + } + else { + var html5divs = + '
' + + '
' + + '
' + + '
Play/Pause
' + + '
0:00
' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
0:00
' + + '
Full View
' + + '
' + + '' + + '
'; + $("#" + element).html(html5divs); + $("#" + element + " .html5player").strobemediaplaybackhtml5(); + } + } + + new DeviceDetection(agent).addCallback(onDeviceDetection).addProfiles(profiles).detect(); + } + } + } }(); \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/lib/devicedetection.js b/lib/osmf/player/StrobeMediaPlayback/html-template/lib/devicedetection.js index d6c8dc4..c12fe1e 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/lib/devicedetection.js +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/lib/devicedetection.js @@ -1,210 +1,210 @@ -/*********************************************************** - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - * - **********************************************************/ - -/** - * Constructor - * @param userAgent Override the default detection of the user agent - */ -function DeviceDetection(userAgent){ - /** Storage for callbacks */ - this.callbacks = new Array(); - /** Selected user agent */ - this.userAgent = userAgent && typeof(userAgent) == "string" ? userAgent : navigator.userAgent; - /** Profiles list */ - this.profiles = []; - /** Default profile */ - this.selectedProfile = this.profiles[0]; -}; - -/** - * Loads and parses JSON. If a 'successCallback' is not provided, the - * Expected format: {regex} - * @param xml XML to process - */ -DeviceDetection.prototype.addProfiles = function(list){ - var len = list.settings.length; - var value; - var settings = {}; - for(var i = 0; i < len; i++){ - value = list.settings[i]; - settings[value.type] = { quality: value.quality, - flashenabled: value.flashenabled == "true", - flashfirst: value.flashfirst == "true"}; - } - len = list.profiles.length; - for(var i = 0; i < len; i++){ - value = list.profiles[i]; - //generate a profile object - profile = { name: value.name, - type: value.type, - regex: value.regex}; - - var quality = value.quality; - switch(quality){ - case "hd": - case "sd": - case "mobile": - profile.quality = quality; - break; - default: - profile.quality = settings[profile.type] == null ? "sd" : settings[profile.type].quality; - break; - } - - profile.flashenabled = value.flashenabled == "undefined" ? settings[profile.type].flashenabled == "true" : value.flashenabled == "true"; - profile.flashfirst = value.flashfirst == "undefined" ? settings[profile.type].flashfirst == "true" : value.flashfirst == "true"; - this.addProfile(profile); - } - return this; -} - -/** - * Loads and parses XML. If a 'successCallback' is not provided, the - * Expected format: {regex} - * @param xml XML to process - */ -DeviceDetection.prototype.loadProfilesXML = function(url, successCallback){ - if(!jQuery){ - if(console) console.error("Could not find jQuery."); - return false; - } - //create a proxy so it can be accessed inside the jquery loop (each) - var thisProxy = this; - //use jquery to load the profiles xml - $.get(url, - function(data){ //result function - var profile; - var settings = {}; - $(data).find("setting").each(function(index){ - settings[$(this).attr("type")] = { quality: $(this).attr("quality"), - flashenabled: $(this).attr("flashenabled") == "true", - flashfirst: $(this).attr("flashfirst") == "true"}; - }); - $(data).find("profile").each(function(index){ //loop over each profile - //generate a profile object - profile = { name: $(this).attr("name"), - type: $(this).attr("type"), - regex: $(this).text()}; - - var quality = $(this).attr("quality"); - switch(quality){ - case "hd": - case "sd": - case "mobile": - profile.quality = quality; - break; - default: - profile.quality = settings[profile.type] == null ? "sd" : settings[profile.type].quality; - break; - } - - profile.flashenabled = $(this).attr("flashenabled") == "undefined" ? settings[profile.type].flashenabled == "true" : $(this).attr("flashenabled") == "true"; - profile.flashfirst = $(this).attr("flashfirst") == "undefined" ? settings[profile.type].flashfirst == "true" : $(this).attr("flashfirst") == "true"; - thisProxy.addProfile(profile); - }); - if(typeof(successCallback) == "function") successCallback(thisProxy); - }, "xml"); -} - -/** - * Adds a callback to handle the execute result - */ -DeviceDetection.prototype.addCallback = function(callback){ - if(typeof(callback) == "function"){ - this.callbacks.push(callback); - } - return this; //allow method chaining -} - -/** - * Executes processing of the userAgent - */ -DeviceDetection.prototype.detect = function(){ - var thisProxy = this; - var len = this.profiles.length; - var item; - for(var i = 0; i < len; i++){ - item = this.profiles[i]; - if(thisProxy.userAgent.search(item.regex) != -1){ - this.selectedProfile = item; - break; - } - } - - if(this.selectedProfile == null){ - //TODO handle this case - } - - //Protect from user generated errors - if(this.callbacks && typeof(this.callbacks) == "object" && this.callbacks.length > 0){ - var len = this.callbacks.length; - for(var i = 0; i < len; i++){ - try{ - this.callbacks[i](this); - }catch(error){ - if(console) console.log("[Error] " + error.message); - } - } - } - - return this; //allow method chaining -}; - -/** - * Set a specific profile to override the defaults - * @param name Profile name - * @param profile Object containing valid profile values - */ -DeviceDetection.prototype.addProfile = function(profile){ - if(typeof(profile) != "object"){ - if(console) console.error("Setting a profile requires a valid object."); - return this; //object must be an Object - } - - //TODO require all fields here? - - if(typeof(profile.regex) == "string"){ - profile.regex = new RegExp(profile.regex, "i"); //should we make the regex flags dynamic? - } - - this.profiles.push(profile); - - return this; -} - -//ACCESSORS - -DeviceDetection.prototype.profileDetected = function(){ - return this.selectedProfile != null; -} - -/** - * Simple call to determine whether to use Flash or not - */ -DeviceDetection.prototype.useFlash = function(){ - if(this.flashFirst() && this.flashEnabled()) return true; - else return this.flashEnabled(); -} - -DeviceDetection.prototype.getProfile = function(){ return this.selectedProfile; } -DeviceDetection.prototype.type = function(){ return this.profileDetected() ? this.selectedProfile.type : null; } -DeviceDetection.prototype.flashEnabled = function(){ return this.profileDetected() ? this.selectedProfile.flashenabled : null; } -DeviceDetection.prototype.flashFirst = function(){ return this.profileDetected() ? this.selectedProfile.flashfirst : null; } +/*********************************************************** + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + **********************************************************/ + +/** + * Constructor + * @param userAgent Override the default detection of the user agent + */ +function DeviceDetection(userAgent){ + /** Storage for callbacks */ + this.callbacks = new Array(); + /** Selected user agent */ + this.userAgent = userAgent && typeof(userAgent) == "string" ? userAgent : navigator.userAgent; + /** Profiles list */ + this.profiles = []; + /** Default profile */ + this.selectedProfile = this.profiles[0]; +}; + +/** + * Loads and parses JSON. If a 'successCallback' is not provided, the + * Expected format: {regex} + * @param xml XML to process + */ +DeviceDetection.prototype.addProfiles = function(list){ + var len = list.settings.length; + var value; + var settings = {}; + for(var i = 0; i < len; i++){ + value = list.settings[i]; + settings[value.type] = { quality: value.quality, + flashenabled: value.flashenabled == "true", + flashfirst: value.flashfirst == "true"}; + } + len = list.profiles.length; + for(var i = 0; i < len; i++){ + value = list.profiles[i]; + //generate a profile object + profile = { name: value.name, + type: value.type, + regex: value.regex}; + + var quality = value.quality; + switch(quality){ + case "hd": + case "sd": + case "mobile": + profile.quality = quality; + break; + default: + profile.quality = settings[profile.type] == null ? "sd" : settings[profile.type].quality; + break; + } + + profile.flashenabled = value.flashenabled == "undefined" ? settings[profile.type].flashenabled == "true" : value.flashenabled == "true"; + profile.flashfirst = value.flashfirst == "undefined" ? settings[profile.type].flashfirst == "true" : value.flashfirst == "true"; + this.addProfile(profile); + } + return this; +} + +/** + * Loads and parses XML. If a 'successCallback' is not provided, the + * Expected format: {regex} + * @param xml XML to process + */ +DeviceDetection.prototype.loadProfilesXML = function(url, successCallback){ + if(!jQuery){ + if(console) console.error("Could not find jQuery."); + return false; + } + //create a proxy so it can be accessed inside the jquery loop (each) + var thisProxy = this; + //use jquery to load the profiles xml + $.get(url, + function(data){ //result function + var profile; + var settings = {}; + $(data).find("setting").each(function(index){ + settings[$(this).attr("type")] = { quality: $(this).attr("quality"), + flashenabled: $(this).attr("flashenabled") == "true", + flashfirst: $(this).attr("flashfirst") == "true"}; + }); + $(data).find("profile").each(function(index){ //loop over each profile + //generate a profile object + profile = { name: $(this).attr("name"), + type: $(this).attr("type"), + regex: $(this).text()}; + + var quality = $(this).attr("quality"); + switch(quality){ + case "hd": + case "sd": + case "mobile": + profile.quality = quality; + break; + default: + profile.quality = settings[profile.type] == null ? "sd" : settings[profile.type].quality; + break; + } + + profile.flashenabled = $(this).attr("flashenabled") == "undefined" ? settings[profile.type].flashenabled == "true" : $(this).attr("flashenabled") == "true"; + profile.flashfirst = $(this).attr("flashfirst") == "undefined" ? settings[profile.type].flashfirst == "true" : $(this).attr("flashfirst") == "true"; + thisProxy.addProfile(profile); + }); + if(typeof(successCallback) == "function") successCallback(thisProxy); + }, "xml"); +} + +/** + * Adds a callback to handle the execute result + */ +DeviceDetection.prototype.addCallback = function(callback){ + if(typeof(callback) == "function"){ + this.callbacks.push(callback); + } + return this; //allow method chaining +} + +/** + * Executes processing of the userAgent + */ +DeviceDetection.prototype.detect = function(){ + var thisProxy = this; + var len = this.profiles.length; + var item; + for(var i = 0; i < len; i++){ + item = this.profiles[i]; + if(thisProxy.userAgent.search(item.regex) != -1){ + this.selectedProfile = item; + break; + } + } + + if(this.selectedProfile == null){ + //TODO handle this case + } + + //Protect from user generated errors + if(this.callbacks && typeof(this.callbacks) == "object" && this.callbacks.length > 0){ + var len = this.callbacks.length; + for(var i = 0; i < len; i++){ + try{ + this.callbacks[i](this); + }catch(error){ + if(console) console.log("[Error] " + error.message); + } + } + } + + return this; //allow method chaining +}; + +/** + * Set a specific profile to override the defaults + * @param name Profile name + * @param profile Object containing valid profile values + */ +DeviceDetection.prototype.addProfile = function(profile){ + if(typeof(profile) != "object"){ + if(console) console.error("Setting a profile requires a valid object."); + return this; //object must be an Object + } + + //TODO require all fields here? + + if(typeof(profile.regex) == "string"){ + profile.regex = new RegExp(profile.regex, "i"); //should we make the regex flags dynamic? + } + + this.profiles.push(profile); + + return this; +} + +//ACCESSORS + +DeviceDetection.prototype.profileDetected = function(){ + return this.selectedProfile != null; +} + +/** + * Simple call to determine whether to use Flash or not + */ +DeviceDetection.prototype.useFlash = function(){ + if(this.flashFirst() && this.flashEnabled()) return true; + else return this.flashEnabled(); +} + +DeviceDetection.prototype.getProfile = function(){ return this.selectedProfile; } +DeviceDetection.prototype.type = function(){ return this.profileDetected() ? this.selectedProfile.type : null; } +DeviceDetection.prototype.flashEnabled = function(){ return this.profileDetected() ? this.selectedProfile.flashenabled : null; } +DeviceDetection.prototype.flashFirst = function(){ return this.profileDetected() ? this.selectedProfile.flashfirst : null; } DeviceDetection.prototype.isMobile = function(){ return this.profileDetected() ? this.selectedProfile.type == "mobile" : false; } \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/lib/jquery-ui-1.8.14.custom.min.js b/lib/osmf/player/StrobeMediaPlayback/html-template/lib/jquery-ui-1.8.14.custom.min.js index d194918..f630e50 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/lib/jquery-ui-1.8.14.custom.min.js +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/lib/jquery-ui-1.8.14.custom.min.js @@ -1,100 +1,100 @@ -/*! - * jQuery UI 1.8.14 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.14", -keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus(); -b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this, -"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection", -function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth, -outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a,"tabindex"),d=isNaN(b); -return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e= -0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= -false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -;/* - * jQuery UI Draggable 1.8.14 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== -"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= -this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('
').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;this.helper= -this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true}, -_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b= -false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, -10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle|| -!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&& -a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= -this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"), -10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), -10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, -(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!= -"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"), -10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+ -this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&& -!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.leftg[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.topg[3])?h:!(h-this.offset.click.topg[2])?e:!(e-this.offset.click.left=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e= +0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= +false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); +;/* + * jQuery UI Draggable 1.8.14 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */ +(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== +"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= +this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('
').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;this.helper= +this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); +this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true}, +_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b= +false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, +10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle|| +!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&& +a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= +this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"), +10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), +10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, +(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!= +"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"), +10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+ +this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&& +!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.leftg[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.topg[3])?h:!(h-this.offset.click.topg[2])?e:!(e-this.offset.click.left=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e 0) event.data.player.currentTime = time; - if(event.data.player.paused) event.data.onPause(event); - else event.data.onPlay(event); - }, - - onClick: function(event){ - if(event.data.player.ended) event.data.hideControls(event); - else event.data.onMouseMove(event); - }, - - onDoubleClick: function(event){ - event.data.onFullViewClick(event); - }, - - onFullViewClick: function(event){ - try{ - if(event.data.fullview.hasClass("disabled")) return; //do not do anything if the button is disabled - if(navigator.userAgent.match(/(Macintosh|Windows|Safari|Version\/5\.[1-9])/gi).length >= 3){ //at a minimum match one of the OSes, Safari, and the version - if($(document).context.webkitIsFullScreen) $(document).context.webkitCancelFullScreen(); - else event.data.$element.context.webkitRequestFullScreen(); - }else event.data.player.webkitEnterFullScreen(); - }catch(error){ - event.data.onFullscreenChange(event); - } - }, - - onFullscreenChange: function(event){ - event.data.$element.toggleClass(event.data.options.fullscreenclass); - - event.data.fullview.toggleClass(event.data.options.fullviewactiveclass); - - event.data.trackswidth = event.data.tracks.width(); - if(event.data.player.ended) event.data.onTimeUpdate(event); - }, - - onTimeUpdate: function(event){ - var percent = event.data.player.currentTime/event.data.player.duration; - var px = percent*event.data.trackswidth; - event.data.playedbar.css("width", px+"px"); - if(!event.data.isdragging) event.data.slider.css("left", px+"px"); - var times = formatTimeStatus(event.data.player.currentTime, event.data.player.duration); - event.data.currenttime.html(times[0]); - event.data.duration.html(times[1]); - }, - - onError: function(event){ - var message; - switch (event.target.error.code) { - case event.target.error.MEDIA_ERR_ABORTED: - message = 'You aborted the video playback.'; - break; - case event.target.error.MEDIA_ERR_NETWORK: - message = 'A network error caused the video download to fail part-way.'; - break; - case event.target.error.MEDIA_ERR_DECODE: - message = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support.'; - break; - case event.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: - message = 'The video could not be loaded, either because the server or network failed or because the format is not supported.'; - break; - default: - message = 'An unknown error occurred.'; - break; - } - event.data.errorwindow.html(message); - event.data.errorwindow.show(); - }, - - showControls: function(){ - if(this.controlbar.is(":visible")) return; - this.controlbar.fadeIn(this.options.fadeinspeed); - }, - - hideControls: function(event){ - if(event.data.player.paused && !event.data.player.ended) return; - event.data.controlbar.fadeOut(event.data.options.fadeoutspeed); - } - }; - - StrobeMediaPlaybackHtml5.prototype = strobeMediaPlaybackHtml5Methods; - - /** - * jQuery plugin hook - */ - $.fn.strobemediaplaybackhtml5 = function(options){ - var instances = [], i; - var result = this.each(function(){ - instances.push(new StrobeMediaPlaybackHtml5(this, options)); - }); - - for (i = 0; i < instances.length; i++) { - instances[i].initialize(); - } - return result; - }; - - /** - * jQuery plugin defaults - */ - $.fn.strobemediaplaybackhtml5.defaults = { - autoplay: false, - hidedelay: 6000, - fadeinspeed: "fast", - fadeoutspeed: 500, - controlbarselector: ".controls", - progressbarselector: ".progress", - tracksselector: ".tracks", - sliderselector: ".slider", - seekbarselector: ".seeking", - playedbarselector: ".played", - bufferedbarselector: ".buffered", - playtoggleselector: ".icon.playtoggle", - currenttimeselector: ".timestamp.current", - durationtimeselector: ".timestamp.duration", - errorwindowselector: ".errorwindow", - fullviewselector: ".icon.fullview", - fullscreenclass: "fullscreen", - fullviewactiveclass: "fullscreen" - }; - - function formatTimeStatus(currentPosition, totalDuration){ - var h; - var m; - var s; - function prettyPrintSeconds(seconds, leadingMinutes, leadingHours){ - seconds = Math.floor(isNaN(seconds) ? 0 : Math.max(0, seconds)); - h = Math.floor(seconds / 3600); - m = Math.floor(seconds % 3600 / 60); - s = seconds % 60; - return ((h > 0 || leadingHours) ? (h + ":") : "") + - (((h > 0 || leadingMinutes) && m < 10) ? "0" : "") + - m + - ":" + - (s < 10 ? "0" : "") + - s; - } - - var totalDurationString = prettyPrintSeconds(totalDuration); - var currentPositionString = prettyPrintSeconds(currentPosition, h > 0 || m > 9, h > 0); - return [currentPositionString, totalDurationString]; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence +* (the "License"); you may not use this file except in +* compliance with the License. +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +/** + * + */ +(function($, undefined){ + /** + * + */ + var StrobeMediaPlaybackHtml5 = function(element, options){ + this.$window = $(window); + this.$document = $(document); + this.element = element; + this.$element = $(element); + this.options = $.extend({}, $.fn.strobemediaplaybackhtml5.defaults, options); + }; + + var strobeMediaPlaybackHtml5Methods = { + initialize: function(){ + $(document).bind('webkitfullscreenchange', this, this.onFullscreenChange); + + this.$element.bind("mousemove", this, this.onMouseMove); + + this.$player = this.$element.find("video"); //$("#" + this.options.id) + this.player = this.$player.get(0); + + this.$player.bind("timeupdate", this, this.onTimeUpdate); + this.$player.bind('play', this, this.onPlay); + this.$player.bind("playing", this, this.onPlaying); + this.$player.bind('pause', this, this.onPause); + this.$player.bind('ended', this, this.onEnded); + this.$player.bind("loadeddata", this, this.onLoadedData); + this.$player.bind("loadedmetadata", this, this.onMetaDataLoaded); + this.$player.bind("progress", this, this.onProgress); + this.$player.bind("click", this, this.onClick); + this.$player.bind("dblclick", this, this.onDoubleClick); + this.$player.bind("contextmenu", this, function(event){ event.preventDefault(); }); //disable context menu + + this.hidedelaytimeout, this.isdragging, this.trackswidth; + + this.controlbar = this.$element.find(this.options.controlbarselector); + + this.progressbar = this.controlbar.find(this.options.progressbarselector); + this.progressbar.bind('click', this, this.onSeekClick); + this.tracks = this.progressbar.find(this.options.tracksselector); + this.seekbar = this.progressbar.find(this.options.seekbarselector); + this.playedbar = this.progressbar.find(this.options.playedbarselector); + this.bufferbar = this.progressbar.find(this.options.bufferedbarselector); + + this.playtoggle = this.controlbar.find(this.options.playtoggleselector); + this.playtoggle.bind('click', this, this.onPlayToggleClick); + this.playtoggle.bind("mousedown mouseup touchstart touchend", this, this.onButtonHover); + + this.slider = this.controlbar.find(this.options.sliderselector); + this.slider.draggable({disabled: false, containment: "parent", axis: "x"}); + this.slider.bind("dragstart", this, this.onSliderDragStart); + this.slider.bind("drag", this, this.onSliderDragging); + this.slider.bind("dragstop", this, this.onSliderDragStop); + this.slider.bind("mousedown mouseup touchstart touchend", this, this.onButtonHover); + + this.fullview = this.controlbar.find(this.options.fullviewselector); + this.fullview.bind("click", this, this.onFullViewClick); + this.fullview.bind("mousedown mouseup touchstart touchend", this, this.onButtonHover); + + //disable the fullview button until metadata is loaded; necessary for iPad native fullscreen to work + this.fullview.addClass("disabled"); + + this.$player.attr("preload", "true"); //start loading the video, if not already started + + this.currenttime = this.controlbar.find(this.options.currenttimeselector); + this.duration = this.controlbar.find(this.options.durationtimeselector); + + this.errorwindow = this.$element.find(this.options.errorwindowselector); + + this.options.originalWidth = this.player.clientWidth; + if(this.options.autoplay) this.player.play(); + }, + + onSliderDragStart: function(event){ + event.data.isdragging = true; + event.data.seekbar.css("width", event.data.playedbar.width()+"px").show(); + }, + + onSliderDragging: function(event, ui){ + event.data.seekbar.css("width", ui.position.left+"px"); + }, + + onSliderDragStop: function(event, ui){ + event.data.isdragging = false; + event.data.seekbar.hide(); + event.data.player.currentTime = event.data.player.duration*((ui.position.left+event.data.slider.width()/2)/$(this).parent().width()); + event.data.onTimeUpdate(event); + }, + + onProgress: function(event){ + try{ + var start = event.target.buffered.start(); + var end = event.target.buffered.end() + var duration = event.target.duration; + event.data.bufferbar.css("width", ((end/duration)*100)+"%"); + }catch(exception){} + }, + + onPlay: function(event){ + event.data.playtoggle.addClass('paused'); + }, + + onPlaying: function(event){ + event.data.slider.draggable("option", "disabled", false); + }, + + onPause: function(event){ + event.data.playtoggle.removeClass('paused'); + }, + + onEnded: function(event){ + event.data.onPause(event); + event.data.showControls(); + }, + + onLoadedData: function(event){ + event.data.bufferbar.css("width", "100%"); + event.data.showControls(); + event.data.duration.html(formatTimeStatus(0, event.target.duration)[1]); + event.data.trackswidth = event.data.tracks.width(); + }, + + onMetaDataLoaded: function(event){ + event.data.fullview.removeClass("disabled"); + }, + + onMouseMove: function(event){ + event.data.showControls(); + if(!event.data.player.paused && !event.data.player.ended){ + clearTimeout(event.data.hidedelaytimeout); + event.data.hidedelaytimeout = setTimeout(function(){event.data.hideControls(event);}, event.data.options.hidedelay); + } + }, + + onButtonHover: function(event){ + $(this).toggleClass("hover"); + }, + + onPlayToggleClick: function(event){ + if(event.data.player.paused || event.data.player.ended) event.data.player.play(); + else event.data.player.pause(); + }, + + onSeekClick: function(event){ + var time = event.data.player.duration * ((event.clientX - event.data.progressbar.offset().left) / event.data.progressbar.outerWidth()); + if(time > 0) event.data.player.currentTime = time; + if(event.data.player.paused) event.data.onPause(event); + else event.data.onPlay(event); + }, + + onClick: function(event){ + if(event.data.player.ended) event.data.hideControls(event); + else event.data.onMouseMove(event); + }, + + onDoubleClick: function(event){ + event.data.onFullViewClick(event); + }, + + onFullViewClick: function(event){ + try{ + if(event.data.fullview.hasClass("disabled")) return; //do not do anything if the button is disabled + if(navigator.userAgent.match(/(Macintosh|Windows|Safari|Version\/5\.[1-9])/gi).length >= 3){ //at a minimum match one of the OSes, Safari, and the version + if($(document).context.webkitIsFullScreen) $(document).context.webkitCancelFullScreen(); + else event.data.$element.context.webkitRequestFullScreen(); + }else event.data.player.webkitEnterFullScreen(); + }catch(error){ + event.data.onFullscreenChange(event); + } + }, + + onFullscreenChange: function(event){ + event.data.$element.toggleClass(event.data.options.fullscreenclass); + + event.data.fullview.toggleClass(event.data.options.fullviewactiveclass); + + event.data.trackswidth = event.data.tracks.width(); + if(event.data.player.ended) event.data.onTimeUpdate(event); + }, + + onTimeUpdate: function(event){ + var percent = event.data.player.currentTime/event.data.player.duration; + var px = percent*event.data.trackswidth; + event.data.playedbar.css("width", px+"px"); + if(!event.data.isdragging) event.data.slider.css("left", px+"px"); + var times = formatTimeStatus(event.data.player.currentTime, event.data.player.duration); + event.data.currenttime.html(times[0]); + event.data.duration.html(times[1]); + }, + + onError: function(event){ + var message; + switch (event.target.error.code) { + case event.target.error.MEDIA_ERR_ABORTED: + message = 'You aborted the video playback.'; + break; + case event.target.error.MEDIA_ERR_NETWORK: + message = 'A network error caused the video download to fail part-way.'; + break; + case event.target.error.MEDIA_ERR_DECODE: + message = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support.'; + break; + case event.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: + message = 'The video could not be loaded, either because the server or network failed or because the format is not supported.'; + break; + default: + message = 'An unknown error occurred.'; + break; + } + event.data.errorwindow.html(message); + event.data.errorwindow.show(); + }, + + showControls: function(){ + if(this.controlbar.is(":visible")) return; + this.controlbar.fadeIn(this.options.fadeinspeed); + }, + + hideControls: function(event){ + if(event.data.player.paused && !event.data.player.ended) return; + event.data.controlbar.fadeOut(event.data.options.fadeoutspeed); + } + }; + + StrobeMediaPlaybackHtml5.prototype = strobeMediaPlaybackHtml5Methods; + + /** + * jQuery plugin hook + */ + $.fn.strobemediaplaybackhtml5 = function(options){ + var instances = [], i; + var result = this.each(function(){ + instances.push(new StrobeMediaPlaybackHtml5(this, options)); + }); + + for (i = 0; i < instances.length; i++) { + instances[i].initialize(); + } + return result; + }; + + /** + * jQuery plugin defaults + */ + $.fn.strobemediaplaybackhtml5.defaults = { + autoplay: false, + hidedelay: 6000, + fadeinspeed: "fast", + fadeoutspeed: 500, + controlbarselector: ".controls", + progressbarselector: ".progress", + tracksselector: ".tracks", + sliderselector: ".slider", + seekbarselector: ".seeking", + playedbarselector: ".played", + bufferedbarselector: ".buffered", + playtoggleselector: ".icon.playtoggle", + currenttimeselector: ".timestamp.current", + durationtimeselector: ".timestamp.duration", + errorwindowselector: ".errorwindow", + fullviewselector: ".icon.fullview", + fullscreenclass: "fullscreen", + fullviewactiveclass: "fullscreen" + }; + + function formatTimeStatus(currentPosition, totalDuration){ + var h; + var m; + var s; + function prettyPrintSeconds(seconds, leadingMinutes, leadingHours){ + seconds = Math.floor(isNaN(seconds) ? 0 : Math.max(0, seconds)); + h = Math.floor(seconds / 3600); + m = Math.floor(seconds % 3600 / 60); + s = seconds % 60; + return ((h > 0 || leadingHours) ? (h + ":") : "") + + (((h > 0 || leadingMinutes) && m < 10) ? "0" : "") + + m + + ":" + + (s < 10 ? "0" : "") + + s; + } + + var totalDurationString = prettyPrintSeconds(totalDuration); + var currentPositionString = prettyPrintSeconds(currentPosition, h > 0 || m > 9, h > 0); + return [currentPositionString, totalDurationString]; + } })(jQuery); \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/lib/jquery/jquery-1.4.2.js b/lib/osmf/player/StrobeMediaPlayback/html-template/lib/jquery/jquery-1.4.2.js index fff6776..5c4c146 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/lib/jquery/jquery-1.4.2.js +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/lib/jquery/jquery-1.4.2.js @@ -1,6240 +1,6240 @@ -/*! - * jQuery JavaScript Library v1.4.2 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Sat Feb 13 22:33:48 2010 -0500 - */ -(function( window, undefined ) { - -// Define a local copy of jQuery -var jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context ); - }, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - - // A central reference to the root jQuery(document) - rootjQuery, - - // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/, - - // Is it a simple selector - isSimple = /^.[^:#\[\.,]*$/, - - // Check if a string has a non-whitespace character in it - rnotwhite = /\S/, - - // Used for trimming whitespace - rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, - - // Keep a UserAgent string for use with jQuery.browser - userAgent = navigator.userAgent, - - // For matching the engine and version of the browser - browserMatch, - - // Has the ready events already been bound? - readyBound = false, - - // The functions to execute on DOM ready - readyList = [], - - // The ready event handler - DOMContentLoaded, - - // Save a reference to some core methods - toString = Object.prototype.toString, - hasOwnProperty = Object.prototype.hasOwnProperty, - push = Array.prototype.push, - slice = Array.prototype.slice, - indexOf = Array.prototype.indexOf; - -jQuery.fn = jQuery.prototype = { - init: function( selector, context ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), or $(undefined) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // The body element only exists once, optimize finding it - if ( selector === "body" && !context ) { - this.context = document; - this[0] = document.body; - this.selector = "body"; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - match = quickExpr.exec( selector ); - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - doc = (context ? context.ownerDocument || context : document); - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - ret = rsingleTag.exec( selector ); - - if ( ret ) { - if ( jQuery.isPlainObject( context ) ) { - selector = [ document.createElement( ret[1] ) ]; - jQuery.fn.attr.call( selector, context, true ); - - } else { - selector = [ doc.createElement( ret[1] ) ]; - } - - } else { - ret = buildFragment( [ match[1] ], [ doc ] ); - selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; - } - - return jQuery.merge( this, selector ); - - // HANDLE: $("#id") - } else { - elem = document.getElementById( match[2] ); - - if ( elem ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $("TAG") - } else if ( !context && /^\w+$/.test( selector ) ) { - this.selector = selector; - this.context = document; - selector = document.getElementsByTagName( selector ); - return jQuery.merge( this, selector ); - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return (context || rootjQuery).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return jQuery( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if (selector.selector !== undefined) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.4.2", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return slice.call( this, 0 ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - // Build a new jQuery matched element set - var ret = jQuery(); - - if ( jQuery.isArray( elems ) ) { - push.apply( ret, elems ); - - } else { - jQuery.merge( ret, elems ); - } - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + (this.selector ? " " : "") + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Attach the listeners - jQuery.bindReady(); - - // If the DOM is already ready - if ( jQuery.isReady ) { - // Execute the function immediately - fn.call( document, jQuery ); - - // Otherwise, remember the function for later - } else if ( readyList ) { - // Add the function to the wait list - readyList.push( fn ); - } - - return this; - }, - - eq: function( i ) { - return i === -1 ? - this.slice( i ) : - this.slice( i, +i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ), - "slice", slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || jQuery(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - // copy reference to target object - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging object literal values or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { - var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src - : jQuery.isArray(copy) ? [] : {}; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - window.$ = _$; - - if ( deep ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // Handle when the DOM is ready - ready: function() { - // Make sure that the DOM is not already loaded - if ( !jQuery.isReady ) { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 13 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If there are functions bound, to execute - if ( readyList ) { - // Execute all of them - var fn, i = 0; - while ( (fn = readyList[ i++ ]) ) { - fn.call( document, jQuery ); - } - - // Reset the list of functions - readyList = null; - } - - // Trigger any bound ready events - if ( jQuery.fn.triggerHandler ) { - jQuery( document ).triggerHandler( "ready" ); - } - } - }, - - bindReady: function() { - if ( readyBound ) { - return; - } - - readyBound = true; - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" ) { - return jQuery.ready(); - } - - // Mozilla, Opera and webkit nightlies currently support this event - if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else if ( document.attachEvent ) { - // ensure firing before onload, - // maybe late but safe also for iframes - document.attachEvent("onreadystatechange", DOMContentLoaded); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var toplevel = false; - - try { - toplevel = window.frameElement == null; - } catch(e) {} - - if ( document.documentElement.doScroll && toplevel ) { - doScrollCheck(); - } - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return toString.call(obj) === "[object Function]"; - }, - - isArray: function( obj ) { - return toString.call(obj) === "[object Array]"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { - return false; - } - - // Not own constructor property must be Object - if ( obj.constructor - && !hasOwnProperty.call(obj, "constructor") - && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || hasOwnProperty.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - for ( var name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw msg; - }, - - parseJSON: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") - .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") - .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { - - // Try to use the native JSON parser first - return window.JSON && window.JSON.parse ? - window.JSON.parse( data ) : - (new Function("return " + data))(); - - } else { - jQuery.error( "Invalid JSON: " + data ); - } - }, - - noop: function() {}, - - // Evalulates a script in a global context - globalEval: function( data ) { - if ( data && rnotwhite.test(data) ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.getElementsByTagName("head")[0] || document.documentElement, - script = document.createElement("script"); - - script.type = "text/javascript"; - - if ( jQuery.support.scriptEval ) { - script.appendChild( document.createTextNode( data ) ); - } else { - script.text = data; - } - - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709). - head.insertBefore( script, head.firstChild ); - head.removeChild( script ); - } - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - var name, i = 0, - length = object.length, - isObj = length === undefined || jQuery.isFunction(object); - - if ( args ) { - if ( isObj ) { - for ( name in object ) { - if ( callback.apply( object[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( object[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in object ) { - if ( callback.call( object[ name ], name, object[ name ] ) === false ) { - break; - } - } - } else { - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} - } - } - - return object; - }, - - trim: function( text ) { - return (text || "").replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( array, results ) { - var ret = results || []; - - if ( array != null ) { - // The window, strings (and functions) also have 'length' - // The extra typeof function check is to prevent crashes - // in Safari 2 (See: #3039) - if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { - push.call( ret, array ); - } else { - jQuery.merge( ret, array ); - } - } - - return ret; - }, - - inArray: function( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; - }, - - merge: function( first, second ) { - var i = first.length, j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var ret = []; - - // Go through the array, only saving the items - // that pass the validator function - for ( var i = 0, length = elems.length; i < length; i++ ) { - if ( !inv !== !callback( elems[ i ], i ) ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var ret = [], value; - - // Go through the array, translating each of the items to their - // new value (or values). - for ( var i = 0, length = elems.length; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - proxy: function( fn, proxy, thisObject ) { - if ( arguments.length === 2 ) { - if ( typeof proxy === "string" ) { - thisObject = fn; - fn = thisObject[ proxy ]; - proxy = undefined; - - } else if ( proxy && !jQuery.isFunction( proxy ) ) { - thisObject = proxy; - proxy = undefined; - } - } - - if ( !proxy && fn ) { - proxy = function() { - return fn.apply( thisObject || this, arguments ); - }; - } - - // Set the guid of unique handler to the same of original handler, so it can be removed - if ( fn ) { - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - } - - // So proxy can be declared as an argument - return proxy; - }, - - // Use of jQuery.browser is frowned upon. - // More details: http://docs.jquery.com/Utilities/jQuery.browser - uaMatch: function( ua ) { - ua = ua.toLowerCase(); - - var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || - []; - - return { browser: match[1] || "", version: match[2] || "0" }; - }, - - browser: {} -}); - -browserMatch = jQuery.uaMatch( userAgent ); -if ( browserMatch.browser ) { - jQuery.browser[ browserMatch.browser ] = true; - jQuery.browser.version = browserMatch.version; -} - -// Deprecated, use jQuery.browser.webkit instead -if ( jQuery.browser.webkit ) { - jQuery.browser.safari = true; -} - -if ( indexOf ) { - jQuery.inArray = function( elem, array ) { - return indexOf.call( array, elem ); - }; -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); - -// Cleanup functions for the document ready method -if ( document.addEventListener ) { - DOMContentLoaded = function() { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - }; - -} else if ( document.attachEvent ) { - DOMContentLoaded = function() { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }; -} - -// The DOM ready check for Internet Explorer -function doScrollCheck() { - if ( jQuery.isReady ) { - return; - } - - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); - } catch( error ) { - setTimeout( doScrollCheck, 1 ); - return; - } - - // and execute any waiting functions - jQuery.ready(); -} - -function evalScript( i, elem ) { - if ( elem.src ) { - jQuery.ajax({ - url: elem.src, - async: false, - dataType: "script" - }); - } else { - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } -} - -// Mutifunctional method to get and set values to a collection -// The value/s can be optionally by executed if its a function -function access( elems, key, value, exec, fn, pass ) { - var length = elems.length; - - // Setting many attributes - if ( typeof key === "object" ) { - for ( var k in key ) { - access( elems, k, key[k], exec, fn, value ); - } - return elems; - } - - // Setting one attribute - if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = !pass && exec && jQuery.isFunction(value); - - for ( var i = 0; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - - return elems; - } - - // Getting an attribute - return length ? fn( elems[0], key ) : undefined; -} - -function now() { - return (new Date).getTime(); -} -(function() { - - jQuery.support = {}; - - var root = document.documentElement, - script = document.createElement("script"), - div = document.createElement("div"), - id = "script" + now(); - - div.style.display = "none"; - div.innerHTML = "
a"; - - var all = div.getElementsByTagName("*"), - a = div.getElementsByTagName("a")[0]; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return; - } - - jQuery.support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: div.firstChild.nodeType === 3, - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText insted) - style: /red/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: a.getAttribute("href") === "/a", - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55$/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: div.getElementsByTagName("input")[0].value === "on", - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected, - - parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null, - - // Will be defined later - deleteExpando: true, - checkClone: false, - scriptEval: false, - noCloneEvent: true, - boxModel: null - }; - - script.type = "text/javascript"; - try { - script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); - } catch(e) {} - - root.insertBefore( script, root.firstChild ); - - // Make sure that the execution of code works by injecting a script - // tag with appendChild/createTextNode - // (IE doesn't support this, fails, and uses .text instead) - if ( window[ id ] ) { - jQuery.support.scriptEval = true; - delete window[ id ]; - } - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete script.test; - - } catch(e) { - jQuery.support.deleteExpando = false; - } - - root.removeChild( script ); - - if ( div.attachEvent && div.fireEvent ) { - div.attachEvent("onclick", function click() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - jQuery.support.noCloneEvent = false; - div.detachEvent("onclick", click); - }); - div.cloneNode(true).fireEvent("onclick"); - } - - div = document.createElement("div"); - div.innerHTML = ""; - - var fragment = document.createDocumentFragment(); - fragment.appendChild( div.firstChild ); - - // WebKit doesn't clone checked state correctly in fragments - jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; - - // Figure out if the W3C box model works as expected - // document.body must exist before we can do this - jQuery(function() { - var div = document.createElement("div"); - div.style.width = div.style.paddingLeft = "1px"; - - document.body.appendChild( div ); - jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; - document.body.removeChild( div ).style.display = 'none'; - - div = null; - }); - - // Technique from Juriy Zaytsev - // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - var eventSupported = function( eventName ) { - var el = document.createElement("div"); - eventName = "on" + eventName; - - var isSupported = (eventName in el); - if ( !isSupported ) { - el.setAttribute(eventName, "return;"); - isSupported = typeof el[eventName] === "function"; - } - el = null; - - return isSupported; - }; - - jQuery.support.submitBubbles = eventSupported("submit"); - jQuery.support.changeBubbles = eventSupported("change"); - - // release memory in IE - root = script = div = all = a = null; -})(); - -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; -var expando = "jQuery" + now(), uuid = 0, windowData = {}; - -jQuery.extend({ - cache: {}, - - expando:expando, - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - "object": true, - "applet": true - }, - - data: function( elem, name, data ) { - if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { - return; - } - - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ], cache = jQuery.cache, thisCache; - - if ( !id && typeof name === "string" && data === undefined ) { - return null; - } - - // Compute a unique ID for the element - if ( !id ) { - id = ++uuid; - } - - // Avoid generating a new cache unless none exists and we - // want to manipulate it. - if ( typeof name === "object" ) { - elem[ expando ] = id; - thisCache = cache[ id ] = jQuery.extend(true, {}, name); - - } else if ( !cache[ id ] ) { - elem[ expando ] = id; - cache[ id ] = {}; - } - - thisCache = cache[ id ]; - - // Prevent overriding the named cache with undefined values - if ( data !== undefined ) { - thisCache[ name ] = data; - } - - return typeof name === "string" ? thisCache[ name ] : thisCache; - }, - - removeData: function( elem, name ) { - if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { - return; - } - - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ]; - - // If we want to remove a specific section of the element's data - if ( name ) { - if ( thisCache ) { - // Remove the section of cache data - delete thisCache[ name ]; - - // If we've removed all the data, remove the element's cache - if ( jQuery.isEmptyObject(thisCache) ) { - jQuery.removeData( elem ); - } - } - - // Otherwise, we want to remove all of the element's data - } else { - if ( jQuery.support.deleteExpando ) { - delete elem[ jQuery.expando ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( jQuery.expando ); - } - - // Completely remove the data cache - delete cache[ id ]; - } - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - if ( typeof key === "undefined" && this.length ) { - return jQuery.data( this[0] ); - - } else if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - var parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value === undefined ) { - var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - if ( data === undefined && this.length ) { - data = jQuery.data( this[0], key ); - } - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } else { - return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() { - jQuery.data( this, key, value ); - }); - } - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); -jQuery.extend({ - queue: function( elem, type, data ) { - if ( !elem ) { - return; - } - - type = (type || "fx") + "queue"; - var q = jQuery.data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( !data ) { - return q || []; - } - - if ( !q || jQuery.isArray(data) ) { - q = jQuery.data( elem, type, jQuery.makeArray(data) ); - - } else { - q.push( data ); - } - - return q; - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), fn = queue.shift(); - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift("inprogress"); - } - - fn.call(elem, function() { - jQuery.dequeue(elem, type); - }); - } - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - } - - if ( data === undefined ) { - return jQuery.queue( this[0], type ); - } - return this.each(function( i, elem ) { - var queue = jQuery.queue( this, type, data ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; - type = type || "fx"; - - return this.queue( type, function() { - var elem = this; - setTimeout(function() { - jQuery.dequeue( elem, type ); - }, time ); - }); - }, - - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - } -}); -var rclass = /[\n\t]/g, - rspace = /\s+/, - rreturn = /\r/g, - rspecialurl = /href|src|style/, - rtype = /(button|input)/i, - rfocusable = /(button|input|object|select|textarea)/i, - rclickable = /^(a|area)$/i, - rradiocheck = /radio|checkbox/; - -jQuery.fn.extend({ - attr: function( name, value ) { - return access( this, name, value, true, jQuery.attr ); - }, - - removeAttr: function( name, fn ) { - return this.each(function(){ - jQuery.attr( this, name, "" ); - if ( this.nodeType === 1 ) { - this.removeAttribute( name ); - } - }); - }, - - addClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.addClass( value.call(this, i, self.attr("class")) ); - }); - } - - if ( value && typeof value === "string" ) { - var classNames = (value || "").split( rspace ); - - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className ) { - elem.className = value; - - } else { - var className = " " + elem.className + " ", setClass = elem.className; - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { - setClass += " " + classNames[c]; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.removeClass( value.call(this, i, self.attr("class")) ); - }); - } - - if ( (value && typeof value === "string") || value === undefined ) { - var classNames = (value || "").split(rspace); - - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; - - if ( elem.nodeType === 1 && elem.className ) { - if ( value ) { - var className = (" " + elem.className + " ").replace(rclass, " "); - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[c] + " ", " "); - } - elem.className = jQuery.trim( className ); - - } else { - elem.className = ""; - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this); - self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, i = 0, self = jQuery(this), - state = stateVal, - classNames = value.split( rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space seperated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery.data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " "; - for ( var i = 0, l = this.length; i < l; i++ ) { - if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - if ( value === undefined ) { - var elem = this[0]; - - if ( elem ) { - if ( jQuery.nodeName( elem, "option" ) ) { - return (elem.attributes.value || {}).specified ? elem.value : elem.text; - } - - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - if ( option.selected ) { - // Get the specifc value for the option - value = jQuery(option).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - } - - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { - return elem.getAttribute("value") === null ? "on" : elem.value; - } - - - // Everything else, we just grab the value - return (elem.value || "").replace(rreturn, ""); - - } - - return undefined; - } - - var isFunction = jQuery.isFunction(value); - - return this.each(function(i) { - var self = jQuery(this), val = value; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call(this, i, self.val()); - } - - // Typecast each time if the value is a Function and the appended - // value is therefore different each time. - if ( typeof val === "number" ) { - val += ""; - } - - if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { - this.checked = jQuery.inArray( self.val(), val ) >= 0; - - } else if ( jQuery.nodeName( this, "select" ) ) { - var values = jQuery.makeArray(val); - - jQuery( "option", this ).each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - this.selectedIndex = -1; - } - - } else { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - attrFn: { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true - }, - - attr: function( elem, name, value, pass ) { - // don't set attributes on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; - } - - if ( pass && name in jQuery.attrFn ) { - return jQuery(elem)[name](value); - } - - var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - // Whether we are setting (or getting) - set = value !== undefined; - - // Try to normalize/fix the name - name = notxml && jQuery.props[ name ] || name; - - // Only do all the following if this is a node (faster for style) - if ( elem.nodeType === 1 ) { - // These attributes require special treatment - var special = rspecialurl.test( name ); - - // Safari mis-reports the default selected property of an option - // Accessing the parent's selectedIndex property fixes it - if ( name === "selected" && !jQuery.support.optSelected ) { - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - - // If applicable, access the attribute via the DOM 0 way - if ( name in elem && notxml && !special ) { - if ( set ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } - - elem[ name ] = value; - } - - // browsers index elements by id/name on forms, give priority to attributes. - if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { - return elem.getAttributeNode( name ).nodeValue; - } - - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - if ( name === "tabIndex" ) { - var attributeNode = elem.getAttributeNode( "tabIndex" ); - - return attributeNode && attributeNode.specified ? - attributeNode.value : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - - return elem[ name ]; - } - - if ( !jQuery.support.style && notxml && name === "style" ) { - if ( set ) { - elem.style.cssText = "" + value; - } - - return elem.style.cssText; - } - - if ( set ) { - // convert the value to a string (all browsers do this but IE) see #1070 - elem.setAttribute( name, "" + value ); - } - - var attr = !jQuery.support.hrefNormalized && notxml && special ? - // Some attributes require a special call on IE - elem.getAttribute( name, 2 ) : - elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return attr === null ? undefined : attr; - } - - // elem is actually elem.style ... set the style - // Using attr for specific style information is now deprecated. Use style instead. - return jQuery.style( elem, name, value ); - } -}); -var rnamespaces = /\.(.*)$/, - fcleanup = function( nm ) { - return nm.replace(/[^\w\s\.\|`]/g, function( ch ) { - return "\\" + ch; - }); - }; - -/* - * A number of helper functions used for managing events. - * Many of the ideas behind this code originated from - * Dean Edwards' addEvent library. - */ -jQuery.event = { - - // Bind an event to an element - // Original by Dean Edwards - add: function( elem, types, handler, data ) { - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // For whatever reason, IE has trouble passing the window object - // around, causing it to be cloned in the process - if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { - elem = window; - } - - var handleObjIn, handleObj; - - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - } - - // Make sure that the function being executed has a unique ID - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure - var elemData = jQuery.data( elem ); - - // If no elemData is found then we must be trying to bind to one of the - // banned noData elements - if ( !elemData ) { - return; - } - - var events = elemData.events = elemData.events || {}, - eventHandle = elemData.handle, eventHandle; - - if ( !eventHandle ) { - elemData.handle = eventHandle = function() { - // Handle the second event of a trigger and when - // an event is called after a page has unloaded - return typeof jQuery !== "undefined" && !jQuery.event.triggered ? - jQuery.event.handle.apply( eventHandle.elem, arguments ) : - undefined; - }; - } - - // Add elem as a property of the handle function - // This is to prevent a memory leak with non-native events in IE. - eventHandle.elem = elem; - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = types.split(" "); - - var type, i = 0, namespaces; - - while ( (type = types[ i++ ]) ) { - handleObj = handleObjIn ? - jQuery.extend({}, handleObjIn) : - { handler: handler, data: data }; - - // Namespaced event handlers - if ( type.indexOf(".") > -1 ) { - namespaces = type.split("."); - type = namespaces.shift(); - handleObj.namespace = namespaces.slice(0).sort().join("."); - - } else { - namespaces = []; - handleObj.namespace = ""; - } - - handleObj.type = type; - handleObj.guid = handler.guid; - - // Get the current list of functions bound to this event - var handlers = events[ type ], - special = jQuery.event.special[ type ] || {}; - - // Init the event handler queue - if ( !handlers ) { - handlers = events[ type ] = []; - - // Check for a special event handler - // Only use addEventListener/attachEvent if the special - // events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add the function to the element's handler list - handlers.push( handleObj ); - - // Keep track of which events have been used, for global triggering - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, pos ) { - // don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, - elemData = jQuery.data( elem ), - events = elemData && elemData.events; - - if ( !elemData || !events ) { - return; - } - - // types is actually an event object here - if ( types && types.type ) { - handler = types.handler; - types = types.type; - } - - // Unbind all events for the element - if ( !types || typeof types === "string" && types.charAt(0) === "." ) { - types = types || ""; - - for ( type in events ) { - jQuery.event.remove( elem, type + types ); - } - - return; - } - - // Handle multiple events separated by a space - // jQuery(...).unbind("mouseover mouseout", fn); - types = types.split(" "); - - while ( (type = types[ i++ ]) ) { - origType = type; - handleObj = null; - all = type.indexOf(".") < 0; - namespaces = []; - - if ( !all ) { - // Namespaced event handlers - namespaces = type.split("."); - type = namespaces.shift(); - - namespace = new RegExp("(^|\\.)" + - jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)") - } - - eventType = events[ type ]; - - if ( !eventType ) { - continue; - } - - if ( !handler ) { - for ( var j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( all || namespace.test( handleObj.namespace ) ) { - jQuery.event.remove( elem, origType, handleObj.handler, j ); - eventType.splice( j--, 1 ); - } - } - - continue; - } - - special = jQuery.event.special[ type ] || {}; - - for ( var j = pos || 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( handler.guid === handleObj.guid ) { - // remove the given handler for the given type - if ( all || namespace.test( handleObj.namespace ) ) { - if ( pos == null ) { - eventType.splice( j--, 1 ); - } - - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - - if ( pos != null ) { - break; - } - } - } - - // remove generic event handler if no more handlers exist - if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { - if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { - removeEvent( elem, type, elemData.handle ); - } - - ret = null; - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - var handle = elemData.handle; - if ( handle ) { - handle.elem = null; - } - - delete elemData.events; - delete elemData.handle; - - if ( jQuery.isEmptyObject( elemData ) ) { - jQuery.removeData( elem ); - } - } - }, - - // bubbling is internal - trigger: function( event, data, elem /*, bubbling */ ) { - // Event object or event type - var type = event.type || event, - bubbling = arguments[3]; - - if ( !bubbling ) { - event = typeof event === "object" ? - // jQuery.Event object - event[expando] ? event : - // Object literal - jQuery.extend( jQuery.Event(type), event ) : - // Just the event type (string) - jQuery.Event(type); - - if ( type.indexOf("!") >= 0 ) { - event.type = type = type.slice(0, -1); - event.exclusive = true; - } - - // Handle a global trigger - if ( !elem ) { - // Don't bubble custom events when global (to avoid too much overhead) - event.stopPropagation(); - - // Only trigger if we've ever bound an event for it - if ( jQuery.event.global[ type ] ) { - jQuery.each( jQuery.cache, function() { - if ( this.events && this.events[type] ) { - jQuery.event.trigger( event, data, this.handle.elem ); - } - }); - } - } - - // Handle triggering a single element - - // don't do events on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; - } - - // Clean up in case it is reused - event.result = undefined; - event.target = elem; - - // Clone the incoming data, if any - data = jQuery.makeArray( data ); - data.unshift( event ); - } - - event.currentTarget = elem; - - // Trigger the event, it is assumed that "handle" is a function - var handle = jQuery.data( elem, "handle" ); - if ( handle ) { - handle.apply( elem, data ); - } - - var parent = elem.parentNode || elem.ownerDocument; - - // Trigger an inline bound script - try { - if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { - if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { - event.result = false; - } - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (e) {} - - if ( !event.isPropagationStopped() && parent ) { - jQuery.event.trigger( event, data, parent, true ); - - } else if ( !event.isDefaultPrevented() ) { - var target = event.target, old, - isClick = jQuery.nodeName(target, "a") && type === "click", - special = jQuery.event.special[ type ] || {}; - - if ( (!special._default || special._default.call( elem, event ) === false) && - !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { - - try { - if ( target[ type ] ) { - // Make sure that we don't accidentally re-trigger the onFOO events - old = target[ "on" + type ]; - - if ( old ) { - target[ "on" + type ] = null; - } - - jQuery.event.triggered = true; - target[ type ](); - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (e) {} - - if ( old ) { - target[ "on" + type ] = old; - } - - jQuery.event.triggered = false; - } - } - }, - - handle: function( event ) { - var all, handlers, namespaces, namespace, events; - - event = arguments[0] = jQuery.event.fix( event || window.event ); - event.currentTarget = this; - - // Namespaced event handlers - all = event.type.indexOf(".") < 0 && !event.exclusive; - - if ( !all ) { - namespaces = event.type.split("."); - event.type = namespaces.shift(); - namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - var events = jQuery.data(this, "events"), handlers = events[ event.type ]; - - if ( events && handlers ) { - // Clone the handlers to prevent manipulation - handlers = handlers.slice(0); - - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; - - // Filter the functions by class - if ( all || namespace.test( handleObj.namespace ) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handleObj.handler; - event.data = handleObj.data; - event.handleObj = handleObj; - - var ret = handleObj.handler.apply( this, arguments ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - - if ( event.isImmediatePropagationStopped() ) { - break; - } - } - } - } - - return event.result; - }, - - props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), - - fix: function( event ) { - if ( event[ expando ] ) { - return event; - } - - // store a copy of the original event object - // and "clone" to set read-only properties - var originalEvent = event; - event = jQuery.Event( originalEvent ); - - for ( var i = this.props.length, prop; i; ) { - prop = this.props[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary - if ( !event.target ) { - event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either - } - - // check if target is a textnode (safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && event.fromElement ) { - event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; - } - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, body = document.body; - event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); - event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); - } - - // Add which for key events - if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) { - event.which = event.charCode || event.keyCode; - } - - // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) - if ( !event.metaKey && event.ctrlKey ) { - event.metaKey = event.ctrlKey; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && event.button !== undefined ) { - event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); - } - - return event; - }, - - // Deprecated, use jQuery.guid instead - guid: 1E8, - - // Deprecated, use jQuery.proxy instead - proxy: jQuery.proxy, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady, - teardown: jQuery.noop - }, - - live: { - add: function( handleObj ) { - jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); - }, - - remove: function( handleObj ) { - var remove = true, - type = handleObj.origType.replace(rnamespaces, ""); - - jQuery.each( jQuery.data(this, "events").live || [], function() { - if ( type === this.origType.replace(rnamespaces, "") ) { - remove = false; - return false; - } - }); - - if ( remove ) { - jQuery.event.remove( this, handleObj.origType, liveHandler ); - } - } - - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( this.setInterval ) { - this.onbeforeunload = eventHandle; - } - - return false; - }, - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - } -}; - -var removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - elem.removeEventListener( type, handle, false ); - } : - function( elem, type, handle ) { - elem.detachEvent( "on" + type, handle ); - }; - -jQuery.Event = function( src ) { - // Allow instantiation without the 'new' keyword - if ( !this.preventDefault ) { - return new jQuery.Event( src ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - // Event type - } else { - this.type = src; - } - - // timeStamp is buggy for some events on Firefox(#3843) - // So we won't rely on the native value - this.timeStamp = now(); - - // Mark it as fixed - this[ expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - } - // otherwise set the returnValue property of the original event to false (IE) - e.returnValue = false; - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Checks if an event happened on an element within another element -// Used in jQuery.event.special.mouseenter and mouseleave handlers -var withinElement = function( event ) { - // Check if mouse(over|out) are still within the same parent element - var parent = event.relatedTarget; - - // Firefox sometimes assigns relatedTarget a XUL element - // which we cannot access the parentNode property of - try { - // Traverse up the tree - while ( parent && parent !== this ) { - parent = parent.parentNode; - } - - if ( parent !== this ) { - // set the correct event type - event.type = event.data; - - // handle event if we actually just moused on to a non sub-element - jQuery.event.handle.apply( this, arguments ); - } - - // assuming we've left the element since we most likely mousedover a xul element - } catch(e) { } -}, - -// In case of event delegation, we only need to rename the event.type, -// liveHandler will take care of the rest. -delegate = function( event ) { - event.type = event.data; - jQuery.event.handle.apply( this, arguments ); -}; - -// Create mouseenter and mouseleave events -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - setup: function( data ) { - jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); - }, - teardown: function( data ) { - jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); - } - }; -}); - -// submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function( data, namespaces ) { - if ( this.nodeName.toLowerCase() !== "form" ) { - jQuery.event.add(this, "click.specialSubmit", function( e ) { - var elem = e.target, type = elem.type; - - if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { - return trigger( "submit", this, arguments ); - } - }); - - jQuery.event.add(this, "keypress.specialSubmit", function( e ) { - var elem = e.target, type = elem.type; - - if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { - return trigger( "submit", this, arguments ); - } - }); - - } else { - return false; - } - }, - - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialSubmit" ); - } - }; - -} - -// change delegation, happens here so we have bind. -if ( !jQuery.support.changeBubbles ) { - - var formElems = /textarea|input|select/i, - - changeFilters, - - getVal = function( elem ) { - var type = elem.type, val = elem.value; - - if ( type === "radio" || type === "checkbox" ) { - val = elem.checked; - - } else if ( type === "select-multiple" ) { - val = elem.selectedIndex > -1 ? - jQuery.map( elem.options, function( elem ) { - return elem.selected; - }).join("-") : - ""; - - } else if ( elem.nodeName.toLowerCase() === "select" ) { - val = elem.selectedIndex; - } - - return val; - }, - - testChange = function testChange( e ) { - var elem = e.target, data, val; - - if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { - return; - } - - data = jQuery.data( elem, "_change_data" ); - val = getVal(elem); - - // the current data will be also retrieved by beforeactivate - if ( e.type !== "focusout" || elem.type !== "radio" ) { - jQuery.data( elem, "_change_data", val ); - } - - if ( data === undefined || val === data ) { - return; - } - - if ( data != null || val ) { - e.type = "change"; - return jQuery.event.trigger( e, arguments[1], elem ); - } - }; - - jQuery.event.special.change = { - filters: { - focusout: testChange, - - click: function( e ) { - var elem = e.target, type = elem.type; - - if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { - return testChange.call( this, e ); - } - }, - - // Change has to be called before submit - // Keydown will be called before keypress, which is used in submit-event delegation - keydown: function( e ) { - var elem = e.target, type = elem.type; - - if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || - (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || - type === "select-multiple" ) { - return testChange.call( this, e ); - } - }, - - // Beforeactivate happens also before the previous element is blurred - // with this event you can't trigger a change event, but you can store - // information/focus[in] is not needed anymore - beforeactivate: function( e ) { - var elem = e.target; - jQuery.data( elem, "_change_data", getVal(elem) ); - } - }, - - setup: function( data, namespaces ) { - if ( this.type === "file" ) { - return false; - } - - for ( var type in changeFilters ) { - jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); - } - - return formElems.test( this.nodeName ); - }, - - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialChange" ); - - return formElems.test( this.nodeName ); - } - }; - - changeFilters = jQuery.event.special.change.filters; -} - -function trigger( type, elem, args ) { - args[0].type = type; - return jQuery.event.handle.apply( elem, args ); -} - -// Create "bubbling" focus and blur events -if ( document.addEventListener ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - jQuery.event.special[ fix ] = { - setup: function() { - this.addEventListener( orig, handler, true ); - }, - teardown: function() { - this.removeEventListener( orig, handler, true ); - } - }; - - function handler( e ) { - e = jQuery.event.fix( e ); - e.type = fix; - return jQuery.event.handle.call( this, e ); - } - }); -} - -jQuery.each(["bind", "one"], function( i, name ) { - jQuery.fn[ name ] = function( type, data, fn ) { - // Handle object literals - if ( typeof type === "object" ) { - for ( var key in type ) { - this[ name ](key, data, type[key], fn); - } - return this; - } - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - var handler = name === "one" ? jQuery.proxy( fn, function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }) : fn; - - if ( type === "unload" && name !== "one" ) { - this.one( type, data, fn ); - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.add( this[i], type, handler, data ); - } - } - - return this; - }; -}); - -jQuery.fn.extend({ - unbind: function( type, fn ) { - // Handle object literals - if ( typeof type === "object" && !type.preventDefault ) { - for ( var key in type ) { - this.unbind(key, type[key]); - } - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.remove( this[i], type, fn ); - } - } - - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.live( types, data, fn, selector ); - }, - - undelegate: function( selector, types, fn ) { - if ( arguments.length === 0 ) { - return this.unbind( "live" ); - - } else { - return this.die( types, null, fn, selector ); - } - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - - triggerHandler: function( type, data ) { - if ( this[0] ) { - var event = jQuery.Event( type ); - event.preventDefault(); - event.stopPropagation(); - jQuery.event.trigger( event, data, this[0] ); - return event.result; - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, i = 1; - - // link all the functions, so any of them can unbind this click handler - while ( i < args.length ) { - jQuery.proxy( fn, args[ i++ ] ); - } - - return this.click( jQuery.proxy( fn, function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - })); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -var liveMap = { - focus: "focusin", - blur: "focusout", - mouseenter: "mouseover", - mouseleave: "mouseout" -}; - -jQuery.each(["live", "die"], function( i, name ) { - jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { - var type, i = 0, match, namespaces, preType, - selector = origSelector || this.selector, - context = origSelector ? this : jQuery( this.context ); - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - types = (types || "").split(" "); - - while ( (type = types[ i++ ]) != null ) { - match = rnamespaces.exec( type ); - namespaces = ""; - - if ( match ) { - namespaces = match[0]; - type = type.replace( rnamespaces, "" ); - } - - if ( type === "hover" ) { - types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); - continue; - } - - preType = type; - - if ( type === "focus" || type === "blur" ) { - types.push( liveMap[ type ] + namespaces ); - type = type + namespaces; - - } else { - type = (liveMap[ type ] || type) + namespaces; - } - - if ( name === "live" ) { - // bind live handler - context.each(function(){ - jQuery.event.add( this, liveConvert( type, selector ), - { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); - }); - - } else { - // unbind live handler - context.unbind( liveConvert( type, selector ), fn ); - } - } - - return this; - } -}); - -function liveHandler( event ) { - var stop, elems = [], selectors = [], args = arguments, - related, match, handleObj, elem, j, i, l, data, - events = jQuery.data( this, "events" ); - - // Make sure we avoid non-left-click bubbling in Firefox (#3861) - if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) { - return; - } - - event.liveFired = this; - - var live = events.live.slice(0); - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { - selectors.push( handleObj.selector ); - - } else { - live.splice( j--, 1 ); - } - } - - match = jQuery( event.target ).closest( selectors, event.currentTarget ); - - for ( i = 0, l = match.length; i < l; i++ ) { - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( match[i].selector === handleObj.selector ) { - elem = match[i].elem; - related = null; - - // Those two events require additional checking - if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { - related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; - } - - if ( !related || related !== elem ) { - elems.push({ elem: elem, handleObj: handleObj }); - } - } - } - } - - for ( i = 0, l = elems.length; i < l; i++ ) { - match = elems[i]; - event.currentTarget = match.elem; - event.data = match.handleObj.data; - event.handleObj = match.handleObj; - - if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) { - stop = false; - break; - } - } - - return stop; -} - -function liveConvert( type, selector ) { - return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&"); -} - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( fn ) { - return fn ? this.bind( name, fn ) : this.trigger( name ); - }; - - if ( jQuery.attrFn ) { - jQuery.attrFn[ name ] = true; - } -}); - -// Prevent memory leaks in IE -// Window isn't included so as not to unbind existing unload events -// More info: -// - http://isaacschlueter.com/2006/10/msie-memory-leaks/ -if ( window.attachEvent && !window.addEventListener ) { - window.attachEvent("onunload", function() { - for ( var id in jQuery.cache ) { - if ( jQuery.cache[ id ].handle ) { - // Try/Catch is to handle iframes being unloaded, see #4280 - try { - jQuery.event.remove( jQuery.cache[ id ].handle.elem ); - } catch(e) {} - } - } - }); -} -/*! - * Sizzle CSS Selector Engine - v1.0 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function(){ - baseHasDuplicate = false; - return 0; -}); - -var Sizzle = function(selector, context, results, seed) { - results = results || []; - var origContext = context = context || document; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context), - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) { - selector += parts.shift(); - } - - set = posProcess( selector, set ); - } - } - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - var ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; - } - - if ( context ) { - var ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray(set); - } else { - prune = false; - } - - while ( parts.length ) { - var cur = parts.pop(), pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - Sizzle.error( cur || selector ); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - } else if ( context && context.nodeType === 1 ) { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - } else { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function(results){ - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort(sortOrder); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[i-1] ) { - results.splice(i--, 1); - } - } - } - } - - return results; -}; - -Sizzle.matches = function(expr, set){ - return Sizzle(expr, null, null, set); -}; - -Sizzle.find = function(expr, context, isXML){ - var set, match; - - if ( !expr ) { - return []; - } - - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var type = Expr.order[i], match; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; - match.splice(1,1); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace(/\\/g, ""); - set = Expr.find[ type ]( match, context, isXML ); - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = context.getElementsByTagName("*"); - } - - return {set: set, expr: expr}; -}; - -Sizzle.filter = function(expr, set, inplace, not){ - var old = expr, result = [], curLoop = set, match, anyFound, - isXMLFilter = set && set[0] && isXML(set[0]); - - while ( expr && set.length ) { - for ( var type in Expr.filter ) { - if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - var filter = Expr.filter[ type ], found, item, left = match[1]; - anyFound = false; - - match.splice(1,1); - - if ( left.substr( left.length - 1 ) === "\\" ) { - continue; - } - - if ( curLoop === result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - } else { - curLoop[i] = false; - } - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr === old ) { - if ( anyFound == null ) { - Sizzle.error( expr ); - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -Sizzle.error = function( msg ) { - throw "Syntax error, unrecognized expression: " + msg; -}; - -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - match: { - ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ - }, - leftMatch: {}, - attrMap: { - "class": "className", - "for": "htmlFor" - }, - attrHandle: { - href: function(elem){ - return elem.getAttribute("href"); - } - }, - relative: { - "+": function(checkSet, part){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !/\W/.test(part), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag ) { - part = part.toLowerCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - ">": function(checkSet, part){ - var isPartStr = typeof part === "string"; - - if ( isPartStr && !/\W/.test(part) ) { - part = part.toLowerCase(); - - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; - } - } - } else { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - "": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; - - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = part.toLowerCase(); - checkFn = dirNodeCheck; - } - - checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); - }, - "~": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; - - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = part.toLowerCase(); - checkFn = dirNodeCheck; - } - - checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); - } - }, - find: { - ID: function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? [m] : []; - } - }, - NAME: function(match, context){ - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], results = context.getElementsByName(match[1]); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - TAG: function(match, context){ - return context.getElementsByTagName(match[1]); - } - }, - preFilter: { - CLASS: function(match, curLoop, inplace, result, not, isXML){ - match = " " + match[1].replace(/\\/g, "") + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { - if ( !inplace ) { - result.push( elem ); - } - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - ID: function(match){ - return match[1].replace(/\\/g, ""); - }, - TAG: function(match, curLoop){ - return match[1].toLowerCase(); - }, - CHILD: function(match){ - if ( match[1] === "nth" ) { - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( - match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - ATTR: function(match, curLoop, inplace, result, not, isXML){ - var name = match[1].replace(/\\/g, ""); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - PSEUDO: function(match, curLoop, inplace, result, not){ - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - if ( !inplace ) { - result.push.apply( result, ret ); - } - return false; - } - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - POS: function(match){ - match.unshift( true ); - return match; - } - }, - filters: { - enabled: function(elem){ - return elem.disabled === false && elem.type !== "hidden"; - }, - disabled: function(elem){ - return elem.disabled === true; - }, - checked: function(elem){ - return elem.checked === true; - }, - selected: function(elem){ - // Accessing this property makes selected-by-default - // options in Safari work properly - elem.parentNode.selectedIndex; - return elem.selected === true; - }, - parent: function(elem){ - return !!elem.firstChild; - }, - empty: function(elem){ - return !elem.firstChild; - }, - has: function(elem, i, match){ - return !!Sizzle( match[3], elem ).length; - }, - header: function(elem){ - return /h\d/i.test( elem.nodeName ); - }, - text: function(elem){ - return "text" === elem.type; - }, - radio: function(elem){ - return "radio" === elem.type; - }, - checkbox: function(elem){ - return "checkbox" === elem.type; - }, - file: function(elem){ - return "file" === elem.type; - }, - password: function(elem){ - return "password" === elem.type; - }, - submit: function(elem){ - return "submit" === elem.type; - }, - image: function(elem){ - return "image" === elem.type; - }, - reset: function(elem){ - return "reset" === elem.type; - }, - button: function(elem){ - return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; - }, - input: function(elem){ - return /input|select|textarea|button/i.test(elem.nodeName); - } - }, - setFilters: { - first: function(elem, i){ - return i === 0; - }, - last: function(elem, i, match, array){ - return i === array.length - 1; - }, - even: function(elem, i){ - return i % 2 === 0; - }, - odd: function(elem, i){ - return i % 2 === 1; - }, - lt: function(elem, i, match){ - return i < match[3] - 0; - }, - gt: function(elem, i, match){ - return i > match[3] - 0; - }, - nth: function(elem, i, match){ - return match[3] - 0 === i; - }, - eq: function(elem, i, match){ - return match[3] - 0 === i; - } - }, - filter: { - PSEUDO: function(elem, match, i, array){ - var name = match[1], filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; - } else if ( name === "not" ) { - var not = match[3]; - - for ( var i = 0, l = not.length; i < l; i++ ) { - if ( not[i] === elem ) { - return false; - } - } - - return true; - } else { - Sizzle.error( "Syntax error, unrecognized expression: " + name ); - } - }, - CHILD: function(elem, match){ - var type = match[1], node = elem; - switch (type) { - case 'only': - case 'first': - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - if ( type === "first" ) { - return true; - } - node = elem; - case 'last': - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - return true; - case 'nth': - var first = match[2], last = match[3]; - - if ( first === 1 && last === 0 ) { - return true; - } - - var doneName = match[0], - parent = elem.parentNode; - - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - parent.sizcache = doneName; - } - - var diff = elem.nodeIndex - last; - if ( first === 0 ) { - return diff === 0; - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - } - }, - ID: function(elem, match){ - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - TAG: function(elem, match){ - return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; - }, - CLASS: function(elem, match){ - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - ATTR: function(elem, match){ - var name = match[1], - result = Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value !== check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - POS: function(elem, match, i, array){ - var name = match[2], filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ - return "\\" + (num - 0 + 1); - })); -} - -var makeArray = function(array, results) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -// Also verifies that the returned array holds DOM nodes -// (which is not the case in the Blackberry browser) -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; - -// Provide a fallback method if it does not work -} catch(e){ - makeArray = function(array, results) { - var ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - } else { - if ( typeof array.length === "number" ) { - for ( var i = 0, l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - } else { - for ( var i = 0; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.compareDocumentPosition ? -1 : 1; - } - - var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( "sourceIndex" in document.documentElement ) { - sortOrder = function( a, b ) { - if ( !a.sourceIndex || !b.sourceIndex ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.sourceIndex ? -1 : 1; - } - - var ret = a.sourceIndex - b.sourceIndex; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( document.createRange ) { - sortOrder = function( a, b ) { - if ( !a.ownerDocument || !b.ownerDocument ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.ownerDocument ? -1 : 1; - } - - var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); - aRange.setStart(a, 0); - aRange.setEnd(a, 0); - bRange.setStart(b, 0); - bRange.setEnd(b, 0); - var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} - -// Utility function for retreiving the text value of an array of DOM nodes -function getText( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += getText( elem.childNodes ); - } - } - - return ret; -} - -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - var form = document.createElement("div"), - id = "script" + (new Date).getTime(); - form.innerHTML = ""; - - // Inject it into the root element, check its status, and remove it quickly - var root = document.documentElement; - root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - if ( document.getElementById( id ) ) { - Expr.find.ID = function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; - } - }; - - Expr.filter.ID = function(elem, match){ - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } - - root.removeChild( form ); - root = form = null; // release memory in IE -})(); - -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); - - // Make sure no comments are found - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function(match, context){ - var results = context.getElementsByTagName(match[1]); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - } - - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - Expr.attrHandle.href = function(elem){ - return elem.getAttribute("href", 2); - }; - } - - div = null; // release memory in IE -})(); - -if ( document.querySelectorAll ) { - (function(){ - var oldSizzle = Sizzle, div = document.createElement("div"); - div.innerHTML = "

"; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function(query, context, extra, seed){ - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && context.nodeType === 9 && !isXML(context) ) { - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(e){} - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - div = null; // release memory in IE - })(); -} - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
"; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function(match, context, isXML) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - div = null; // release memory in IE -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - elem = elem[dir]; - var match = false; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; - elem.sizset = i; - } - - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - elem = elem[dir]; - var match = false; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem.sizcache = doneName; - elem.sizset = i; - } - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -var contains = document.compareDocumentPosition ? function(a, b){ - return !!(a.compareDocumentPosition(b) & 16); -} : function(a, b){ - return a !== b && (a.contains ? a.contains(b) : true); -}; - -var isXML = function(elem){ - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -var posProcess = function(selector, context){ - var tmpSet = [], later = "", match, - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = getText; -jQuery.isXMLDoc = isXML; -jQuery.contains = contains; - -return; - -window.Sizzle = Sizzle; - -})(); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - slice = Array.prototype.slice; - -// Implement the identical functionality for filter and not -var winnow = function( elements, qualifier, keep ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return (elem === qualifier) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return (jQuery.inArray( elem, qualifier ) >= 0) === keep; - }); -}; - -jQuery.fn.extend({ - find: function( selector ) { - var ret = this.pushStack( "", "find", selector ), length = 0; - - for ( var i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( var n = length; n < ret.length; n++ ) { - for ( var r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && jQuery.filter( selector, this ).length > 0; - }, - - closest: function( selectors, context ) { - if ( jQuery.isArray( selectors ) ) { - var ret = [], cur = this[0], match, matches = {}, selector; - - if ( cur && selectors.length ) { - for ( var i = 0, l = selectors.length; i < l; i++ ) { - selector = selectors[i]; - - if ( !matches[selector] ) { - matches[selector] = jQuery.expr.match.POS.test( selector ) ? - jQuery( selector, context || this.context ) : - selector; - } - } - - while ( cur && cur.ownerDocument && cur !== context ) { - for ( selector in matches ) { - match = matches[selector]; - - if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { - ret.push({ selector: selector, elem: cur }); - delete matches[selector]; - } - } - cur = cur.parentNode; - } - } - - return ret; - } - - var pos = jQuery.expr.match.POS.test( selectors ) ? - jQuery( selectors, context || this.context ) : null; - - return this.map(function( i, cur ) { - while ( cur && cur.ownerDocument && cur !== context ) { - if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) { - return cur; - } - cur = cur.parentNode; - } - return null; - }); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - if ( !elem || typeof elem === "string" ) { - return jQuery.inArray( this[0], - // If it receives a string, the selector is used - // If it receives nothing, the siblings are used - elem ? jQuery( elem ) : this.parent().children() ); - } - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context || this.context ) : - jQuery.makeArray( selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - andSelf: function() { - return this.add( this.prevObject ); - } -}); - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( elem.parentNode.firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, slice.call(arguments).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], cur = elem[dir]; - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - nth: function( cur, result, dir, elem ) { - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; - } - } - - return cur; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); -var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g, - rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i, - rtagName = /<([\w:]+)/, - rtbody = /"; - }, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
", "
" ], - thead: [ 1, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - col: [ 2, "", "
" ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }; - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE can't serialize and - - - - - - - - - -
- -
-
- -
-
- - - - -
-

1. Change your flash vars

- -
-
- Embed parameters -
- - - - - - - - - -
-
-
- Flash Vars -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- Plugins -
- - -
- -
-
-
- - -
- Advanced Parameters -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- Multicast Parameters -
- - - - - - - -
- -
- - -
- -
- -

-
-
-
- - - - - - - - -
-

2. Preview Player

-
-
-

3. Preview Code

- -

Embed variables

- -
-
-
- -
-
- -
- - + + + + +Strobe Media Playback player setup + + + + + + + + + + + + +
+ +
+
+ +
+
+ + + + +
+

1. Change your flash vars

+ +
+
+ Embed parameters +
+ + + + + + + + + +
+
+
+ Flash Vars +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ Plugins +
+ + +
+ +
+
+
+ + +
+ Advanced Parameters +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ Multicast Parameters +
+ + + + + + + +
+ +
+ + +
+ +
+ +

+
+
+
+ + + + + + + + +
+

2. Preview Player

+
+
+

3. Preview Code

+ +

Embed variables

+ +
+
+
+ +
+
+ +
+ + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/skins/tablet-skin.xml b/lib/osmf/player/StrobeMediaPlayback/html-template/skins/tablet-skin.xml index 4b03d2e..58281f3 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/skins/tablet-skin.xml +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/skins/tablet-skin.xml @@ -1,44 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/strobemediaplayback-iframe-embed.html b/lib/osmf/player/StrobeMediaPlayback/html-template/strobemediaplayback-iframe-embed.html index 92f5abb..7bd5135 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/strobemediaplayback-iframe-embed.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/strobemediaplayback-iframe-embed.html @@ -1,12 +1,12 @@ - - - - - Flash/Strobe Media Playback - iframe embed sample - - -

Flash/Strobe Media Playback - iframe embed sample

- - - + + + + + Flash/Strobe Media Playback - iframe embed sample + + +

Flash/Strobe Media Playback - iframe embed sample

+ + + diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/thumbs.html b/lib/osmf/player/StrobeMediaPlayback/html-template/thumbs.html index bad9d4d..3cfc446 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/thumbs.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/thumbs.html @@ -1,84 +1,84 @@ - - - - - Device Detection Test - - - - - - - - - - - - - -
-

This is a demo page demonstrating the Strobe Media Playback 1.6 features. The page is displayed differently on - each of the following device types: Desktop, Tablet, Smartphone. Each device type is defined to have its own - appropriate skin and interactions. Additionally, the page renders HTML5 code for devices that are not Flash-enabled.

-

On Flash-enabled smartphones, the player display thumbnails that, when pressed, start playback in full screen. On - Flash-enabled tablets, the page displays wider, inline videos waiting in a paused state. On desktops, the behavior - of the player is as it has been for SMP 1.5 and 1.0.

-
-
-
-
-
-

Video One

Video one description.

-
-
-
-
-
-

Video Two

The description of the second video.

-
- + + + + + Device Detection Test + + + + + + + + + + + + + +
+

This is a demo page demonstrating the Strobe Media Playback 1.6 features. The page is displayed differently on + each of the following device types: Desktop, Tablet, Smartphone. Each device type is defined to have its own + appropriate skin and interactions. Additionally, the page renders HTML5 code for devices that are not Flash-enabled.

+

On Flash-enabled smartphones, the player display thumbnails that, when pressed, start playback in full screen. On + Flash-enabled tablets, the page displays wider, inline videos waiting in a paused state. On desktops, the behavior + of the player is as it has been for SMP 1.5 and 1.0.

+
+
+
+
+
+

Video One

Video one description.

+
+
+
+
+
+

Video Two

The description of the second video.

+
+ \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/html-template/youtube-googleanalytics.html b/lib/osmf/player/StrobeMediaPlayback/html-template/youtube-googleanalytics.html index 0599752..674f40a 100644 --- a/lib/osmf/player/StrobeMediaPlayback/html-template/youtube-googleanalytics.html +++ b/lib/osmf/player/StrobeMediaPlayback/html-template/youtube-googleanalytics.html @@ -1,165 +1,165 @@ - - - - YouTube & Google Analytics Sample - - - - - - -

YouTube & Google Analytics plugins

- -
-

Before using the OSMF YouTube plug-in, please review the YouTube API Terms of Service. (The OSMF YouTube plug-in is built off the YouTube API.)

- -
- -
- ... -
-
-
-
- - -
-
-
-

Video Quality Control (uses the Strobe Media Playback JavaScript API)

-
- The available qualities will be loaded once the playback starts... -
- - - - + + + + YouTube & Google Analytics Sample + + + + + + +

YouTube & Google Analytics plugins

+ +
+

Before using the OSMF YouTube plug-in, please review the YouTube API Terms of Service. (The OSMF YouTube plug-in is built off the YouTube API.)

+ +
+ +
+ ... +
+
+
+
+ + +
+
+
+

Video Quality Control (uses the Strobe Media Playback JavaScript API)

+
+ The available qualities will be loaded once the playback starts... +
+ + + + \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/src/StrobeMediaPlayback.as b/lib/osmf/player/StrobeMediaPlayback/src/StrobeMediaPlayback.as index 1ee2b7a..709906a 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/StrobeMediaPlayback.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/StrobeMediaPlayback.as @@ -22,6 +22,7 @@ package import flash.display.*; import flash.events.*; import flash.external.ExternalInterface; + import flash.net.drm.DRMManager; import flash.system.Capabilities; import flash.ui.Mouse; import flash.utils.Timer; @@ -52,7 +53,7 @@ package import org.osmf.traits.PlayState; import org.osmf.traits.PlayTrait; import org.osmf.utils.OSMFSettings; - import org.osmf.utils.OSMFStrings; + import org.osmf.utils.OSMFStrings; CONFIG::LOGGING { @@ -152,6 +153,10 @@ package player.addEventListener(TimeEvent.COMPLETE, onComplete); player.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + // Add DRM error handler + var drmManager:DRMManager = DRMManager.getDRMManager(); + drmManager.addEventListener(DRMErrorEvent.DRM_ERROR, onDRMError); + // this is used for DVR rolling window // TODO: Add this event only when the resource is DVR rolling window not all the time player.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, onCurrentTimeChange); @@ -214,6 +219,73 @@ package } } + private function reportError(message:String):void + { + // If an alert widget is available, use it. Otherwise, trace the message: + if (alert) + { + if (_media != null && mediaContainer.containsMediaElement(_media)) + { + mediaContainer.removeMediaElement(_media); + } + if (controlBar != null && controlBarContainer.containsMediaElement(controlBar)) + { + controlBarContainer.removeMediaElement(controlBar); + } + if (posterImage && mediaContainer.containsMediaElement(posterImage)) + { + mediaContainer.removeMediaElement(posterImage); + } + if (playOverlay != null && mediaContainer.layoutRenderer.hasTarget(playOverlay)) + { + mediaContainer.layoutRenderer.removeTarget(playOverlay); + } + if (bufferingOverlay != null && mediaContainer.layoutRenderer.hasTarget(bufferingOverlay)) + { + mediaContainer.layoutRenderer.removeTarget(bufferingOverlay); + } + + mediaContainer.addMediaElement(alert); + alert.alert("Error", message); + } + else + { + trace("Error:", message); + } + } + + private function onDRMError(event:DRMErrorEvent):void + { + switch(event.errorID) + { + // Use the following link for the error codes + // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/runtimeErrors.html + case 3305: + case 3328: + case 3315: + if (configuration.verbose) + { + reportError("Unable to connect to the authentication server. Error ID " + event.errorID); + } + else + { + reportError("We are unable to connect to the authentication server. We apologize for the inconvenience."); + } + break; + + default: + if (configuration.verbose) + { + reportError("DRM Error " + event.errorID); + } + else + { + reportError("Unexpected DRM error"); + } + break; + } + } + // Internals // private function onChromeProviderComplete(event:Event = null):void @@ -1008,37 +1080,7 @@ package } } - // If an alert widget is available, use it. Otherwise, trace the message: - if (alert) - { - if (_media != null && mediaContainer.containsMediaElement(_media)) - { - mediaContainer.removeMediaElement(_media); - } - if (controlBar != null && controlBarContainer.containsMediaElement(controlBar)) - { - controlBarContainer.removeMediaElement(controlBar); - } - if (posterImage && mediaContainer.containsMediaElement(posterImage)) - { - mediaContainer.removeMediaElement(posterImage); - } - if (playOverlay != null && mediaContainer.layoutRenderer.hasTarget(playOverlay)) - { - mediaContainer.layoutRenderer.removeTarget(playOverlay); - } - if (bufferingOverlay != null && mediaContainer.layoutRenderer.hasTarget(bufferingOverlay)) - { - mediaContainer.layoutRenderer.removeTarget(bufferingOverlay); - } - - mediaContainer.addMediaElement(alert); - alert.alert("Error", message); - } - else - { - trace("Error:", message); - } + reportError(message); // Forward the raw error message to JavaScript: if (ExternalInterface.available) diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/ChromeProvider.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/ChromeProvider.as index a66e4f4..cc27dbf 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/ChromeProvider.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/ChromeProvider.as @@ -41,7 +41,7 @@ package org.osmf.player.chrome import org.osmf.player.chrome.widgets.WidgetIDs; import org.osmf.player.elements.ErrorWidget; - //import spark.components.mediaClasses.VolumeBar; + //import spark.components.mediaClasses.VolumeBar; [Event(name="complete", type="flash.events.Event")] diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/IControlBar.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/IControlBar.as index 3ecb0b3..5b2d1cf 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/IControlBar.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/IControlBar.as @@ -1,27 +1,27 @@ -package org.osmf.player.chrome{ - import flash.events.IEventDispatcher; - - import org.osmf.layout.ILayoutTarget; - import org.osmf.media.MediaElement; - import org.osmf.player.chrome.assets.AssetsManager; - - /** - * IControlBar - * @author johncblandii - */ - public interface IControlBar extends ILayoutTarget, IEventDispatcher{ - // PROPERTIES - // - function get width():Number; function set width(value:Number):void; - function get height():Number; function set height(value:Number):void; - function get autoHide():Boolean; function set autoHide(value:Boolean):void; - function get autoHideTimeout():int; function set autoHideTimeout(value:int):void; - function get media():MediaElement; function set media(value:MediaElement):void; - function get tintColor():uint; function set tintColor(value:uint):void; - function get visible():Boolean; function set visible(value:Boolean):void; - - // FUNCTIONS - // - function configure(xml:XML, assetManager:AssetsManager):void; - } +package org.osmf.player.chrome{ + import flash.events.IEventDispatcher; + + import org.osmf.layout.ILayoutTarget; + import org.osmf.media.MediaElement; + import org.osmf.player.chrome.assets.AssetsManager; + + /** + * IControlBar + * @author johncblandii + */ + public interface IControlBar extends ILayoutTarget, IEventDispatcher{ + // PROPERTIES + // + function get width():Number; function set width(value:Number):void; + function get height():Number; function set height(value:Number):void; + function get autoHide():Boolean; function set autoHide(value:Boolean):void; + function get autoHideTimeout():int; function set autoHideTimeout(value:int):void; + function get media():MediaElement; function set media(value:MediaElement):void; + function get tintColor():uint; function set tintColor(value:uint):void; + function get visible():Boolean; function set visible(value:Boolean):void; + + // FUNCTIONS + // + function configure(xml:XML, assetManager:AssetsManager):void; + } } \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/SmartphoneControlBar.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/SmartphoneControlBar.as index 01b32c2..ec78ef8 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/SmartphoneControlBar.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/SmartphoneControlBar.as @@ -1,249 +1,249 @@ -/*********************************************************** - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems - * Incorporated. All Rights Reserved. - * - **********************************************************/ - -package org.osmf.player.chrome{ - import flash.events.Event; - import flash.events.MouseEvent; - import flash.events.TimerEvent; - import flash.geom.Rectangle; - import flash.utils.Timer; - - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - import org.osmf.player.chrome.assets.AssetIDs; - import org.osmf.player.chrome.assets.AssetsManager; - import org.osmf.player.chrome.assets.FontAsset; - import org.osmf.player.chrome.widgets.AutoHideWidget; - import org.osmf.player.chrome.widgets.BackButton; - import org.osmf.player.chrome.widgets.ButtonHighlight; - import org.osmf.player.chrome.widgets.CurrentTimeWidget; - import org.osmf.player.chrome.widgets.FullScreenEnterButton; - import org.osmf.player.chrome.widgets.FullScreenLeaveButton; - import org.osmf.player.chrome.widgets.PauseButton; - import org.osmf.player.chrome.widgets.PlayButton; - import org.osmf.player.chrome.widgets.ScrubBar; - import org.osmf.player.chrome.widgets.TotalTimeWidget; - import org.osmf.player.chrome.widgets.Widget; - import org.osmf.player.chrome.widgets.WidgetIDs; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - - /** - * MobileControlBar - * @author johncblandii - */ - public class SmartphoneControlBar extends AutoHideWidget implements IControlBar{ - - // OVERRIDES - // - override public function configure(xml:XML, assetManager:AssetsManager):void{ - id = WidgetIDs.CONTROL_BAR; - fadeSteps = 6; - face = AssetIDs.CONTROL_BAR_BACKDROP; - - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - layoutMetadata.layoutMode = LayoutMode.NONE; - layoutMetadata.height = 220; - - FontAsset(assetManager.getAsset(AssetIDs.DEFAULT_FONT)).resource.size = 16; - FontAsset(assetManager.getAsset(AssetIDs.DEFAULT_FONT_BOLD)).resource.size = 16; - - super.configure(xml, assetManager); - - // Top Row Controls - var controlsTop:Widget = new Widget(); - controlsTop.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; - controlsTop.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - controlsTop.layoutMetadata.verticalAlign = VerticalAlign.TOP; - controlsTop.layoutMetadata.top = 40; - controlsTop.layoutMetadata.left = 40; - controlsTop.layoutMetadata.right = 40; - - // Current time - var currentTime:CurrentTimeWidget = new CurrentTimeWidget(); - currentTime.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - currentTime.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; - controlsTop.addChildWidget(currentTime); - - var beforeScrubBarMargin:Widget = getSpacer(20); - controlsTop.addChildWidget(beforeScrubBarMargin); - - // Scrub bar - var scrubBar:ScrubBar = new ScrubBar(); - scrubBar.id = WidgetIDs.SCRUB_BAR; - scrubBar.includeTimeHint = false; - scrubBar.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - scrubBar.layoutMetadata.verticalAlign = VerticalAlign.TOP; - scrubBar.layoutMetadata.percentWidth = 100; - controlsTop.addChildWidget(scrubBar); - - var afterScrubBarMargin:Widget = getSpacer(20); - controlsTop.addChildWidget(afterScrubBarMargin); - - // Duration - var totalTime:TotalTimeWidget = new TotalTimeWidget(); - totalTime.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - totalTime.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; - controlsTop.addChildWidget(totalTime); - - addChildWidget(controlsTop); - - // Bottom row Controls - var controlsBottom:Widget = new Widget(); - controlsBottom.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; - controlsBottom.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - controlsBottom.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - controlsBottom.layoutMetadata.bottom = 20; - - // Back - var backButton:BackButton = new BackButton(); - backButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; - backButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; - backButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - backButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - controlsBottom.addChildWidget(backButton); - - // separator - var afterBackSeparator:Widget = getSeparator(); - controlsBottom.addChildWidget(afterBackSeparator); - - // Play/pause - var playButton:PlayButton = new PlayButton(); - playButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; - playButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; - playButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - playButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - controlsBottom.addChildWidget(playButton); - - var pauseButton:PauseButton = new PauseButton(); - pauseButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; - pauseButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; - pauseButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - pauseButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - controlsBottom.addChildWidget(pauseButton); - - // separator - var afterPlayPauseSeparator:Widget = getSeparator(); - controlsBottom.addChildWidget(afterPlayPauseSeparator); - - // FullScreen - var fullscreenLeaveButton:FullScreenLeaveButton = new FullScreenLeaveButton(); - fullscreenLeaveButton.twoStepFullScreen = true; - fullscreenLeaveButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; - fullscreenLeaveButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; - fullscreenLeaveButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - fullscreenLeaveButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - controlsBottom.addChildWidget(fullscreenLeaveButton); - - var fullscreenEnterButton:FullScreenEnterButton = new FullScreenEnterButton(); - fullscreenEnterButton.twoStepFullScreen = true; - fullscreenEnterButton.id = WidgetIDs.FULL_SCREEN_ENTER_BUTTON; - fullscreenEnterButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; - fullscreenEnterButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; - fullscreenEnterButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - fullscreenEnterButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - controlsBottom.addChildWidget(fullscreenEnterButton); - - addChildWidget(controlsBottom); - - // Configure - configureWidgets - ( [controlsTop, currentTime, beforeScrubBarMargin, scrubBar, afterScrubBarMargin, totalTime, - controlsBottom, backButton, afterBackSeparator, playButton, pauseButton, afterPlayPauseSeparator, fullscreenLeaveButton, fullscreenEnterButton] - ); - - measure(); - - highlight = new ButtonHighlight(assetManager); - } - +/*********************************************************** + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems + * Incorporated. All Rights Reserved. + * + **********************************************************/ + +package org.osmf.player.chrome{ + import flash.events.Event; + import flash.events.MouseEvent; + import flash.events.TimerEvent; + import flash.geom.Rectangle; + import flash.utils.Timer; + + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaElement; + import org.osmf.player.chrome.assets.AssetIDs; + import org.osmf.player.chrome.assets.AssetsManager; + import org.osmf.player.chrome.assets.FontAsset; + import org.osmf.player.chrome.widgets.AutoHideWidget; + import org.osmf.player.chrome.widgets.BackButton; + import org.osmf.player.chrome.widgets.ButtonHighlight; + import org.osmf.player.chrome.widgets.CurrentTimeWidget; + import org.osmf.player.chrome.widgets.FullScreenEnterButton; + import org.osmf.player.chrome.widgets.FullScreenLeaveButton; + import org.osmf.player.chrome.widgets.PauseButton; + import org.osmf.player.chrome.widgets.PlayButton; + import org.osmf.player.chrome.widgets.ScrubBar; + import org.osmf.player.chrome.widgets.TotalTimeWidget; + import org.osmf.player.chrome.widgets.Widget; + import org.osmf.player.chrome.widgets.WidgetIDs; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + + /** + * MobileControlBar + * @author johncblandii + */ + public class SmartphoneControlBar extends AutoHideWidget implements IControlBar{ + + // OVERRIDES + // + override public function configure(xml:XML, assetManager:AssetsManager):void{ + id = WidgetIDs.CONTROL_BAR; + fadeSteps = 6; + face = AssetIDs.CONTROL_BAR_BACKDROP; + + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + layoutMetadata.layoutMode = LayoutMode.NONE; + layoutMetadata.height = 220; + + FontAsset(assetManager.getAsset(AssetIDs.DEFAULT_FONT)).resource.size = 16; + FontAsset(assetManager.getAsset(AssetIDs.DEFAULT_FONT_BOLD)).resource.size = 16; + + super.configure(xml, assetManager); + + // Top Row Controls + var controlsTop:Widget = new Widget(); + controlsTop.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; + controlsTop.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + controlsTop.layoutMetadata.verticalAlign = VerticalAlign.TOP; + controlsTop.layoutMetadata.top = 40; + controlsTop.layoutMetadata.left = 40; + controlsTop.layoutMetadata.right = 40; + + // Current time + var currentTime:CurrentTimeWidget = new CurrentTimeWidget(); + currentTime.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + currentTime.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; + controlsTop.addChildWidget(currentTime); + + var beforeScrubBarMargin:Widget = getSpacer(20); + controlsTop.addChildWidget(beforeScrubBarMargin); + + // Scrub bar + var scrubBar:ScrubBar = new ScrubBar(); + scrubBar.id = WidgetIDs.SCRUB_BAR; + scrubBar.includeTimeHint = false; + scrubBar.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + scrubBar.layoutMetadata.verticalAlign = VerticalAlign.TOP; + scrubBar.layoutMetadata.percentWidth = 100; + controlsTop.addChildWidget(scrubBar); + + var afterScrubBarMargin:Widget = getSpacer(20); + controlsTop.addChildWidget(afterScrubBarMargin); + + // Duration + var totalTime:TotalTimeWidget = new TotalTimeWidget(); + totalTime.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + totalTime.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; + controlsTop.addChildWidget(totalTime); + + addChildWidget(controlsTop); + + // Bottom row Controls + var controlsBottom:Widget = new Widget(); + controlsBottom.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; + controlsBottom.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + controlsBottom.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + controlsBottom.layoutMetadata.bottom = 20; + + // Back + var backButton:BackButton = new BackButton(); + backButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; + backButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; + backButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + backButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + controlsBottom.addChildWidget(backButton); + + // separator + var afterBackSeparator:Widget = getSeparator(); + controlsBottom.addChildWidget(afterBackSeparator); + + // Play/pause + var playButton:PlayButton = new PlayButton(); + playButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; + playButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; + playButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + playButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + controlsBottom.addChildWidget(playButton); + + var pauseButton:PauseButton = new PauseButton(); + pauseButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; + pauseButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; + pauseButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + pauseButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + controlsBottom.addChildWidget(pauseButton); + + // separator + var afterPlayPauseSeparator:Widget = getSeparator(); + controlsBottom.addChildWidget(afterPlayPauseSeparator); + + // FullScreen + var fullscreenLeaveButton:FullScreenLeaveButton = new FullScreenLeaveButton(); + fullscreenLeaveButton.twoStepFullScreen = true; + fullscreenLeaveButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; + fullscreenLeaveButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; + fullscreenLeaveButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + fullscreenLeaveButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + controlsBottom.addChildWidget(fullscreenLeaveButton); + + var fullscreenEnterButton:FullScreenEnterButton = new FullScreenEnterButton(); + fullscreenEnterButton.twoStepFullScreen = true; + fullscreenEnterButton.id = WidgetIDs.FULL_SCREEN_ENTER_BUTTON; + fullscreenEnterButton.layoutMetadata.verticalAlign = VerticalAlign.TOP; + fullscreenEnterButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; + fullscreenEnterButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + fullscreenEnterButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + controlsBottom.addChildWidget(fullscreenEnterButton); + + addChildWidget(controlsBottom); + + // Configure + configureWidgets + ( [controlsTop, currentTime, beforeScrubBarMargin, scrubBar, afterScrubBarMargin, totalTime, + controlsBottom, backButton, afterBackSeparator, playButton, pauseButton, afterPlayPauseSeparator, fullscreenLeaveButton, fullscreenEnterButton] + ); + + measure(); + + highlight = new ButtonHighlight(assetManager); + } + protected function removeHighlight(event:Event=null):void{ if(highlight.parent) removeChild(highlight); - } - - protected function showHighlight(event:Event):void{ - if(isNaN(event.target.width) || isNaN(event.target.height)) return; - addChildAt(highlight, 1); - - //calculate it once [cut down on calculations] - if(!highlightSize) highlightSize = new Rectangle(0, 0, highlight.width/2, highlight.height/2); - - highlight.x = (event.target.parent.x+event.target.x+event.target.width/2)-highlightSize.width; + } + + protected function showHighlight(event:Event):void{ + if(isNaN(event.target.width) || isNaN(event.target.height)) return; + addChildAt(highlight, 1); + + //calculate it once [cut down on calculations] + if(!highlightSize) highlightSize = new Rectangle(0, 0, highlight.width/2, highlight.height/2); + + highlight.x = (event.target.parent.x+event.target.x+event.target.width/2)-highlightSize.width; highlight.y = (event.target.parent.y+event.target.y+event.target.height/2)-highlightSize.height; - } - - override protected function onAutoHideTimer(event:Event):void{ - if(playTrait && (playTrait.playState == PlayState.PAUSED || playTrait.playState == PlayState.STOPPED)) return; - super.onAutoHideTimer(event); - } - - override protected function processRequiredTraitsAvailable(element:MediaElement):void{ - super.processRequiredTraitsAvailable(element); - playTrait = element.getTrait(MediaTraitType.PLAY) as PlayTrait; - } - - // INTERNALS - // - - private function configureWidgets(widgets:Array):void - { - for each( var widget:Widget in widgets) - { - if (widget) - { - widget.configure(, assetManager); - } - } - } - - protected function getSeparator():Widget{ - var widget:Widget = new Widget(); - widget.face = AssetIDs.BUTTON_SEPARATOR; - return widget; - } - - protected function getMargin(face:String, horizontalAlign:String, assetManager:AssetsManager):Widget{ - var margin:Widget = new Widget(); - margin.face = face; - margin.layoutMetadata.horizontalAlign = horizontalAlign; - margin.layoutMetadata.verticalAlign = VerticalAlign.TOP; - return margin; - } - - protected function getSpacer(value:Number=10, direction:String="horizontal"):Widget{ - var spacer:Widget = new Widget(); - if(direction == "horizontal") spacer.width = value; - else spacer.height = value; - return spacer; - } - - protected var playTrait:PlayTrait; - - protected var highlight:ButtonHighlight; - protected var highlightSize:Rectangle; - - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.PLAY; - } + } + + override protected function onAutoHideTimer(event:Event):void{ + if(playTrait && (playTrait.playState == PlayState.PAUSED || playTrait.playState == PlayState.STOPPED)) return; + super.onAutoHideTimer(event); + } + + override protected function processRequiredTraitsAvailable(element:MediaElement):void{ + super.processRequiredTraitsAvailable(element); + playTrait = element.getTrait(MediaTraitType.PLAY) as PlayTrait; + } + + // INTERNALS + // + + private function configureWidgets(widgets:Array):void + { + for each( var widget:Widget in widgets) + { + if (widget) + { + widget.configure(, assetManager); + } + } + } + + protected function getSeparator():Widget{ + var widget:Widget = new Widget(); + widget.face = AssetIDs.BUTTON_SEPARATOR; + return widget; + } + + protected function getMargin(face:String, horizontalAlign:String, assetManager:AssetsManager):Widget{ + var margin:Widget = new Widget(); + margin.face = face; + margin.layoutMetadata.horizontalAlign = horizontalAlign; + margin.layoutMetadata.verticalAlign = VerticalAlign.TOP; + return margin; + } + + protected function getSpacer(value:Number=10, direction:String="horizontal"):Widget{ + var spacer:Widget = new Widget(); + if(direction == "horizontal") spacer.width = value; + else spacer.height = value; + return spacer; + } + + protected var playTrait:PlayTrait; + + protected var highlight:ButtonHighlight; + protected var highlightSize:Rectangle; + + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.PLAY; + } } \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/TabletControlBar.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/TabletControlBar.as index 5d4f720..5f84cbb 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/TabletControlBar.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/TabletControlBar.as @@ -1,198 +1,198 @@ -/*********************************************************** - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems - * Incorporated. All Rights Reserved. - * - **********************************************************/ - -package org.osmf.player.chrome{ - import flash.events.Event; - import flash.events.MouseEvent; - import flash.geom.Rectangle; - - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.player.chrome.assets.AssetIDs; - import org.osmf.player.chrome.assets.AssetsManager; - import org.osmf.player.chrome.assets.FontAsset; - import org.osmf.player.chrome.widgets.AutoHideWidget; - import org.osmf.player.chrome.widgets.ButtonHighlight; - import org.osmf.player.chrome.widgets.CurrentTimeWidget; - import org.osmf.player.chrome.widgets.FullScreenEnterButton; - import org.osmf.player.chrome.widgets.FullScreenLeaveButton; - import org.osmf.player.chrome.widgets.PauseButton; - import org.osmf.player.chrome.widgets.PlayButton; - import org.osmf.player.chrome.widgets.ScrubBar; - import org.osmf.player.chrome.widgets.TotalTimeWidget; - import org.osmf.player.chrome.widgets.Widget; - import org.osmf.player.chrome.widgets.WidgetIDs; - import org.osmf.traits.MediaTraitType; - - /** - * MobileControlBar - * @author johncblandii - */ - public class TabletControlBar extends AutoHideWidget implements IControlBar - { - // OVERRIDES - // - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - id = WidgetIDs.CONTROL_BAR; - face = AssetIDs.CONTROL_BAR_BACKDROP; - fadeSteps = 6; - - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - layoutMetadata.verticalAlign = VerticalAlign.TOP; - layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; - layoutMetadata.height = 55; - - FontAsset(assetManager.getAsset(AssetIDs.DEFAULT_FONT)).resource.size = 16; - FontAsset(assetManager.getAsset(AssetIDs.DEFAULT_FONT_BOLD)).resource.size = 16; - - super.configure(xml, assetManager); - - // Left margin - var leftMargin:Widget = new Widget(); - leftMargin.face = AssetIDs.CONTROL_BAR_BACKDROP_LEFT; - leftMargin.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; - addChildWidget(leftMargin); - - // Play/pause - var playButton:PlayButton = new PlayButton(); - playButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE - playButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; - playButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - playButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - addChildWidget(playButton); - - var pauseButton:PauseButton = new PauseButton(); - pauseButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE - pauseButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; - pauseButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - pauseButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - addChildWidget(pauseButton); - - // Middle controls - var middleControls:Widget = new Widget(); - middleControls.layoutMetadata.verticalAlign = VerticalAlign.BOTTOM; - middleControls.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; - middleControls.layoutMetadata.percentWidth = 100; - middleControls.layoutMetadata.height = 44; - - // Current time - var currentTime:CurrentTimeWidget = new CurrentTimeWidget(); - currentTime.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; - currentTime.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - currentTime.layoutMetadata.height = 25; - middleControls.addChildWidget(currentTime); - - // Spacer - var beforeScrubSpacer:Widget = new Widget(); - beforeScrubSpacer.width = 10; - middleControls.addChildWidget(beforeScrubSpacer); - - // Scrub bar - var scrubBar:ScrubBar = new ScrubBar(); - scrubBar.id = WidgetIDs.SCRUB_BAR; - scrubBar.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - scrubBar.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - scrubBar.layoutMetadata.percentWidth = 100; - scrubBar.layoutMetadata.height = 25; - scrubBar.includeTimeHint = false; - middleControls.addChildWidget(scrubBar); - - // Spacer - var afterScrubSpacer:Widget = new Widget(); - afterScrubSpacer.width = 10; - middleControls.addChildWidget(afterScrubSpacer); - - // Duration - var totalTime:TotalTimeWidget = new TotalTimeWidget(); - totalTime.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; - totalTime.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - totalTime.layoutMetadata.height = 25; - middleControls.addChildWidget(totalTime); - - addChildWidget(middleControls); - - // FullScreen - var fullscreenLeaveButton:FullScreenLeaveButton = new FullScreenLeaveButton(); - fullscreenLeaveButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - fullscreenLeaveButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; - fullscreenLeaveButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - fullscreenLeaveButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - addChildWidget(fullscreenLeaveButton); - - var fullscreenEnterButton:FullScreenEnterButton = new FullScreenEnterButton(); - fullscreenEnterButton.id = WidgetIDs.FULL_SCREEN_ENTER_BUTTON; - fullscreenEnterButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - fullscreenEnterButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; - fullscreenEnterButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); - fullscreenEnterButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); - addChildWidget(fullscreenEnterButton); - - var rightMargin:Widget = new Widget(); - rightMargin.face = AssetIDs.CONTROL_BAR_BACKDROP_RIGHT; - rightMargin.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; - addChildWidget(rightMargin); - - // Configure - configureWidgets([leftMargin, playButton, pauseButton, middleControls, currentTime, beforeScrubSpacer, scrubBar, afterScrubSpacer, totalTime, fullscreenLeaveButton, fullscreenEnterButton, rightMargin]); - - measure(); - - highlight = new ButtonHighlight(assetManager); - } - - // INTERNALS - // - - private function configureWidgets(widgets:Array):void - { - for each( var widget:Widget in widgets) - { - if (widget) - { - widget.configure(, assetManager); - } - } - } - - protected function removeHighlight(event:Event=null):void{ - if(highlight.parent) removeChild(highlight); - } - - protected function showHighlight(event:Event):void{ - if(isNaN(event.target.width) || isNaN(event.target.height)) return; - addChildAt(highlight, 1); - - //calculate it once [cut down on calculations] - if(!highlightSize) highlightSize = new Rectangle(0, 0, highlight.width/2, highlight.height/2); - - highlight.x = (event.target.x+event.target.width/2)-highlightSize.width; - highlight.y = (event.target.y+event.target.height/2)-highlightSize.height; - } - - protected var highlight:ButtonHighlight; - protected var highlightSize:Rectangle; - - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.PLAY; - } +/*********************************************************** + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems + * Incorporated. All Rights Reserved. + * + **********************************************************/ + +package org.osmf.player.chrome{ + import flash.events.Event; + import flash.events.MouseEvent; + import flash.geom.Rectangle; + + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.player.chrome.assets.AssetIDs; + import org.osmf.player.chrome.assets.AssetsManager; + import org.osmf.player.chrome.assets.FontAsset; + import org.osmf.player.chrome.widgets.AutoHideWidget; + import org.osmf.player.chrome.widgets.ButtonHighlight; + import org.osmf.player.chrome.widgets.CurrentTimeWidget; + import org.osmf.player.chrome.widgets.FullScreenEnterButton; + import org.osmf.player.chrome.widgets.FullScreenLeaveButton; + import org.osmf.player.chrome.widgets.PauseButton; + import org.osmf.player.chrome.widgets.PlayButton; + import org.osmf.player.chrome.widgets.ScrubBar; + import org.osmf.player.chrome.widgets.TotalTimeWidget; + import org.osmf.player.chrome.widgets.Widget; + import org.osmf.player.chrome.widgets.WidgetIDs; + import org.osmf.traits.MediaTraitType; + + /** + * MobileControlBar + * @author johncblandii + */ + public class TabletControlBar extends AutoHideWidget implements IControlBar + { + // OVERRIDES + // + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + id = WidgetIDs.CONTROL_BAR; + face = AssetIDs.CONTROL_BAR_BACKDROP; + fadeSteps = 6; + + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + layoutMetadata.verticalAlign = VerticalAlign.TOP; + layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; + layoutMetadata.height = 55; + + FontAsset(assetManager.getAsset(AssetIDs.DEFAULT_FONT)).resource.size = 16; + FontAsset(assetManager.getAsset(AssetIDs.DEFAULT_FONT_BOLD)).resource.size = 16; + + super.configure(xml, assetManager); + + // Left margin + var leftMargin:Widget = new Widget(); + leftMargin.face = AssetIDs.CONTROL_BAR_BACKDROP_LEFT; + leftMargin.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; + addChildWidget(leftMargin); + + // Play/pause + var playButton:PlayButton = new PlayButton(); + playButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE + playButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; + playButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + playButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + addChildWidget(playButton); + + var pauseButton:PauseButton = new PauseButton(); + pauseButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE + pauseButton.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; + pauseButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + pauseButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + addChildWidget(pauseButton); + + // Middle controls + var middleControls:Widget = new Widget(); + middleControls.layoutMetadata.verticalAlign = VerticalAlign.BOTTOM; + middleControls.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; + middleControls.layoutMetadata.percentWidth = 100; + middleControls.layoutMetadata.height = 44; + + // Current time + var currentTime:CurrentTimeWidget = new CurrentTimeWidget(); + currentTime.layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; + currentTime.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + currentTime.layoutMetadata.height = 25; + middleControls.addChildWidget(currentTime); + + // Spacer + var beforeScrubSpacer:Widget = new Widget(); + beforeScrubSpacer.width = 10; + middleControls.addChildWidget(beforeScrubSpacer); + + // Scrub bar + var scrubBar:ScrubBar = new ScrubBar(); + scrubBar.id = WidgetIDs.SCRUB_BAR; + scrubBar.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + scrubBar.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + scrubBar.layoutMetadata.percentWidth = 100; + scrubBar.layoutMetadata.height = 25; + scrubBar.includeTimeHint = false; + middleControls.addChildWidget(scrubBar); + + // Spacer + var afterScrubSpacer:Widget = new Widget(); + afterScrubSpacer.width = 10; + middleControls.addChildWidget(afterScrubSpacer); + + // Duration + var totalTime:TotalTimeWidget = new TotalTimeWidget(); + totalTime.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; + totalTime.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + totalTime.layoutMetadata.height = 25; + middleControls.addChildWidget(totalTime); + + addChildWidget(middleControls); + + // FullScreen + var fullscreenLeaveButton:FullScreenLeaveButton = new FullScreenLeaveButton(); + fullscreenLeaveButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + fullscreenLeaveButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; + fullscreenLeaveButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + fullscreenLeaveButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + addChildWidget(fullscreenLeaveButton); + + var fullscreenEnterButton:FullScreenEnterButton = new FullScreenEnterButton(); + fullscreenEnterButton.id = WidgetIDs.FULL_SCREEN_ENTER_BUTTON; + fullscreenEnterButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + fullscreenEnterButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; + fullscreenEnterButton.addEventListener(MouseEvent.ROLL_OVER, showHighlight, false, 0, true); + fullscreenEnterButton.addEventListener(MouseEvent.ROLL_OUT, removeHighlight, false, 0, true); + addChildWidget(fullscreenEnterButton); + + var rightMargin:Widget = new Widget(); + rightMargin.face = AssetIDs.CONTROL_BAR_BACKDROP_RIGHT; + rightMargin.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; + addChildWidget(rightMargin); + + // Configure + configureWidgets([leftMargin, playButton, pauseButton, middleControls, currentTime, beforeScrubSpacer, scrubBar, afterScrubSpacer, totalTime, fullscreenLeaveButton, fullscreenEnterButton, rightMargin]); + + measure(); + + highlight = new ButtonHighlight(assetManager); + } + + // INTERNALS + // + + private function configureWidgets(widgets:Array):void + { + for each( var widget:Widget in widgets) + { + if (widget) + { + widget.configure(, assetManager); + } + } + } + + protected function removeHighlight(event:Event=null):void{ + if(highlight.parent) removeChild(highlight); + } + + protected function showHighlight(event:Event):void{ + if(isNaN(event.target.width) || isNaN(event.target.height)) return; + addChildAt(highlight, 1); + + //calculate it once [cut down on calculations] + if(!highlightSize) highlightSize = new Rectangle(0, 0, highlight.width/2, highlight.height/2); + + highlight.x = (event.target.x+event.target.width/2)-highlightSize.width; + highlight.y = (event.target.y+event.target.height/2)-highlightSize.height; + } + + protected var highlight:ButtonHighlight; + protected var highlightSize:Rectangle; + + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.PLAY; + } } \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/VolumeControlBar.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/VolumeControlBar.as index 86e0acc..e35e16b 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/VolumeControlBar.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/VolumeControlBar.as @@ -1,106 +1,106 @@ -/*********************************************************** - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems - * Incorporated. All Rights Reserved. - * - **********************************************************/ - -package org.osmf.player.chrome{ - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - import org.osmf.player.chrome.assets.AssetIDs; - import org.osmf.player.chrome.assets.AssetsManager; - import org.osmf.player.chrome.widgets.AutoHideWidget; - import org.osmf.player.chrome.widgets.MuteButton; - import org.osmf.player.chrome.widgets.VolumeWidget; - import org.osmf.player.chrome.widgets.Widget; - import org.osmf.player.chrome.widgets.WidgetIDs; - import org.osmf.traits.MediaTraitType; - - /** - * MobileControlBar - * @author johncblandii - */ - public class VolumeControlBar extends AutoHideWidget implements IControlBar - { - // OVERRIDES - // - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - //id = WidgetIDs; - face = AssetIDs.VOLUME_BAR_BACKDROP; - fadeSteps = 6; - - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - layoutMetadata.verticalAlign = VerticalAlign.TOP; - layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; - super.configure(xml, assetManager); - - // Mute/unmute - var muteButton:MuteButton = new MuteButton(false); - muteButton.id = WidgetIDs.MUTE_BUTTON; - muteButton.volumeSteps = 1; - muteButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - muteButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; - addChildWidget(muteButton); - - var separator:Widget = new Widget(); - separator.face = AssetIDs.VOLUME_BAR_BUTTON_SEPARATOR; - addChildWidget(separator); - - volumeWidget = new VolumeWidget(); - volumeWidget.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; - volumeWidget.layoutMetadata.width = layoutMetadata.width; - addChildWidget(volumeWidget); - - //muteButton.volumeWidget = volumeWidget; - - // Configure - configureWidgets([muteButton, separator, volumeWidget]); - - measure(); - } - - override public function set media(value:MediaElement):void{ - if(value != null){ - super.media = value; - if(volumeWidget) - volumeWidget.media = value; - } - } - - // INTERNALS - // - - private function configureWidgets(widgets:Array):void - { - for each( var widget:Widget in widgets) - { - if (widget) - { - widget.configure(, assetManager); - } - } - } - - private var volumeWidget:VolumeWidget; - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.AUDIO; - } +/*********************************************************** + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems + * Incorporated. All Rights Reserved. + * + **********************************************************/ + +package org.osmf.player.chrome{ + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaElement; + import org.osmf.player.chrome.assets.AssetIDs; + import org.osmf.player.chrome.assets.AssetsManager; + import org.osmf.player.chrome.widgets.AutoHideWidget; + import org.osmf.player.chrome.widgets.MuteButton; + import org.osmf.player.chrome.widgets.VolumeWidget; + import org.osmf.player.chrome.widgets.Widget; + import org.osmf.player.chrome.widgets.WidgetIDs; + import org.osmf.traits.MediaTraitType; + + /** + * MobileControlBar + * @author johncblandii + */ + public class VolumeControlBar extends AutoHideWidget implements IControlBar + { + // OVERRIDES + // + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + //id = WidgetIDs; + face = AssetIDs.VOLUME_BAR_BACKDROP; + fadeSteps = 6; + + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + layoutMetadata.verticalAlign = VerticalAlign.TOP; + layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; + super.configure(xml, assetManager); + + // Mute/unmute + var muteButton:MuteButton = new MuteButton(false); + muteButton.id = WidgetIDs.MUTE_BUTTON; + muteButton.volumeSteps = 1; + muteButton.layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + muteButton.layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; + addChildWidget(muteButton); + + var separator:Widget = new Widget(); + separator.face = AssetIDs.VOLUME_BAR_BUTTON_SEPARATOR; + addChildWidget(separator); + + volumeWidget = new VolumeWidget(); + volumeWidget.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; + volumeWidget.layoutMetadata.width = layoutMetadata.width; + addChildWidget(volumeWidget); + + //muteButton.volumeWidget = volumeWidget; + + // Configure + configureWidgets([muteButton, separator, volumeWidget]); + + measure(); + } + + override public function set media(value:MediaElement):void{ + if(value != null){ + super.media = value; + if(volumeWidget) + volumeWidget.media = value; + } + } + + // INTERNALS + // + + private function configureWidgets(widgets:Array):void + { + for each( var widget:Widget in widgets) + { + if (widget) + { + widget.configure(, assetManager); + } + } + } + + private var volumeWidget:VolumeWidget; + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.AUDIO; + } } \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/BackButton.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/BackButton.as index 176eac8..46a6c23 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/BackButton.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/BackButton.as @@ -23,7 +23,7 @@ package org.osmf.player.chrome.widgets import flash.events.Event; import flash.events.MouseEvent; - import org.osmf.player.chrome.assets.AssetIDs; + import org.osmf.player.chrome.assets.AssetIDs; public class BackButton extends ButtonWidget { diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/ButtonHighlight.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/ButtonHighlight.as index 0052aa4..6ac3097 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/ButtonHighlight.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/ButtonHighlight.as @@ -24,7 +24,7 @@ package org.osmf.player.chrome.widgets import flash.events.MouseEvent; import org.osmf.player.chrome.assets.AssetIDs; - import org.osmf.player.chrome.assets.AssetsManager; + import org.osmf.player.chrome.assets.AssetsManager; public class ButtonHighlight extends Sprite { diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/CurrentTimeWidget.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/CurrentTimeWidget.as index 31204e9..26caa6e 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/CurrentTimeWidget.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/CurrentTimeWidget.as @@ -53,7 +53,7 @@ package org.osmf.player.chrome.widgets import org.osmf.traits.MediaTraitType; import org.osmf.traits.PlayTrait; import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; + import org.osmf.traits.TimeTrait; /** * CurrentTimeWidget displays the current time and the total duration of the media. diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/FullScreenEnterButton.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/FullScreenEnterButton.as index e79a19d..16af539 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/FullScreenEnterButton.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/FullScreenEnterButton.as @@ -28,7 +28,7 @@ package org.osmf.player.chrome.widgets import org.osmf.media.MediaElement; import org.osmf.player.chrome.assets.AssetIDs; import org.osmf.player.chrome.events.WidgetEvent; - import org.osmf.traits.MediaTraitType; + import org.osmf.traits.MediaTraitType; public class FullScreenEnterButton extends ButtonWidget { diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/FullScreenLeaveButton.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/FullScreenLeaveButton.as index 42f4787..b1d7efe 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/FullScreenLeaveButton.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/FullScreenLeaveButton.as @@ -28,7 +28,7 @@ package org.osmf.player.chrome.widgets import org.osmf.media.MediaElement; import org.osmf.player.chrome.assets.AssetIDs; import org.osmf.player.chrome.events.WidgetEvent; - import org.osmf.traits.MediaTraitType; + import org.osmf.traits.MediaTraitType; public class FullScreenLeaveButton extends ButtonWidget { diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/VideoInfoOverlay.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/VideoInfoOverlay.as index e27abd3..ef0b5e7 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/VideoInfoOverlay.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/chrome/widgets/VideoInfoOverlay.as @@ -45,7 +45,7 @@ package org.osmf.player.chrome.widgets import org.osmf.player.utils.StrobePlayerStrings; import org.osmf.player.utils.StrobeUtils; import org.osmf.traits.MediaTraitType; - import org.osmf.utils.OSMFSettings; + import org.osmf.utils.OSMFSettings; CONFIG::FLASH_10_1 { diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/elements/ControlBarElement.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/elements/ControlBarElement.as index 597dd63..393d28d 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/elements/ControlBarElement.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/elements/ControlBarElement.as @@ -31,7 +31,7 @@ package org.osmf.player.elements import org.osmf.player.chrome.metadata.ChromeMetadata; import org.osmf.player.configuration.ControlBarType; import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.MediaTraitType; + import org.osmf.traits.MediaTraitType; /** * ControlBarElement defines a MediaElement implementation which contains the ControlBar UI. diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/elements/VolumeBarElement.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/elements/VolumeBarElement.as index 3582806..db4355a 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/elements/VolumeBarElement.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/elements/VolumeBarElement.as @@ -27,7 +27,7 @@ package org.osmf.player.elements import org.osmf.player.chrome.ChromeProvider; import org.osmf.player.chrome.VolumeControlBar; import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.MediaTraitType; + import org.osmf.traits.MediaTraitType; /** * VolumeBarElement defines a MediaElement implementation which contains the VolumeBar UI. diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/media/StrobeMediaPlayer.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/media/StrobeMediaPlayer.as index c3b93ae..eaada65 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/media/StrobeMediaPlayer.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/media/StrobeMediaPlayer.as @@ -262,56 +262,6 @@ package org.osmf.player.media ); } return rect; - } - - public function seekUntilSuccess(position:Number, maxRepeatCount:uint = 10):void - { - var repeatCount:uint = 0; - // WORKARROUND: FM-939 - HTTPStreamingDVR - the first seek always fails - // http://bugs.adobe.com/jira/browse/FM-939 - var workarroundTimer:Timer = new Timer(2000, 1); - workarroundTimer.addEventListener(TimerEvent.TIMER, - function (event:Event):void - { - if (canSeek) - { - repeatCount ++; - if (repeatCount < maxRepeatCount) - { - seek(position); - } - } - } - ); - - addEventListener - ( SeekEvent.SEEKING_CHANGE - , function(event:SeekEvent):void - { - if (event.seeking == false) - { - removeEventListener(event.type, arguments.callee); - - if (workarroundTimer != null) - { - // WORKARROUND: FM-939 - workarroundTimer.stop(); - workarroundTimer = null; - } - } - else - { - // WORKARROUND: FM-939 - if (workarroundTimer != null) - { - workarroundTimer.start(); - } - } - } - ); - - // Seek to the live position: - seek(position); } public function snapToLive():Boolean @@ -331,7 +281,7 @@ package org.osmf.player.media var livePosition:Number = Math.max(0, duration - bufferTime - dvrSnapToLiveClockOffset); if (canSeekTo(livePosition)) { - seekUntilSuccess(livePosition); + seek(livePosition); isDVRLive = true; return true; } diff --git a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/utils/StrobePlayerStrings.as b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/utils/StrobePlayerStrings.as index e329a4b..09f47d8 100644 --- a/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/utils/StrobePlayerStrings.as +++ b/lib/osmf/player/StrobeMediaPlayback/src/org/osmf/player/utils/StrobePlayerStrings.as @@ -69,7 +69,7 @@ package org.osmf.player.utils public static const title:String = 'Strobe Media Playback'; /** Use single quotes, to facilitate build system updates **/ - public static const version:String = '1.6.1.trunk'; + public static const version:String = '2.0.2494'; public static const ILLEGAL_INPUT_VARIABLE:String = "illegalInputVariable"; diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/.actionScriptProperties b/lib/osmf/player/StrobeMediaPlaybackAIR/.actionScriptProperties new file mode 100644 index 0000000..bd21400 --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/.actionScriptProperties @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/AppMeasurement.swc b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/AppMeasurement.swc new file mode 100644 index 0000000..ba40235 Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/AppMeasurement.swc differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/checkbox.fla b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/checkbox.fla new file mode 100644 index 0000000..6399d1c Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/checkbox.fla differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/checkbox.swc b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/checkbox.swc new file mode 100644 index 0000000..cbf3ecc Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/checkbox.swc differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Black.otf b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Black.otf new file mode 100644 index 0000000..c522fa2 Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Black.otf differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Bold.otf b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Bold.otf new file mode 100644 index 0000000..c7fbc9a Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Bold.otf differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Light.otf b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Light.otf new file mode 100644 index 0000000..92e31f6 Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Light.otf differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Regular.otf b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Regular.otf new file mode 100644 index 0000000..25786b4 Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSans-Regular.otf differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSansEULA.txt b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSansEULA.txt new file mode 100644 index 0000000..e351383 --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/font/PlaybackSansEULA.txt @@ -0,0 +1,96 @@ +Playback Sans is released under the SIL Open Font License - please read it carefully and do not download the fonts unless you agree to the the terms of the license: + +Copyright © 2010, Adobe Systems, Inc. (http://www.adobe.com/), +with Reserved Font Name Playback Sans + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/back.png b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/back.png new file mode 100644 index 0000000..89e611b Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/back.png differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/off.png b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/off.png new file mode 100644 index 0000000..5ff224f Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/off.png differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/on.png b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/on.png new file mode 100644 index 0000000..b24fbfd Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/images/on.png differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/assets/readme.txt b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/readme.txt new file mode 100644 index 0000000..cc79779 --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/assets/readme.txt @@ -0,0 +1 @@ +The symbols library contains graphical assets created using Flash CS5. \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/114x114.png b/lib/osmf/player/StrobeMediaPlaybackAIR/src/114x114.png new file mode 100644 index 0000000..5f88af2 Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/src/114x114.png differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/128x128.png b/lib/osmf/player/StrobeMediaPlaybackAIR/src/128x128.png new file mode 100644 index 0000000..29b7301 Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/src/128x128.png differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/72x72.png b/lib/osmf/player/StrobeMediaPlaybackAIR/src/72x72.png new file mode 100644 index 0000000..77d33d0 Binary files /dev/null and b/lib/osmf/player/StrobeMediaPlaybackAIR/src/72x72.png differ diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/MMTest.as b/lib/osmf/player/StrobeMediaPlaybackAIR/src/MMTest.as new file mode 100644 index 0000000..d6bdf05 --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/src/MMTest.as @@ -0,0 +1,113 @@ +package +{ + + import flash.display.Sprite; + import flash.events.Event; + import flash.events.MouseEvent; + import flash.events.NetDataEvent; + import flash.events.NetMonitorEvent; + import flash.events.NetStatusEvent; + import flash.net.*; + import flash.text.TextField; + import flash.text.TextFormat; + import flash.system.Security + + public class MMTest extends Sprite{ + private var _nmonitor:NetMonitor; + private var _txtDebug:TextField; + + public function MMTest(){ + super(); + + _nmonitor = new NetMonitor(); + var streams:Vector. = _nmonitor.listStreams(); + this._nmonitor.addEventListener(NetMonitorEvent.NET_STREAM_CREATE, netStreamCreate); + + _txtDebug = new TextField(); + _txtDebug.background = true; + _txtDebug.backgroundColor = 0x333333 + _txtDebug.border = true + _txtDebug.borderColor = 0xcccccc + _txtDebug.defaultTextFormat = new TextFormat("Verdana",10,0xffffff,false,null,null,null,null,null,4,4) + _txtDebug.autoSize= "left" + _txtDebug.wordWrap = true; + _txtDebug.width = 350; + _txtDebug.height = 192; + + this._txtDebug.text = "MM Tests:\n\n"; + this.addChild(_txtDebug); + //this.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown); + //this.addEventListener(MouseEvent.MOUSE_UP,onMouseUp); + } + + public function clean():void{ + this._txtDebug.text = "MM Tests:\n\n"; + } + + private function onMouseDown(e:Event):void{ + this.startDrag() + } + + private function onMouseUp(e:Event):void{ + this.stopDrag(); + } + + private function netStreamCreate( e:NetMonitorEvent):void{ + this._txtDebug.text += "---netStreamCreate--- \n\n"; + var ns:NetStream = e.netStream; + ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); + ns.addEventListener(NetDataEvent.MEDIA_TYPE_DATA, onStreamData); + + } + + private function netStatusHandler(e:NetStatusEvent):void{ + this._txtDebug.text += "--netStatusEvent.info.code:"+e.info.code+"\n" + var ns:NetStream = e.target as NetStream + + if (e.info.code=="NetStream.Play.Start"){ + this._txtDebug.text += "--Security.pageDomain:" + Security.pageDomain+"\n" + this._txtDebug.text += "--netStream.info.resourceName: " + ns.info.resourceName+"\n"; + this._txtDebug.text += "--netStream.info.isLive(): " + ns.info.isLive+"\n"; + this._txtDebug.text += "--netStream.info.uri: " + ns.info.uri+"\n\n"; + } + + } + + private function onStreamData(e:NetDataEvent):void { + this._txtDebug.text += "[+]"+"Data event at " + e.timestamp +"\n" ; + var netStream:NetStream = e.target as NetStream; + switch( e.info.handler ) + { + case "onMetaData": + this._txtDebug.text += "--MetaData: " + stringify( netStream.info.metaData ); + break; + case "onXMPData": + this._txtDebug.text += "--XMPData: " + stringify( netStream.info.xmpData ); + break; + default: + this._txtDebug.text += "--" + e.info.handler + ": " + stringify(e.info.args[0]) ; + + } + this._txtDebug.text += "[-]\n\n" + + } + + private function stringify( object:Object ):String{ + var string:String = ""; + + var prop:String; + var comma:Boolean = false; + for ( prop in object ) + { + if( comma ) string += ", "; + else comma = true; + + if( typeof(object[prop]) == "object" ) + { + stringify( object[prop] ) + } else string += prop + " = " + object[prop]; + } + return string; + } + } +} \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/MyVideoElement.as b/lib/osmf/player/StrobeMediaPlaybackAIR/src/MyVideoElement.as new file mode 100644 index 0000000..efaeb9e --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/src/MyVideoElement.as @@ -0,0 +1,197 @@ +package +{ + import flash.display.Bitmap; + import flash.display.Loader; + import flash.display.Sprite; + import flash.events.*; + import flash.filters.BitmapFilterQuality; + import flash.filters.DropShadowFilter; + import flash.net.URLRequest; + import flash.text.*; + + public class MyVideoElement extends Sprite + { + + private var _txtTime:TextField; + private var _txtName:TextField; + private var _txtDescription:TextField; + private var _border:Sprite; + private var _dropShadowFilter:DropShadowFilter; + + public var vidInfo:VideoInfo; + public var completeWidth:Number; + public var completeHeight:Number; + public var thumbImage:Bitmap; + + public static const BORDER:Number = 7; + + public function MyVideoElement(vi:VideoInfo, w:Number = 214, h:Number = 214):void { + super(); + + vidInfo = vi; + + //turn on button mode+hand cursor + this.buttonMode = true; + this.useHandCursor = true; + + //mouseEnabled = true; + completeWidth = w; + completeHeight = h; + + //loader for thumb + var ulThumb:Loader = new Loader(); + ulThumb.contentLoaderInfo.addEventListener(Event.COMPLETE, onThumbLoaded); + ulThumb.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onThumbIOError); + ulThumb.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onThumbSecurityError); + ulThumb.load(new URLRequest(vidInfo.videoThumbnailPath)); + + //display of name + _txtName = new TextField(); + _txtName.embedFonts = true; + _txtName.antiAliasType = AntiAliasType.ADVANCED; + _txtName.selectable = false; + _txtName.mouseEnabled = false; + _txtName.multiline = false; + _txtName.height = 24; + _txtName.defaultTextFormat = new TextFormat("PlaybackBlack", 14, 0x0299FD, true, false); + _txtName.text = vidInfo.videoName; + addChild(_txtName); + + //description + var descriptionFormat:TextFormat = new TextFormat("PlaybackLight", 10, 0x000000); + descriptionFormat.leading = -2; + _txtDescription = new TextField(); + _txtDescription.defaultTextFormat = descriptionFormat; + _txtDescription.embedFonts = true; + _txtDescription.antiAliasType = AntiAliasType.ADVANCED; + _txtDescription.selectable = false; + _txtDescription.multiline = true; + _txtDescription.wordWrap = true; + _txtDescription.mouseEnabled = false; + _txtDescription.height = 34; + _txtDescription.text = vidInfo.videoDescription; + addChild(_txtDescription); + + _dropShadowFilter = new DropShadowFilter(); + _dropShadowFilter.distance = 1; + _dropShadowFilter.angle = 45; + _dropShadowFilter.color = 0x333333; + _dropShadowFilter.alpha = 0.5; + _dropShadowFilter.blurX = 12; + _dropShadowFilter.blurY = 12; + _dropShadowFilter.strength = 1; + _dropShadowFilter.quality = BitmapFilterQuality.LOW; + _dropShadowFilter.inner = false; + _dropShadowFilter.knockout = false; + _dropShadowFilter.hideObject = false; + + thumbImage = new Bitmap(); + thumbImage.width = completeWidth; + thumbImage.height = completeHeight; + thumbImage.x = 0; + thumbImage.y = 0; + + _border = new Sprite(); + _border.mouseEnabled = false; + addChild(_border); + + //display of time + _txtTime = new TextField(); + _txtTime.embedFonts = true; + _txtTime.antiAliasType = AntiAliasType.ADVANCED; + _txtTime.selectable = false; + _txtTime.mouseEnabled = false; + _txtTime.background = true; + _txtTime.backgroundColor = 0x5E5E5E; + _txtTime.autoSize = TextFieldAutoSize.LEFT; + _txtTime.defaultTextFormat = new TextFormat("PlaybackLight", 12, 0xffffff); + _txtTime.text = formatSeconds(vidInfo.duration); + addChild(_txtTime); + + //events for mouse actions + addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); + addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); + + update(); + } + + public function resize(w:Number, h:Number):void { + completeWidth = w; + completeHeight = h; + resizeThumb(w, h); + update(); + } + + private function update():void { + _txtTime.y = completeHeight * 3 / 4 - _txtTime.height - 2 * BORDER; + _txtTime.x = completeWidth - _txtTime.width - 2 * BORDER; + _txtName.x = 0; + _txtName.y = (completeHeight * 3 / 4) + BORDER; + _txtName.width = completeWidth; + _txtDescription.x = 0; + _txtDescription.y = _txtName.y + _txtName.height - BORDER; + _txtDescription.width = completeWidth; + } + + private function resizeThumb(newW:Number, newH:Number):void { + if (thumbImage) { + thumbImage.width = newW; + thumbImage.height = newW * 3 / 4; + } + } + + private function formatSeconds(n:Number):String { + var sc:String = "00"; + if (Math.floor(n / 60) < 10) { + sc = "0" + Math.floor(n / 60).toString(); + } else { + sc = Math.floor(n / 60).toString(); + } + + var mn:String = "00"; + if ( n%60 < 10) { + mn = "0" + (n%60).toString(); + } else { + mn = (n%60).toString(); + } + return sc + ":" + mn; + } + + /* ---- + * Handlers + * ---- + */ + private function onThumbLoaded(e:Event):void { + var loader:Loader = Loader(e.target.loader); + + thumbImage = Bitmap(loader.content); + thumbImage.filters = new Array(_dropShadowFilter); + resizeThumb(completeWidth, completeHeight); + addChild(thumbImage); + + //we bring the time on top + addChild(_txtTime); + addChild(_border); + } + + private function onMouseOver(e:Event):void { + if (thumbImage != null && contains(thumbImage)) { + _border.graphics.clear(); + _border.graphics.beginFill(0xCBE7F9, 0.5); + _border.graphics.lineStyle(BORDER, 0xCBE7F9, 1, true); + _border.graphics.drawRect(0, 0, thumbImage.width, thumbImage.height); + _border.graphics.endFill(); + } + } + + private function onMouseOut(e:Event):void { + _border.graphics.clear(); + } + + private function onThumbIOError(e:Event):void{ + } + + private function onThumbSecurityError(e:Event):void{ + } + } +} \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/RoundButton.as b/lib/osmf/player/StrobeMediaPlaybackAIR/src/RoundButton.as new file mode 100644 index 0000000..04bde6e --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/src/RoundButton.as @@ -0,0 +1,76 @@ +package +{ + import flash.display.Bitmap; + import flash.display.Sprite; + import flash.events.MouseEvent; + + public class RoundButton extends Sprite + { + + [Embed(source="../assets/images/off.png")] + private var OffGraphic:Class; + + [Embed(source="../assets/images/on.png")] + private var OnGraphic:Class; + + private var _bitmapOff:Bitmap; + private var _bitmapOn:Bitmap; + + public var pageNumber:Number = 1; + public var activated:Boolean = false; + + public function RoundButton() { + _bitmapOff = new OffGraphic(); + _bitmapOn = new OnGraphic(); + + deactivate(); + } + + public function activate():void { + activated = true; + + this.buttonMode = true; + this.useHandCursor = true; + + this.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); + this.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); + + setOff(); + } + + public function deactivate():void { + activated = false; + + this.buttonMode = false; + this.useHandCursor = false; + + this.removeEventListener(MouseEvent.MOUSE_OVER,onMouseOver); + this.removeEventListener(MouseEvent.MOUSE_OUT,onMouseOut); + + setOn(); + } + + private function onMouseOver(e:MouseEvent):void { + setOn(); + } + + private function onMouseOut(e:MouseEvent):void { + setOff(); + } + + public function setOn():void { + if (contains(_bitmapOn)) { + removeChild(_bitmapOn); + } + + addChild(_bitmapOn); + } + + public function setOff():void { + if (contains(_bitmapOn)) { + removeChild(_bitmapOn); + } + addChild(_bitmapOff); + } + } +} \ No newline at end of file diff --git a/lib/osmf/samples/YouTubePluginTest/src/FlexUnitApplication-app.xml b/lib/osmf/player/StrobeMediaPlaybackAIR/src/StrobeMediaPlaybackAIR-app.xml similarity index 76% rename from lib/osmf/samples/YouTubePluginTest/src/FlexUnitApplication-app.xml rename to lib/osmf/player/StrobeMediaPlaybackAIR/src/StrobeMediaPlaybackAIR-app.xml index cc3fe6b..26e0a08 100644 --- a/lib/osmf/samples/YouTubePluginTest/src/FlexUnitApplication-app.xml +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/src/StrobeMediaPlaybackAIR-app.xml @@ -1,220 +1,250 @@ - - - - - - - FlexUnitApplication - - - FlexUnitApplication - - - FlexUnitApplication - - - 0.0.0 - - - - - - - - - - - - - - - - - - [This value will be overwritten by Flash Builder in the output app.xml] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + com.rms.mobileSMP + + + Nail + + + Nail + + + 1.0.0 + + + + + + + + + + + + + + + + + + [This value will be overwritten by Flash Builder in the output app.xml] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + direct + + + + + + true + false + true + + + + + + + + + + + + + + + + + + 72x72.png + 114x114.png + 128x128.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + UIDeviceFamily + + 1 + 2 + + ]]> + high + + diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/StrobeMediaPlaybackAIR.as b/lib/osmf/player/StrobeMediaPlaybackAIR/src/StrobeMediaPlaybackAIR.as new file mode 100644 index 0000000..4420c15 --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/src/StrobeMediaPlaybackAIR.as @@ -0,0 +1,1202 @@ +package +{ + //import AppMeasurement class frm AppMeasurement.swc + import com.omniture.AppMeasurement; + + import fl.controls.*; + import fl.transitions.Tween; + import fl.transitions.easing.Strong; + + import flash.display.*; + import flash.events.*; + import flash.geom.Matrix; + import flash.geom.Point; + import flash.media.*; + import flash.net.*; + import flash.system.Capabilities; + import flash.text.*; + import flash.ui.Multitouch; + import flash.ui.MultitouchInputMode; + import flash.utils.setTimeout; + + import org.osmf.layout.ScaleMode; + import org.osmf.player.chrome.events.WidgetEvent; + + + // we set the background of the SWF + [SWF(backgroundColor="0x000000", frameRate="25")] + + public class StrobeMediaPlaybackAIR extends Sprite + { + // available playlists + private const xmlURLDesktop:String = "http://catherine.corp.adobe.com/nail/playlists/playlist-desktop.xml"; + private const xmlURLAndroid:String = "http://catherine.corp.adobe.com/nail/playlists/playlist-android.xml"; + private const xmlURLiOS:String = "http://catherine.corp.adobe.com/nail/playlists/playlist-ios.xml"; + + // the skin to be loaded + private var skinURL:String = "http://catherine.corp.adobe.com/nail/skin/tablet-skin.xml"; + private var monitor:NetMonitor; + private var s:AppMeasurement; + + // UI elements + private var backgroundHomeView:Sprite; + private var backMatrix:Matrix; + private var whiteSheetHomeView:Sprite; + private var backgroundVideoView:Sprite; + private var whiteLeftSheetVideoView:Sprite; + private var whiteRightSheetVideoView:Sprite; + private var subTitleTxt:TextField; + private var subTitleBg:Sprite; + private var subTitleSep:Sprite; + private var txTitle:TextField; + private var spTitleBg:Sprite; + private var btBack:SuperBackButton; + private var spPlaylistContainer:Sprite; + private var txDescription:TextField; + private var txPosition:TextField; + private var spBottomLine:Sprite; + private var mmMonitor:MMTest; + private var txDescriptionLabel:TextField; + private var spDescriptionLine:Sprite; + private var smpPlayer:StrobeMediaPlayback; + private var maskForSmpStageVideoHomeBackground:Sprite; + private var maskForSmpStageVideoWhiteLeftSheet:Sprite; + private var cbMM:CheckBox; + private var cbPerf:CheckBox; + private var spMask:Sprite; + private var spNavHlder:Sprite; + + // UI data + private var nCurrentPage:Number = 1; + private var nPlaylistPages:Number = 1; + private var maxPerPage:Number = 2; + private var navigation:Vector. = new Vector.(); + private var plXMLLoader:URLLoader; + private var xmlPlaylist:XML; + private var arPlayListInfo:Array; + private var arPlayListElm:Array; + private var viewType:String = VIEW_HOME; + private var rows:Number = 0; + private var columns:Number = 0; + private var nOfElm:Number; + private var swiping:Boolean = false; + + private var calculatedThumbSize:Number = 0; + private var initializeParams:Object = new Object(); + + private var playlistCoords:Point; + private var playlistRotation:Number = 0; + + private var fullscreen:Boolean = false; + + private const THUMB_SIZE:Number = 214; + private const SPACING:Number = 24; + private const TITLE_HEIGHT:Number = 68; + private const SUBTITLE_HEIGHT:Number = 90; + + private const VIEW_HOME:String = "ViewHome"; + private const VIEW_VIDEO:String = "ViewVideo"; + + private const PLAYLIST_ORIENTATION_HORIZONTAL:String = "PlaylistOrientationHorizontal"; + private const PLAYLIST_ORIENTATION_VERTICAL:String = "PlaylistOrientationVertical"; + private const PLAYLIST_ORIENTATION_NONE:String = "PlaylistOrientationNone"; + + [Embed(source="assets/font/PlaybackSans-Regular.otf", fontFamily="Playback", embedAsCFF="false")] + private var PlaybackFont:Class; + [Embed(source="assets/font/PlaybackSans-Bold.otf", fontFamily="PlaybackBold", embedAsCFF="false")] + private var PlaybackBoldFont:Class; + [Embed(source="assets/font/PlaybackSans-Light.otf", fontFamily="PlaybackLight", embedAsCFF="false")] + private var PlaybackLightFont:Class; + [Embed(source="assets/font/PlaybackSans-Black.otf", fontFamily="PlaybackBlack", embedAsCFF="false")] + private var PlaybackBlackFont:Class; + + public function StrobeMediaPlaybackAIR() { + // we prepare the satge + stage.addEventListener(Event.RESIZE, onStageResize); + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullScreenHandler); + stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, function (e:StageVideoAvailabilityEvent):void {}); + + // gesture + Multitouch.inputMode = MultitouchInputMode.GESTURE; + + // we create a monitor to handle MM vaidation + monitor = new NetMonitor(); + var streams:Vector. = monitor.listStreams(); + monitor.addEventListener(NetMonitorEvent.NET_STREAM_CREATE, netStreamCreate); + + // app measurement plugin config + configAppMeasurement(); + + // creating design/layout components + createBackgrounds(); + createSubTitle(); + createWhiteSheets(); + createTitle(); + createPlaylist(); + createBottom(); + createMainVideo(); + createDebugOptions(); + createMMMonitor(); + + // loaing playlist + plXMLLoader = new URLLoader(); + this.plXMLLoader.addEventListener(Event.COMPLETE, onPLXMLLoaded); + this.plXMLLoader.addEventListener(IOErrorEvent.IO_ERROR,onPLXMLIOError); + this.plXMLLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onPLXMLSecurityError); + plXMLLoader.load(new URLRequest(playlist + "?rand=" + Math.random())); + } + + private function createBackgrounds():void { + // max of sizes + var squareEdgeSize:int = Math.max(stage.stageWidth, stage.stageHeight); + + // creating the mask needed to let the stage video show through all layers + maskForSmpStageVideoHomeBackground = new Sprite(); + maskForSmpStageVideoHomeBackground.graphics.clear(); + maskForSmpStageVideoHomeBackground.graphics.beginFill(0x000000, 1); + maskForSmpStageVideoHomeBackground.graphics.drawRect(0, 0, squareEdgeSize, squareEdgeSize); + maskForSmpStageVideoHomeBackground.graphics.endFill(); + + // creating the mask needed to let the stage video show through all layers + maskForSmpStageVideoWhiteLeftSheet = new Sprite(); + maskForSmpStageVideoWhiteLeftSheet.graphics.clear(); + maskForSmpStageVideoWhiteLeftSheet.graphics.beginFill(0x000000, 1); + maskForSmpStageVideoWhiteLeftSheet.graphics.drawRect(0, 0, squareEdgeSize, squareEdgeSize); + maskForSmpStageVideoWhiteLeftSheet.graphics.endFill(); + + // app background + backgroundHomeView = new Sprite(); + backMatrix = new Matrix(); + backgroundHomeView.x = 0; + backgroundHomeView.y = 0; + backgroundHomeView.blendMode = BlendMode.LAYER; + addChild(backgroundHomeView); + + backgroundVideoView = new Sprite(); + backgroundVideoView.visible = false; + addChild(backgroundVideoView); + + arrangeBackgrounds(); + } + + private function createTitle():void { + //title background + spTitleBg = new Sprite(); + var matr:Matrix = new Matrix(); + matr.createGradientBox(TITLE_HEIGHT, TITLE_HEIGHT, Math.PI / 2, 0, 0); + spTitleBg.graphics.beginGradientFill(GradientType.LINEAR, [0x484848,0x000000], [1,1], [0,255], matr); + spTitleBg.graphics.drawRect(0, 0, stage.stageWidth, TITLE_HEIGHT); + spTitleBg.x = 0; + spTitleBg.y = 0; + addChild(spTitleBg); + + //title + txTitle= new TextField(); + txTitle.embedFonts = true; + txTitle.antiAliasType = AntiAliasType.ADVANCED; + txTitle.defaultTextFormat = new TextFormat("PlaybackBlack", 24, 0xcccccc, true); + txTitle.autoSize= "left"; + txTitle.text = "Video Player"; + txTitle.selectable= false; + txTitle.x = SPACING; + txTitle.y = SPACING; + addChild (txTitle); + } + + private function createWhiteSheets():void { + //the white sheet that holds the playlist + whiteSheetHomeView = new Sprite(); + whiteSheetHomeView.visible = true; + whiteSheetHomeView.blendMode = BlendMode.LAYER; + addChild(whiteSheetHomeView); + + whiteLeftSheetVideoView = new Sprite(); + whiteLeftSheetVideoView.visible = false; + whiteLeftSheetVideoView.blendMode = BlendMode.LAYER; + addChild(whiteLeftSheetVideoView); + + whiteRightSheetVideoView = new Sprite(); + whiteRightSheetVideoView.visible = false; + addChild(whiteRightSheetVideoView); + + arrangeWhiteSheets(); + } + + private function arrangeWhiteSheets():void { + if (whiteSheetHomeView) { + whiteSheetHomeView.graphics.clear(); + whiteSheetHomeView.graphics.beginFill(0xffffff, 1); + whiteSheetHomeView.graphics.drawRoundRect(SPACING, SPACING, stage.stageWidth - 2 * SPACING, stage.stageHeight - 2 * SPACING - TITLE_HEIGHT, 24, 24); + whiteSheetHomeView.graphics.endFill(); + whiteSheetHomeView.x = 0; + whiteSheetHomeView.y = TITLE_HEIGHT; + } + + if (stage.stageHeight > stage.stageWidth) { + //vertical orientation + var availableHeight:Number = stage.stageHeight - TITLE_HEIGHT - SUBTITLE_HEIGHT; + if (whiteLeftSheetVideoView) { + whiteLeftSheetVideoView.graphics.clear(); + whiteLeftSheetVideoView.graphics.beginFill(0xffffff, 1); + whiteLeftSheetVideoView.graphics.drawRoundRect( + SPACING, + SPACING, + stage.stageWidth - 2 * SPACING, + availableHeight * 2 / 3 - 2 * SPACING, + 24, + 24 + ); + whiteLeftSheetVideoView.graphics.endFill(); + whiteLeftSheetVideoView.x = 0; + whiteLeftSheetVideoView.y = TITLE_HEIGHT + SUBTITLE_HEIGHT; + } + + if (whiteRightSheetVideoView) { + whiteRightSheetVideoView.graphics.clear(); + whiteRightSheetVideoView.graphics.beginFill(0xffffff, 1); + whiteRightSheetVideoView.graphics.drawRoundRect( + SPACING, + SPACING, + stage.stageWidth - 2 * SPACING, + availableHeight * 1 / 3 - 2 * SPACING, + 24, + 24 + ); + whiteRightSheetVideoView.graphics.endFill(); + whiteRightSheetVideoView.x = 0; + whiteRightSheetVideoView.y = TITLE_HEIGHT + SUBTITLE_HEIGHT + availableHeight * 2 / 3; + } + } else { + // horizontal orientation + if (whiteLeftSheetVideoView) { + whiteLeftSheetVideoView.graphics.clear(); + whiteLeftSheetVideoView.graphics.beginFill(0xffffff, 1); + whiteLeftSheetVideoView.graphics.drawRoundRect( + SPACING, + SPACING, + stage.stageWidth * 2 / 3 - 2 * SPACING, + stage.stageHeight - 2 * SPACING - TITLE_HEIGHT - SUBTITLE_HEIGHT, + 24, + 24 + ); + whiteLeftSheetVideoView.graphics.endFill(); + whiteLeftSheetVideoView.x = 0; + whiteLeftSheetVideoView.y = TITLE_HEIGHT + SUBTITLE_HEIGHT; + } + + if (whiteRightSheetVideoView) { + whiteRightSheetVideoView.graphics.clear(); + whiteRightSheetVideoView.graphics.beginFill(0xffffff, 1); + whiteRightSheetVideoView.graphics.drawRoundRect( + SPACING, + SPACING, + stage.stageWidth * 1 / 3 - 2 * SPACING, + stage.stageHeight - 2 * SPACING - TITLE_HEIGHT - SUBTITLE_HEIGHT, + 24, + 24 + ); + whiteRightSheetVideoView.graphics.endFill(); + whiteRightSheetVideoView.x = stage.stageWidth * 2 / 3; + whiteRightSheetVideoView.y = TITLE_HEIGHT + SUBTITLE_HEIGHT; + } + } + } + + private function arrangeBackgrounds():void { + // the background + var squareEdgeSize:int = Math.max(stage.stageWidth, stage.stageHeight); + if (backMatrix) { + backMatrix.createGradientBox(squareEdgeSize, squareEdgeSize, Math.PI / 2, 0, 0); + } + if (backgroundHomeView) { + backgroundHomeView.graphics.clear(); + backgroundHomeView.graphics.beginGradientFill(GradientType.LINEAR, [0x666666, 0x999999], [1, 1], [0, 255], backMatrix); + backgroundHomeView.graphics.drawRect(0, 0, squareEdgeSize, squareEdgeSize); + backgroundHomeView.graphics.endFill(); + } + if (stage.stageHeight > stage.stageWidth) { + // vertical orientation + var availableHeight:Number = stage.stageHeight - TITLE_HEIGHT - SUBTITLE_HEIGHT; + if (backgroundVideoView) { + backgroundVideoView.graphics.clear(); + backgroundVideoView.graphics.beginFill(0xffffff, 0.35); + backgroundVideoView.graphics.drawRect(0, 0, stage.stageWidth, availableHeight * 1 / 3); + backgroundVideoView.graphics.endFill(); + backgroundVideoView.x = 0; + backgroundVideoView.y = TITLE_HEIGHT + SUBTITLE_HEIGHT + availableHeight * 2 / 3; + } + } else { + // horizontal orientation + if (backgroundVideoView) { + backgroundVideoView.graphics.clear(); + backgroundVideoView.graphics.beginFill(0xffffff, 0.35); + backgroundVideoView.graphics.drawRect(0, 0, stage.stageWidth - stage.stageWidth * 2 / 3, stage.stageHeight - TITLE_HEIGHT + SUBTITLE_HEIGHT); + backgroundVideoView.graphics.endFill(); + backgroundVideoView.x = stage.stageWidth * 2 / 3; + backgroundVideoView.y = TITLE_HEIGHT + SUBTITLE_HEIGHT; + } + } + } + + private function createPlaylist():void { + // playlist area + spPlaylistContainer = new Sprite(); + addChild(spPlaylistContainer); + spPlaylistContainer.addEventListener(TransformGestureEvent.GESTURE_SWIPE, onSwipe); + + // mask + spMask = new Sprite(); + spMask.graphics.beginFill(0xffcccc, 1); + spMask.graphics.drawRect(0, 0, 1, 1); + spMask.graphics.endFill(); + addChild(spMask); + + // arranging the playlist + arrangePlaylistArea(); + } + + private function arrangePlaylistArea():void { + + //if the playlist.xml has not yet been loaded exit this function + if (!arPlayListElm) { + return; + } + + // are we landscape or portrait + var playlistOrientation:String = stage.stageWidth >= stage.stageHeight ? PLAYLIST_ORIENTATION_HORIZONTAL : PLAYLIST_ORIENTATION_VERTICAL; + + // this is the thumb rotation + var thumbRotation:Number = 0; + + // calculate columns and lines + if (viewType == VIEW_VIDEO) { + if (playlistOrientation == PLAYLIST_ORIENTATION_HORIZONTAL) { + // in this case we have only one row of thumbs + // is a row rotated by 90 degrees + rows = 1; + // calculate the proper thumb size + // we start calculating from the available width + calculatedThumbSize = whiteRightSheetVideoView.width - 4 * SPACING; + // calculate number of columns + columns = Math.ceil((whiteRightSheetVideoView.height - 2 * SPACING) / ((calculatedThumbSize + SPACING))); + // horizontally, we may get out of the box + if (columns * (calculatedThumbSize + SPACING) > whiteRightSheetVideoView.height - 2 * SPACING) { + calculatedThumbSize = Math.floor((whiteRightSheetVideoView.height - 2 * SPACING - (columns - 1) * SPACING) / columns); + } + // positioning the container + playlistCoords = new Point(whiteRightSheetVideoView.x + 2 * SPACING, whiteRightSheetVideoView.y + 2 * SPACING); + playlistRotation = 90; + thumbRotation = -90; + } else if (playlistOrientation == PLAYLIST_ORIENTATION_VERTICAL) { + // in this case we have only one row of thumbs + rows = 1; + // calculate the proper thumb size + // we start calculating from the available height + calculatedThumbSize = whiteRightSheetVideoView.height - 4 * SPACING; + // calculate number of columns + columns = Math.ceil((stage.stageWidth - 4 * SPACING) / ((calculatedThumbSize + SPACING))); + // horizontally, we may get out of the box + if (columns * (calculatedThumbSize + SPACING) > stage.stageWidth - 4 * SPACING) { + calculatedThumbSize = Math.floor((stage.stageWidth - 4 * SPACING - (columns - 1) * SPACING) / columns); + } + // positioning the container + playlistCoords = new Point(2 * SPACING, whiteRightSheetVideoView.y + 2 * SPACING); + playlistRotation = 0; + thumbRotation = 0; + } + } else { + // calculate number of columns + columns = Math.ceil((stage.stageWidth - 4 * SPACING) / ((THUMB_SIZE + SPACING))); + // calculate the proper thumb size + calculatedThumbSize = (stage.stageWidth - 4 * SPACING - (columns - 1) * SPACING) / columns; + // calculate the rows + rows = Math.floor( + (stage.stageHeight - TITLE_HEIGHT - 3 * SPACING) / (calculatedThumbSize + SPACING) + ); + // positioning the container + playlistCoords = new Point(2 * SPACING, TITLE_HEIGHT + 2 * SPACING); + playlistRotation = 0; + thumbRotation = 0; + } + + + if (columns > 0 && rows > 0) { + //max number of elements per page + maxPerPage = columns * rows; + + //total number of elemets + nOfElm = arPlayListElm.length; + + //caluclate pages + nPlaylistPages = Math.ceil(nOfElm / (columns * rows)); + + //reduce current page # if the Ui has been modified and now we have fewer pages + if (nCurrentPage > nPlaylistPages) { + nCurrentPage = nPlaylistPages + } + + var col:int = 0; + var row:int = 0; + var page:int = 0; + + for each (var vidElm:MyVideoElement in arPlayListElm) { + if (col >= columns) { + row++; + col = 0; + } + if (row >= rows) { + row = 0; + page++; + } + + // resizing the thumbs + var thumbRatio:Number = vidElm.completeHeight / vidElm.completeWidth; + vidElm.resize(calculatedThumbSize, calculatedThumbSize * thumbRatio); + vidElm.rotation = thumbRotation; + // position the thumbs + vidElm.x = col * (calculatedThumbSize + SPACING) + page * (columns * (calculatedThumbSize + SPACING)); + vidElm.y = row * (calculatedThumbSize + SPACING); + + col++; + } + + // positioning the playlist + spPlaylistContainer.x = playlistCoords.x; + spPlaylistContainer.y = playlistCoords.y; + spPlaylistContainer.rotation = playlistRotation; + + // position and apply playlist mask + if (viewType == VIEW_VIDEO) { + if (playlistOrientation == PLAYLIST_ORIENTATION_HORIZONTAL) { + spMask.width = calculatedThumbSize * rows + SPACING * (rows - 1) + 2 * MyVideoElement.BORDER; + } else { + spMask.width = calculatedThumbSize * columns + SPACING * (columns - 1) + 2 * MyVideoElement.BORDER; + } + spMask.x = whiteRightSheetVideoView.x + 2 * SPACING - MyVideoElement.BORDER; + spMask.y = whiteRightSheetVideoView.y + 2 * SPACING - MyVideoElement.BORDER; + spMask.height = whiteRightSheetVideoView.height - 2 * SPACING + 2 * MyVideoElement.BORDER; + } else { + spMask.width = calculatedThumbSize * columns + SPACING * (columns - 1) + 2 * MyVideoElement.BORDER; + spMask.x = whiteSheetHomeView.x + 2 * SPACING - MyVideoElement.BORDER; + spMask.y = whiteSheetHomeView.y + 2 * SPACING - MyVideoElement.BORDER; + spMask.height = whiteSheetHomeView.height - 3 * SPACING; + } + spMask.alpha = 0.5; + spPlaylistContainer.mask = spMask; + + // calculate and show "x of y elements are shown" + var maxNumber:Number = Math.min((rows * columns * nCurrentPage), nOfElm) + txPosition.text = ((maxPerPage * (nCurrentPage - 1)) + 1) + "-" + maxNumber + " of " + nOfElm + " videos"; + txPosition.x = stage.stageWidth - 2 * SPACING - txPosition.width; + + // remove previous nav + for (var j:int = 0; j < navigation.length; j++) { + if (navigation[j]) { + if (spNavHlder.contains(navigation[j])) { + spNavHlder.removeChild(navigation[j]); + } + navigation[j] = null; + } + } + + // draw the new navigation + if (nPlaylistPages > 1) { + // if we have more elements than we can fit on a page + for (var l:int=0; l < nPlaylistPages; l++) { + navigation[l] = new RoundButton(); + navigation[l].pageNumber = l + 1; + spNavHlder.addChild(navigation[l]); + if (viewType == VIEW_VIDEO && playlistOrientation == PLAYLIST_ORIENTATION_HORIZONTAL) { + // calculating the vertical center and the right side position + navigation[l].x = 0; + navigation[l].y = (l * (navigation[l].width + 6)) - 6; + spNavHlder.x = stage.stageWidth - 3 * SPACING; + spNavHlder.y = whiteRightSheetVideoView.y + SPACING + (whiteRightSheetVideoView.height - spNavHlder.height) / 2; + } else { + // calculating the horizontal possition in the bottom + navigation[l].x = (l * (navigation[l].width + 6)) - 6; + navigation[l].y = 0; + spNavHlder.x = (stage.stageWidth - spNavHlder.width) / 2; + spNavHlder.y = stage.stageHeight - 2 * SPACING - spNavHlder.height / 2 - 1; + } + navigation[l].addEventListener(MouseEvent.CLICK, onClickNavigation); + + if (navigation[l].pageNumber != nCurrentPage) { + navigation[l].activate(); + + } + } + } + } + // moving to the current page + gotoPageNumber(nCurrentPage); + } + + private function createSubTitle():void { + // add subtitle background + subTitleBg = new Sprite(); + subTitleBg.graphics.clear(); + subTitleBg.graphics.beginFill(0x0099ff, 0.22); + subTitleBg.graphics.drawRect(0, 0, stage.stageWidth, SUBTITLE_HEIGHT); + subTitleBg.graphics.endFill(); + subTitleBg.x = 0; + subTitleBg.y = TITLE_HEIGHT; + subTitleBg.visible = false; + addChild(subTitleBg); + + // back button + btBack = new SuperBackButton(); + addChild(btBack); + btBack.x = SPACING; + btBack.y = TITLE_HEIGHT + (SUBTITLE_HEIGHT - btBack.height) / 2; + btBack.visible = false; + btBack.addEventListener(MouseEvent.CLICK, onClickBack); + + // creating separator + subTitleSep = new Sprite(); + subTitleSep.graphics.clear(); + subTitleSep.graphics.lineStyle(1, 0xffffff, 0.5); + subTitleSep.graphics.lineTo(0, SUBTITLE_HEIGHT - 2 * SPACING); + subTitleSep.x = btBack.x + btBack.width + SPACING; + subTitleSep.y = TITLE_HEIGHT + SPACING; + subTitleSep.visible = false; + addChild(subTitleSep); + + // add subtitle text + subTitleTxt = new TextField(); + subTitleTxt.embedFonts = true; + subTitleTxt.antiAliasType = AntiAliasType.ADVANCED; + subTitleTxt.defaultTextFormat = new TextFormat("PlaybackBlack", 24, 0xffffff); + subTitleTxt.autoSize = TextFieldAutoSize.LEFT; + subTitleTxt.selectable = false; + subTitleTxt.visible = false; + // adding a text field without any character will result in a incorrect height value + // so we use a space to get the proper height value + subTitleTxt.text = " "; + subTitleTxt.x = btBack.x + btBack.width + 2 * SPACING; + subTitleTxt.y = TITLE_HEIGHT + (SUBTITLE_HEIGHT - subTitleTxt.height) / 2; + addChild(subTitleTxt); + } + + private function createMainVideo():void { + // initialization parameters + initializeParams["autoPlay"] = false; + initializeParams["skin"] = skinURL; + initializeParams["backgroundColor"] = 0x000000; + initializeParams["showVideoInfoOverlayOnStartUp"] = false; + initializeParams["controlBarType"] = "tablet"; + initializeParams["controlBarMode"] = "floating"; + initializeParams["enableStageVideo"] = true; + initializeParams["playButtonOverlay"] = false; + initializeParams["posterScaleMode"] = ScaleMode.ZOOM; + + // strobe media playback + if (!smpPlayer) { + // we create a player + smpPlayer = new StrobeMediaPlayback(); + smpPlayer.initialize(initializeParams, this.stage, null, null); + smpPlayer.addEventListener(WidgetEvent.VIDEO_INFO_OVERLAY_CLOSE, + function (event:WidgetEvent):void + { + cbPerf.selected = false; + } + ); + } + smpPlayer.visible = false; + smpPlayer.x = 2 * SPACING; + smpPlayer.y = TITLE_HEIGHT + SUBTITLE_HEIGHT + 2 * SPACING; + + if (!contains(smpPlayer)) { + addChild(smpPlayer) + } + + // description label text + txDescriptionLabel = new TextField(); + txDescriptionLabel.embedFonts = true; + txDescriptionLabel.antiAliasType = AntiAliasType.ADVANCED; + txDescriptionLabel.selectable = false; + txDescriptionLabel.defaultTextFormat = new TextFormat("PlaybackBlack", 12, 0x000000); + txDescriptionLabel.autoSize = "left"; + txDescriptionLabel.text = "Description"; + txDescriptionLabel.visible = false; + txDescriptionLabel.x = 2 * SPACING; + addChild(txDescriptionLabel); + + spDescriptionLine = new Sprite(); + spDescriptionLine.visible = false; + spDescriptionLine.x = 2 * SPACING; + addChild(spDescriptionLine); + + //description + txDescription = new TextField(); + txDescription.embedFonts = true; + txDescription.antiAliasType = AntiAliasType.ADVANCED; + txDescription.selectable = false; + txDescription.defaultTextFormat = new TextFormat("PlaybackLight", 12, 0x0000); + txDescription.autoSize = "left"; + txDescription.wordWrap = true; + txDescription.multiline = true; + txDescription.visible = false; + txDescription.width = stage.stageWidth * 2 / 3 - 4 * SPACING; + txDescription.x = 2 * SPACING; + txDescription.text = "lipsum"; + addChild(txDescription); + + arrangeMainVideo(); + } + + private function arrangeMainVideo():void { + if (fullscreen) { + smpPlayer.setSize(stage.stageWidth, stage.stageHeight); + } else { + var width:Number; + var height:Number; + if (stage.stageHeight > stage.stageWidth) { + // vertical orientation + width = stage.stageWidth - 4 * SPACING; + height = width * 9 / 16; + } else { + // horizontal orientation + width = stage.stageWidth * 2 / 3 - 4 * SPACING; + height = width * 9 / 16; + } + if (smpPlayer) { + smpPlayer.setSize(width, height); + smpPlayer.x = whiteLeftSheetVideoView.x + 2 * SPACING; + smpPlayer.y = whiteLeftSheetVideoView.y + 2 * SPACING; + if (viewType == VIEW_VIDEO) { + if (maskForSmpStageVideoHomeBackground) { + maskForSmpStageVideoHomeBackground.width = width; + maskForSmpStageVideoHomeBackground.height = height; + maskForSmpStageVideoHomeBackground.x = 2 * SPACING; + maskForSmpStageVideoHomeBackground.y = TITLE_HEIGHT + SUBTITLE_HEIGHT + 2 * SPACING; + maskForSmpStageVideoHomeBackground.blendMode = BlendMode.ERASE; + backgroundHomeView.blendMode = BlendMode.LAYER; + backgroundHomeView.addChild(maskForSmpStageVideoHomeBackground); + } + if (maskForSmpStageVideoWhiteLeftSheet) { + maskForSmpStageVideoWhiteLeftSheet.width = width; + maskForSmpStageVideoWhiteLeftSheet.height = height; + maskForSmpStageVideoWhiteLeftSheet.x = 2 * SPACING; + maskForSmpStageVideoWhiteLeftSheet.y = 2 * SPACING; + maskForSmpStageVideoWhiteLeftSheet.blendMode = BlendMode.ERASE; + whiteLeftSheetVideoView.blendMode = BlendMode.LAYER; + whiteLeftSheetVideoView.addChild(maskForSmpStageVideoWhiteLeftSheet); + } + } + } + + if (txDescriptionLabel) { + txDescriptionLabel.y = TITLE_HEIGHT + SUBTITLE_HEIGHT + 2 * SPACING + height + SPACING; + } + if (spDescriptionLine) { + spDescriptionLine.graphics.clear(); + spDescriptionLine.graphics.lineStyle(1, 0xcccccc, 1, true, "normal"); + spDescriptionLine.graphics.lineTo(whiteLeftSheetVideoView.width - 2 * SPACING, 0); + spDescriptionLine.y = txDescriptionLabel. y + txDescriptionLabel.height + SPACING / 2; + } + if (txDescription) { + txDescription.y = txDescriptionLabel.y + txDescriptionLabel.height + SPACING; + } + } + } + + private function createBottom():void { + //spNavHlder + spNavHlder = new Sprite(); + addChild(spNavHlder); + + //bottom line + spBottomLine = new Sprite(); + addChild(spBottomLine); + + //playlist position text + txPosition = new TextField(); + txPosition.embedFonts = true; + txPosition.antiAliasType = AntiAliasType.ADVANCED; + txPosition.defaultTextFormat = new TextFormat("Playback", 14, 0x0299FD); + txPosition.autoSize = TextFieldAutoSize.LEFT; + txPosition.selectable = false; + addChild(txPosition); + + arrangeBottom(); + } + + private function arrangeBottom():void { + if (viewType == VIEW_VIDEO && stage.stageWidth > stage.stageHeight) { + if (spBottomLine) { + spBottomLine.graphics.clear(); + spBottomLine.graphics.lineStyle(1, 0xcccccc, 1, true, "normal"); + spBottomLine.graphics.lineTo(0, whiteRightSheetVideoView.height - 2 * SPACING); + spBottomLine.x = whiteRightSheetVideoView.x + whiteRightSheetVideoView.width - 2 * SPACING; + spBottomLine.y = whiteRightSheetVideoView.y + 2 * SPACING; + } + if (txPosition) { + txPosition.rotation = -90; + txPosition.x = whiteRightSheetVideoView.x + whiteRightSheetVideoView.width - SPACING; + txPosition.y = whiteRightSheetVideoView.y + 2 * SPACING + txPosition.textWidth; + } + } else { + if (spBottomLine) { + spBottomLine.graphics.clear(); + spBottomLine.graphics.lineStyle(1, 0xcccccc, 1, true, "normal"); + spBottomLine.graphics.lineTo(stage.stageWidth - 4 * SPACING, 0); + spBottomLine.x = 2 * SPACING; + spBottomLine.y = stage.stageHeight - 3 * SPACING; + } + if (txPosition) { + txPosition.rotation = 0; + txPosition.x = stage.stageWidth - 2 * SPACING - txPosition.width; + txPosition.y = stage.stageHeight - 2 * SPACING - txPosition.height / 2; + } + } + } + + private function createDebugOptions():void { + //cbMM + cbMM = new CheckBox(); + cbMM.textField.autoSize = "left"; + cbMM.label = "Show MM Info"; + cbMM.x= SPACING; + cbMM.y= stage.stageHeight - SPACING - 20; //these components start with a wierd size so we kind of approximate their position for now + cbMM.addEventListener(MouseEvent.CLICK, toggleMM); + cbMM.visible = false; + addChild(cbMM); + + //cbPerf + cbPerf = new CheckBox(); + cbPerf.textField.autoSize = "left"; + cbPerf.label = "Show Performance"; + cbPerf.x = 200; + cbPerf. y = stage.stageHeight - SPACING - 20; //these components start with a wierd size so we kind of approximate their position for now + cbPerf.addEventListener(MouseEvent.CLICK, togglePerformance); + cbPerf.visible = false; + addChild(cbPerf); + } + + private function createMMMonitor():void { + //media measurement debug window and listener for the keyboard + mmMonitor = new MMTest(); + mmMonitor.visible=false; + mmMonitor.x= stage.stageWidth/2; + mmMonitor.y = TITLE_HEIGHT+SPACING +5; + addChild(mmMonitor); + } + + private function changeView():void { + if (viewType == VIEW_VIDEO) { + // show subtitle + subTitleBg.visible = true; + subTitleSep.visible = true; + subTitleTxt.visible = true; + // show back button + btBack.visible = true; + // show right backgorund + backgroundVideoView.visible = true; + // hide home sheet + whiteSheetHomeView.visible = false; + // show white sheets + whiteLeftSheetVideoView.visible = true; + whiteRightSheetVideoView.visible = true; + // show Strobe Media Player + smpPlayer.visible = true; + // show description + txDescriptionLabel.visible = true; + spDescriptionLine.visible = true; + txDescription.visible = true; + + // TODO: Re-evaluate the plugin loading mechanism in OSMF when developing AIR applications + //initializeParams["plugin_ads"] = "http://avchathq.com/Nail/AdvertisementPlugin.swf"; + + cbMM.visible = true; + cbPerf.visible = true; + + } else { + // hide subtitle + subTitleBg.visible = false; + subTitleSep.visible = false; + subTitleTxt.visible = false; + // hide back button + btBack.visible = false; + // hide right backgorund + backgroundVideoView.visible = false; + // show home sheet + whiteSheetHomeView.visible = true; + // hide white sheets + whiteLeftSheetVideoView.visible = false; + whiteRightSheetVideoView.visible = false; + // stopping & hiding the Strobe Media Player + smpPlayer.player.stop() + smpPlayer.visible = false; + // hide description + txDescriptionLabel.visible = false; + spDescriptionLine.visible = false; + txDescription.visible = false; + + //hide the MM monitor and performance windows + if (mmMonitor) { + mmMonitor.visible=false; + } + + if (smpPlayer) { + smpPlayer.showVideoInfo(false); + } + + //we hide the checkboxes + if (cbMM) { + cbMM.selected = false; + cbMM.visible = false; + } + if (cbPerf) { + cbPerf.selected = false; + cbPerf.visible = false; + } + } + + // clean the MM window + if (mmMonitor) { + mmMonitor.clean() + } + + // arranging zones + arrangePlaylistArea(); + arrangeWhiteSheets(); + arrangeBackgrounds(); + arrangeMainVideo(); + arrangeBottom(); + } + + private function gotoPageNumber(n:Number):void { + if (n > 0 && n <= nPlaylistPages) { + nCurrentPage = n; + // are we landscape or portrait + var playlistOrientation:String = stage.stageWidth >= stage.stageHeight ? PLAYLIST_ORIENTATION_HORIZONTAL : PLAYLIST_ORIENTATION_VERTICAL; + + if (viewType == VIEW_VIDEO && playlistOrientation == PLAYLIST_ORIENTATION_HORIZONTAL) + { + new Tween( + spPlaylistContainer, + "y", + Strong.easeOut, + spPlaylistContainer.y, + playlistCoords.y - (n - 1) * ((calculatedThumbSize + SPACING) * columns), + 0.5, + true + ); + } else { + new Tween( + spPlaylistContainer, + "x", + Strong.easeOut, + spPlaylistContainer.x, + playlistCoords.x - (n - 1) * ((calculatedThumbSize + SPACING) * columns), + 0.5, + true + ); + } + + //calculate and show "X of Y elements are shown" + var maxNumber:Number = Math.min((rows * columns * nCurrentPage), nOfElm); + txPosition.text = ((maxPerPage * (nCurrentPage - 1)) + 1) + "-" + maxNumber + " of " + nOfElm + " videos"; + + arrangeBottom(); + + //activate and deactivte navigation elements to correspond to the new currentPage + for (var j:int = 0; j < navigation.length; j++) { + if (navigation[j] != null) { + if (j != (nCurrentPage - 1)) { + navigation[j].activate(); + } else { + navigation[j].deactivate(); + } + } + } + } + } + + private function configAppMeasurement():void { + s = new AppMeasurement(); + s.account = "adobedevromania"; + s.Media.autoTrackNetStreams=true; + s.Media.autoTrack= true; + s.Media.trackWhilePlaying = true; + s.Media.trackSeconds=5 + s.Media.playerName="Nail iOS"; + s.debugTracking = true; + s.trackLocal = true; + s.trackOnLoad = true; + s.visitorNamespace = "adobedevelopment"; + s.trackingServer = "adobedevelopment.112.2o7.net"; + addChild(s); + } + + /* ---- + * Handlers + * ---- + */ + private function onPLXMLLoaded(e:Event=null):void { + xmlPlaylist = XML(e.target.data); + var playList:XMLList = xmlPlaylist.video; + var i:Number = -1; + arPlayListInfo = new Array(); + arPlayListElm = new Array() + for each (var video:XML in playList) { + i++; + var vidInfo:VideoInfo = new VideoInfo(); + vidInfo.videoName = video.attribute("name"); + vidInfo.videoDescription = video.attribute("description"); + vidInfo.videoThumbnailPath = video.attribute("thumbnail"); + vidInfo.videoPath = video.attribute("path"); + vidInfo.duration = video.attribute("duration") + /* + // TODO: Re-evaluate the plugin loading mechanism in OSMF when developing AIR applications + if (video.attribute("preroll") != null && video.attribute("preroll") != "undefined") { + vidInfo.preroll = video.attribute("preroll"); + } + if (video.attribute("postroll") != null && video.attribute("postroll") != "undefined") { + vidInfo.postroll = video.attribute("postroll"); + } + if (video.attribute("midroll") != null && video.attribute("midroll") != "undefined") { + vidInfo.midroll = video.attribute("midroll"); + } + if (video.attribute("midrollTime") != null && video.attribute("midrollTime") != "undefined") { + vidInfo.midrollTime = video.attribute("midrollTime") as Number; + } + if (video.attribute("overlay") != null && video.attribute("overlay") != "undefined") { + vidInfo.overlay = video.attribute("overlay"); + } + if (video.attribute("overlay") != null && video.attribute("overlay") != "undefined") { + vidInfo.overlay = video.attribute("overlay"); + } + if (video.attribute("overlayTime") != null && video.attribute("overlayTime") != "undefined") { + vidInfo.overlayTime = video.attribute("overlayTime") as Number; + } */ + var vidElement:MyVideoElement = new MyVideoElement(vidInfo, THUMB_SIZE, THUMB_SIZE); + vidElement.addEventListener(MouseEvent.CLICK, onVideoElementClick); + spPlaylistContainer.addChild(vidElement); + + arPlayListElm.push(vidElement) + arPlayListInfo.push(vidInfo); + } + arrangePlaylistArea(); + } + + private function onVideoElementClick(e:Event):void { + if (!swiping) { + viewType = VIEW_VIDEO; + changeView(); + + subTitleTxt.text = (e.target as MyVideoElement).vidInfo.videoName; + txDescription.text = (e.target as MyVideoElement).vidInfo.videoDescription; + + if (smpPlayer) { + smpPlayer.configuration.poster = (e.target as MyVideoElement).vidInfo.videoThumbnailPath; + smpPlayer.configuration.src = (e.target as MyVideoElement).vidInfo.videoPath; + smpPlayer.loadMedia(); + } else { + initializeParams["poster"] = (e.target as MyVideoElement).vidInfo.videoThumbnailPath; + initializeParams["src"] = (e.target as MyVideoElement).vidInfo.videoPath; + /* + // TODO: Re-evaluate the plugin loading mechanism in OSMF when developing AIR applications + if ((e.target as MyVideoElement).vidInfo.preroll) { + initializeParams["ads_preroll"] = (e.target as MyVideoElement).vidInfo.preroll; + } + if ((e.target as MyVideoElement).vidInfo.postroll) { + initializeParams["ads_postroll"] = (e.target as MyVideoElement).vidInfo.postroll; + } + if ((e.target as MyVideoElement).vidInfo.midroll) { + initializeParams["ads_midroll"] = (e.target as MyVideoElement).vidInfo.midroll; + } + if ((e.target as MyVideoElement).vidInfo.midrollTime) { + initializeParams["ads_midrollTime"] = (e.target as MyVideoElement).vidInfo.midrollTime; + } + if ((e.target as MyVideoElement).vidInfo.overlay) { + initializeParams["ads_overlay"] = (e.target as MyVideoElement).vidInfo.overlay; + } + if ((e.target as MyVideoElement).vidInfo.overlayTime) { + initializeParams["ads_overlayTime"] = (e.target as MyVideoElement).vidInfo.overlayTime; + } */ + smpPlayer.initialize(initializeParams, this.stage, null, null); + } + + } + } + + private function onFullScreenHandler(event:FullScreenEvent):void { + if (event.fullScreen) { + fullscreen = true; + // hide all + backgroundHomeView.visible = false; + spTitleBg.visible = false; + txTitle.visible = false; + subTitleBg.visible = false; + subTitleSep.visible = false; + subTitleTxt.visible = false; + btBack.visible = false; + backgroundVideoView.visible = false; + whiteSheetHomeView.visible = false; + whiteLeftSheetVideoView.visible = false; + whiteRightSheetVideoView.visible = false; + txDescriptionLabel.visible = false; + spDescriptionLine.visible = false; + txDescription.visible = false; + spBottomLine.visible = false; + txPosition.visible = false; + spPlaylistContainer.visible =false; + cbPerf.visible=false; + cbMM.visible=false; + spNavHlder.visible = false; + + smpPlayer.x = 0; + smpPlayer.y = 0; + smpPlayer.setSize(stage.stageWidth, stage.stageHeight); + } else { + fullscreen = false; + // show what is necessary + backgroundHomeView.visible = true; + spTitleBg.visible = true; + txTitle.visible = true; + subTitleBg.visible = true; + subTitleSep.visible = true; + subTitleTxt.visible = true; + btBack.visible = true; + backgroundVideoView.visible = true; + whiteLeftSheetVideoView.visible = true; + whiteRightSheetVideoView.visible = true; + txDescriptionLabel.visible = true; + spDescriptionLine.visible = true; + txDescription.visible = true; + spBottomLine.visible = true; + txPosition.visible = true; + spPlaylistContainer.visible = true; + cbPerf.visible = true; + cbMM.visible = true; + spNavHlder.visible = true; + + arrangeBackgrounds(); + arrangeWhiteSheets(); + arrangePlaylistArea(); + arrangeMainVideo(); + arrangeBottom(); + } + }; + + private function onSwipe(e:TransformGestureEvent):void { + var playlistOrientation:String = stage.stageWidth >= stage.stageHeight ? PLAYLIST_ORIENTATION_HORIZONTAL : PLAYLIST_ORIENTATION_VERTICAL; + swiping = true; + if (viewType == VIEW_VIDEO && playlistOrientation == PLAYLIST_ORIENTATION_HORIZONTAL) { + if (e.offsetY >= 0) { + // user swiped upwards + gotoPageNumber(nCurrentPage-1); + } + if (e.offsetY < 0) { + // user swiped downwards + gotoPageNumber(nCurrentPage+1); + } + } else { + if (e.offsetX >= 0) { + // user swiped towards right + gotoPageNumber(nCurrentPage-1); + } + if (e.offsetX < 0) { + // user swiped towards left + gotoPageNumber(nCurrentPage+1); + } + } + + var timeOut:Number = setTimeout(cancelSwiping, 1000); + } + + private function cancelSwiping():void { + swiping = false; + } + + private function netStreamCreate(e:NetMonitorEvent):void { + var ns:NetStream = e.netStream; + ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); + } + + private function netStatusHandler(event:NetStatusEvent):void { + } + + private function onClickBack(e:MouseEvent):void { + viewType = VIEW_HOME; + changeView(); + } + + private function onStageResize(event:Event = null):void { + + // resize the top header bg + if (spTitleBg) { + spTitleBg.width = stage.stageWidth; + } + // resize the sub title + if (subTitleBg) { + subTitleBg.width = stage.stageWidth; + } + + //arrange the playlist + arrangeWhiteSheets(); + arrangePlaylistArea(); + arrangeBackgrounds(); + arrangeMainVideo(); + arrangeBottom(); + + //position the checkboxes + if (cbMM) { + cbMM.y= stage.stageHeight - SPACING; + } + if (cbPerf) { + cbPerf. y = stage.stageHeight - SPACING; + } + } + + private function onClickNavigation(e:Event):void { + gotoPageNumber((e.target as RoundButton).pageNumber); + } + + private function onPLXMLIOError(e:Event = null):void { + } + + private function onPLXMLSecurityError(e:Event = null):void { + } + + private function toggleMM(e:MouseEvent):void { + if (!mmMonitor.visible) { + mmMonitor.visible = true; + addChild(mmMonitor) + } else { + mmMonitor.visible = false; + } + } + + private function togglePerformance(e:MouseEvent):void { + if (smpPlayer) { + if (cbPerf.selected) { + smpPlayer.showVideoInfo(true); + } else { + smpPlayer.showVideoInfo(false); + } + } + } + + private function get playlist():String + { + if (Capabilities.manufacturer.indexOf("Android") != -1) + { + return xmlURLAndroid; + } + else if (Capabilities.os.indexOf("iPhone") != -1) + { + return xmlURLiOS; + } + else + { + return xmlURLDesktop; + } + } + + } +} \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/SuperBackButton.as b/lib/osmf/player/StrobeMediaPlaybackAIR/src/SuperBackButton.as new file mode 100644 index 0000000..0c0b098 --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/src/SuperBackButton.as @@ -0,0 +1,51 @@ +package +{ + import flash.display.*; + import flash.events.*; + import flash.text.*; + + public class SuperBackButton extends Sprite + { + + [Embed(source="../assets/images/back.png")] + private var BackGraphic:Class; + + private var _txBack:TextField; + private var _bitmapBack:Bitmap; + + public function SuperBackButton() + { + _bitmapBack = new BackGraphic(); + _bitmapBack.x = 0; + _bitmapBack.y = 0; + addChild(_bitmapBack); + + this.buttonMode = true; + this.useHandCursor = true; + + _txBack = new TextField(); + + _txBack.defaultTextFormat = new TextFormat("PlaybackBlack", 24, 0xffffff); + _txBack.embedFonts = true; + _txBack.antiAliasType = AntiAliasType.ADVANCED; + _txBack.mouseEnabled = false; + _txBack.autoSize= TextFieldAutoSize.LEFT; + _txBack.text = "Home"; + _txBack.x = _bitmapBack.x + _bitmapBack.width; + _txBack.y = (_bitmapBack.height - _txBack.height) / 2; + _txBack.selectable = false; + addChild(_txBack); + + this.addEventListener(MouseEvent.MOUSE_OVER,onMouseOver); + this.addEventListener(MouseEvent.MOUSE_OUT,onMouseOut); + } + + private function onMouseOver(e:MouseEvent):void { + _txBack.setTextFormat(new TextFormat("PlaybackBlack", 24, 0xcccccc, true)); + } + + private function onMouseOut(e:MouseEvent):void { + _txBack.setTextFormat(new TextFormat("PlaybackBlack", 24, 0xffffff, true)); + } + } +} \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackAIR/src/VideoInfo.as b/lib/osmf/player/StrobeMediaPlaybackAIR/src/VideoInfo.as new file mode 100644 index 0000000..a8a9d7f --- /dev/null +++ b/lib/osmf/player/StrobeMediaPlaybackAIR/src/VideoInfo.as @@ -0,0 +1,21 @@ +package +{ + public class VideoInfo + { + public var videoName:String; + public var videoDescription:String; + public var videoThumbnailPath:String; + public var videoPath:String; + public var duration:Number =0; + public var preroll:String; + public var postroll:String; + public var midroll:String; + public var overlay:String; + public var midrollTime:Number; + public var overlayTime:Number; + + public function VideoInfo() + { + } + } +} \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/.actionScriptProperties b/lib/osmf/player/StrobeMediaPlaybackTest/.actionScriptProperties index 4ae8e69..46c85fc 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/.actionScriptProperties +++ b/lib/osmf/player/StrobeMediaPlaybackTest/.actionScriptProperties @@ -1,46 +1,46 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/.flexProperties b/lib/osmf/player/StrobeMediaPlaybackTest/.flexProperties index f207211..0f603b0 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/.flexProperties +++ b/lib/osmf/player/StrobeMediaPlaybackTest/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/StrobeMediaPlaybackTest-build-config.xml b/lib/osmf/player/StrobeMediaPlaybackTest/StrobeMediaPlaybackTest-build-config.xml index 3923977..ce2840e 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/StrobeMediaPlaybackTest-build-config.xml +++ b/lib/osmf/player/StrobeMediaPlaybackTest/StrobeMediaPlaybackTest-build-config.xml @@ -1,37 +1,37 @@ - true - false true - - true - - @@ -42,17 +42,17 @@ CONFIG::FLASH_10_1 true - false - @@ -63,24 +63,24 @@ true - - - ${flexlib}/localFonts.ser @@ -97,34 +97,34 @@ 1000 - - - - - - false @@ -150,28 +150,28 @@ ${flexlib}/locale/{locale} #osmf.swc.path# - ../../testing/NetMockerLibrary/#output.bin#/NetMocker.swc + ../../testing/NetMockerLibrary/#output.bin#/NetMockerLibrary.swc ../StrobeMediaPlayback/assets/assets.swc en_US - false - - - @@ -198,28 +198,28 @@ true - - - - true true - false @@ -314,8 +314,8 @@ false - 0xFFFFFF @@ -332,80 +332,80 @@ 375 - - halo - - - - ${flexlib}/${configname}-config.xml - - unknown - http://www.adobe.com/products/flex EN - - unknown @@ -413,49 +413,49 @@ Adobe Flex 4 Application - true - - - - - - true @@ -464,23 +464,23 @@ 10.2.0 - - - true false - diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTest-app.xml b/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTest-app.xml deleted file mode 100644 index c6183ee..0000000 --- a/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTest-app.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - StrobeMediaPlaybackTest - - - StrobeMediaPlaybackTest - - - StrobeMediaPlaybackTest - - - v1 - - - 1 - - - - - - - - - - - - - - - - [This value will be overwritten by Flash Builder in the output app.xml] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTest.mxml b/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTest.mxml index a1e50cd..4345e49 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTest.mxml +++ b/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTest.mxml @@ -1,34 +1,35 @@ - - - - - - - - - + + + + + + + + + + + + diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTests.as b/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTests.as index 175a1b2..56cabf6 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTests.as +++ b/lib/osmf/player/StrobeMediaPlaybackTest/src/StrobeMediaPlaybackTests.as @@ -19,68 +19,87 @@ package { - import flexunit.framework.Test; - import org.osmf.net.TestPlaybackOptimizationManager; - import org.osmf.net.TestPlaybackOptimizationMetrics; - import org.osmf.player.chrome.hint.TestWidgetHint; - import org.osmf.player.chrome.utils.TestFormatUtils; - import org.osmf.player.chrome.widgets.*; - import org.osmf.player.chrome.widgets.TestTimeViewWidget; - import org.osmf.player.configuration.TestConfigurationLoader; - import org.osmf.player.configuration.TestConfigurationXMLDeserializer; - import org.osmf.player.configuration.TestPlayerConfiguration; - import org.osmf.player.configuration.TestPluginConfiguration; - import org.osmf.player.configuration.TestSkinParser; - import org.osmf.player.elements.TestAlertDialogElement; - import org.osmf.player.elements.TestAuthenticationDialogElement; - import org.osmf.player.elements.TestControlBarElement; - import org.osmf.player.elements.TestPlaylistElement; - import org.osmf.player.errors.TestErrorTranslator; - import org.osmf.player.media.TestStrobeMediaFactory; - import org.osmf.player.media.TestStrobeMediaPlayer; - import org.osmf.player.plugins.TestPluginLoader; - import org.osmf.player.utils.TestVideoRenderingUtils; - - [Suite] - [RunWith("org.flexunit.runners.Suite")] - public class StrobeMediaPlaybackTests - { - public var testPlayerConfiguration:TestPlayerConfiguration; - public var testVideoQualityUtils:TestVideoRenderingUtils; - public var testPluginIntegration:TestPluginConfiguration; - public var testControlBarElement:TestControlBarElement - public var testAlertDialogElement:TestAlertDialogElement; - public var testAuthenticationDialogElement:TestAuthenticationDialogElement; - public var testStrobeMediaPlayback:TestStrobeMediaPlayback; - public var testTimeViewWidget:TestTimeViewWidget; - public var testPluginLoader:TestPluginLoader; - //public var testStrobeMediaPlayer:TestStrobeMediaPlayer; - public var testPlaylistElement:TestPlaylistElement; - //public var testPlaybackOptimizationManager:TestPlaybackOptimizationManager; - // public var testPlaybackOptimizationMetrics:TestPlaybackOptimizationMetrics; - public var testStrobeMediaFactory:TestStrobeMediaFactory; - public var testSkinParser:TestSkinParser; - public var testErrorTranslator:TestErrorTranslator; - public var testConfigurationLoader:TestConfigurationLoader; - - - // ChromeLibrary tests - - public var widgetHint:TestWidgetHint; - public var timeHintWidget:TestTimeHintWidget; - public var volumeWidget:TestVolumeWidget; - public var muteButton:TestMuteButton; - public var testFormatUtils:TestFormatUtils; - public var testPlayButton:TestPlayButton; - public var testPauseButton:TestPauseButton; - public var testAlertDialog:TestAlertDialog; - public var testAuthenticationDialog:TestAuthenticationDialog; - public var testFullScreenEnterButton:TestFullScreenEnterButton; - public var testAutoHideWidget:TestAutoHideWidget; - public var testPlaybuttonOverlay:TestPlayButtonOverlay; - // public var testBufferingOverlay:TestBufferingOverlay; - - public var testConfigurationXMLDeserializer:TestConfigurationXMLDeserializer; - } + import flexunit.framework.Test; + + import org.osmf.player.utils.TestVideoRenderingUtils; + import org.osmf.player.utils.TestStrobeUtils; + import org.osmf.player.plugins.TestPluginWhitelist; + import org.osmf.player.plugins.TestPluginLoader; + import org.osmf.player.media.TestStrobeMediaPlayer; + import org.osmf.player.media.TestStrobeMediaFactory; + import org.osmf.player.errors.TestErrorTranslator; + import org.osmf.player.elements.TestPlaylistElement; + import org.osmf.player.elements.TestControlBarElement; + import org.osmf.player.elements.TestAuthenticationDialogElement; + import org.osmf.player.elements.TestAlertDialogElement; + import org.osmf.player.configuration.TestSkinParser; + import org.osmf.player.configuration.TestPluginConfiguration; + import org.osmf.player.configuration.TestPlayerConfiguration; + import org.osmf.player.configuration.TestConfigurationXMLDeserializer; + import org.osmf.player.configuration.TestConfigurationLoader; + import org.osmf.player.chrome.widgets.TestVolumeWidget; + import org.osmf.player.chrome.widgets.TestTimeViewWidget; + import org.osmf.player.chrome.widgets.TestTimeHintWidget; + import org.osmf.player.chrome.widgets.TestScrubBar; + import org.osmf.player.chrome.widgets.TestPlayButtonOverlay; + import org.osmf.player.chrome.widgets.TestPlayButton; + import org.osmf.player.chrome.widgets.TestPauseButton; + import org.osmf.player.chrome.widgets.TestMuteButton; + import org.osmf.player.chrome.widgets.TestFullScreenEnterButton; + import org.osmf.player.chrome.widgets.TestBufferingOverlay; + import org.osmf.player.chrome.widgets.TestAutoHideWidget; + import org.osmf.player.chrome.widgets.TestAuthenticationDialog; + import org.osmf.player.chrome.widgets.TestAlertDialog; + import org.osmf.player.chrome.utils.TestFormatUtils; + import org.osmf.player.chrome.hint.TestWidgetHint; + import org.osmf.net.TestPlaybackOptimizationMetrics; + import org.osmf.net.TestPlaybackOptimizationManager; + + public class StrobeMediaPlaybackTests + { + public static var testsToRun:Array = new Array(); + + public static function currentRunTestSuite():Array + { + + testsToRun.push(TestStrobeMediaPlayback); + testsToRun.push(org.osmf.net.TestPlaybackOptimizationManager); + testsToRun.push(org.osmf.net.TestPlaybackOptimizationMetrics); + testsToRun.push(org.osmf.player.chrome.hint.TestWidgetHint); + testsToRun.push(org.osmf.player.chrome.utils.TestFormatUtils); + testsToRun.push(org.osmf.player.chrome.widgets.TestAlertDialog); + testsToRun.push(org.osmf.player.chrome.widgets.TestAuthenticationDialog); + testsToRun.push(org.osmf.player.chrome.widgets.TestAutoHideWidget); + testsToRun.push(org.osmf.player.chrome.widgets.TestBufferingOverlay); + testsToRun.push(org.osmf.player.chrome.widgets.TestFullScreenEnterButton); + testsToRun.push(org.osmf.player.chrome.widgets.TestMuteButton); + testsToRun.push(org.osmf.player.chrome.widgets.TestPauseButton); + testsToRun.push(org.osmf.player.chrome.widgets.TestPlayButton); + testsToRun.push(org.osmf.player.chrome.widgets.TestPlayButtonOverlay); + testsToRun.push(org.osmf.player.chrome.widgets.TestScrubBar); + testsToRun.push(org.osmf.player.chrome.widgets.TestTimeHintWidget); + testsToRun.push(org.osmf.player.chrome.widgets.TestTimeViewWidget); + testsToRun.push(org.osmf.player.chrome.widgets.TestVolumeWidget); + testsToRun.push(org.osmf.player.configuration.TestConfigurationLoader); + testsToRun.push(org.osmf.player.configuration.TestConfigurationXMLDeserializer); + testsToRun.push(org.osmf.player.configuration.TestPlayerConfiguration); + testsToRun.push(org.osmf.player.configuration.TestPluginConfiguration); + testsToRun.push(org.osmf.player.configuration.TestSkinParser); + testsToRun.push(org.osmf.player.elements.TestAlertDialogElement); + testsToRun.push(org.osmf.player.elements.TestAuthenticationDialogElement); + testsToRun.push(org.osmf.player.elements.TestControlBarElement); + testsToRun.push(org.osmf.player.elements.TestPlaylistElement); + testsToRun.push(org.osmf.player.errors.TestErrorTranslator); + testsToRun.push(org.osmf.player.media.TestStrobeMediaFactory); + testsToRun.push(org.osmf.player.media.TestStrobeMediaPlayer); + testsToRun.push(org.osmf.player.plugins.TestPluginLoader); + testsToRun.push(org.osmf.player.plugins.TestPluginWhitelist); + testsToRun.push(org.osmf.player.utils.TestStrobeUtils); + testsToRun.push(org.osmf.player.utils.TestVideoRenderingUtils); + + return testsToRun; + + } + } } \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/MockHTTPNetStream.as b/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/MockHTTPNetStream.as index 0287a00..b6eb940 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/MockHTTPNetStream.as +++ b/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/MockHTTPNetStream.as @@ -27,7 +27,6 @@ package org.osmf.net import org.osmf.net.*; import org.osmf.net.httpstreaming.HTTPNetStream; import org.osmf.net.httpstreaming.HTTPStreamingFactory; - import org.osmf.net.httpstreaming.HTTPStreamQoSInfo; import org.osmf.net.httpstreaming.dvr.*; import org.osmf.net.httpstreaming.f4f.*; @@ -53,21 +52,6 @@ package org.osmf.net _dvrInfo = info; } - public function set qosInfo(value:HTTPStreamQoSInfo):void - { - _qosInfo = value; - } - - override public function get qosInfo():HTTPStreamQoSInfo - { - return _qosInfo; - } - - override public function DVRGetStreamInfo(streamName:Object):void - { - this.dispatchEvent(new DVRStreamInfoEvent(DVRStreamInfoEvent.DVRSTREAMINFO, false, false, _dvrInfo)); - } - public function unpublish():void { dispatchEvent @@ -93,6 +77,5 @@ package org.osmf.net private var _infoFactory:MockNetStreamInfoFactory = new MockNetStreamInfoFactory(); private var _time:Number; private var _dvrInfo:DVRInfo; - private var _qosInfo:HTTPStreamQoSInfo; } } \ No newline at end of file diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/TestPlaybackOptimizationManager.as b/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/TestPlaybackOptimizationManager.as index 42fed54..a299305 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/TestPlaybackOptimizationManager.as +++ b/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/TestPlaybackOptimizationManager.as @@ -28,9 +28,13 @@ package org.osmf.net import org.flexunit.asserts.assertEquals; import org.flexunit.asserts.assertTrue; import org.flexunit.async.Async; + import org.osmf.logging.Log; import org.osmf.netmocker.MockNetConnection; import org.osmf.netmocker.MockNetStream; import org.osmf.player.configuration.PlayerConfiguration; + import org.osmf.player.debug.LogHandler; + import org.osmf.player.debug.StrobeLogger; + import org.osmf.player.debug.StrobeLoggerFactory; public class TestPlaybackOptimizationManager { @@ -52,7 +56,11 @@ package org.osmf.net // Ignore this error } - + CONFIG::LOGGING + { + // Setup the custom logging factory + Log.loggerFactory = new StrobeLoggerFactory(new LogHandler(false)); + } } diff --git a/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/TestPlaybackOptimizationMetrics.as b/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/TestPlaybackOptimizationMetrics.as index c7ca400..5ac9fd8 100644 --- a/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/TestPlaybackOptimizationMetrics.as +++ b/lib/osmf/player/StrobeMediaPlaybackTest/src/org/osmf/net/TestPlaybackOptimizationMetrics.as @@ -124,7 +124,6 @@ package org.osmf.net var playbackOptimizationMetrics:PlaybackOptimizationMetrics = new PlaybackOptimizationMetrics(netStream); playbackOptimizationMetrics.averagePlaybackBytesPerSecond = 500; - netStream.qosInfo = new MockHTTPStreamQoSInfo(2); netStream.infoFactory.videoBufferByteLength = 2000; netStream.infoFactory.videoBufferLength = 1; diff --git a/lib/osmf/player/preloader/.actionScriptProperties b/lib/osmf/player/preloader/.actionScriptProperties index f4966e2..ba2b01e 100644 --- a/lib/osmf/player/preloader/.actionScriptProperties +++ b/lib/osmf/player/preloader/.actionScriptProperties @@ -1,40 +1,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/player/preloader/Preloader-build-config.xml b/lib/osmf/player/preloader/Preloader-build-config.xml index 0e70f94..f502c4c 100644 --- a/lib/osmf/player/preloader/Preloader-build-config.xml +++ b/lib/osmf/player/preloader/Preloader-build-config.xml @@ -24,8 +24,8 @@ - @@ -39,10 +39,10 @@ false - @@ -61,15 +61,15 @@ - library://ns.adobe.com/flex/mx @@ -126,11 +126,11 @@ - @@ -142,8 +142,8 @@ - @@ -162,13 +162,13 @@ - @@ -178,12 +178,12 @@ flash.fonts.BatikFontManager - @@ -303,29 +303,29 @@ - - - true - - diff --git a/lib/osmf/samples/AdobePassPlugin/.actionScriptProperties b/lib/osmf/samples/AdobePassPlugin/.actionScriptProperties index aea4141..50582a5 100644 --- a/lib/osmf/samples/AdobePassPlugin/.actionScriptProperties +++ b/lib/osmf/samples/AdobePassPlugin/.actionScriptProperties @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/AdobePassPlugin/src/AdobePassPlugin.as b/lib/osmf/samples/AdobePassPlugin/src/AdobePassPlugin.as index 8b99c11..41a2365 100644 --- a/lib/osmf/samples/AdobePassPlugin/src/AdobePassPlugin.as +++ b/lib/osmf/samples/AdobePassPlugin/src/AdobePassPlugin.as @@ -1,42 +1,42 @@ -package -{ - import org.osmf.adobepass.AdobePassPluginInfo; - - import flash.display.Sprite; - import flash.system.Security; - - import org.osmf.media.PluginInfo; - - /** - * The root level object of the AdobePassPlugin. - * - * @langversion 3.0 - * @playerversion Flash 10 - */ - public class AdobePassPlugin extends Sprite - { - /** - * Constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - */ - public function AdobePassPlugin() - { - _pluginInfo = new AdobePassPluginInfo(); - } - - /** - * Gives the player the object which implements the OSMF IPluginInfo interface. - * - * @langversion 3.0 - * @playerversion Flash 10 - */ - public function get pluginInfo():PluginInfo - { - return _pluginInfo; - } - - private var _pluginInfo:PluginInfo; - } -} +package +{ + import org.osmf.adobepass.AdobePassPluginInfo; + + import flash.display.Sprite; + import flash.system.Security; + + import org.osmf.media.PluginInfo; + + /** + * The root level object of the AdobePassPlugin. + * + * @langversion 3.0 + * @playerversion Flash 10 + */ + public class AdobePassPlugin extends Sprite + { + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + */ + public function AdobePassPlugin() + { + _pluginInfo = new AdobePassPluginInfo(); + } + + /** + * Gives the player the object which implements the OSMF IPluginInfo interface. + * + * @langversion 3.0 + * @playerversion Flash 10 + */ + public function get pluginInfo():PluginInfo + { + return _pluginInfo; + } + + private var _pluginInfo:PluginInfo; + } +} diff --git a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/AdobePassPluginInfo.as b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/AdobePassPluginInfo.as index 17edb3f..9337bfd 100644 --- a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/AdobePassPluginInfo.as +++ b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/AdobePassPluginInfo.as @@ -1,43 +1,43 @@ -package org.osmf.adobepass -{ - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.MediaFactoryItemType; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.PluginInfo; - import org.osmf.metadata.Metadata; - import org.osmf.net.NetLoader; - import org.osmf.adobepass.media.AdobePassProxyElement; - - public class AdobePassPluginInfo extends PluginInfo - { - private var mediaInfos:Vector.; - private var pluginMetadata:Object; - - public function AdobePassPluginInfo() - { - mediaInfos = new Vector.; - var mediaInfo:MediaFactoryItem = new MediaFactoryItem - ( "com.adobe.adobepass.AdobePassPluginInfo" - , new NetLoader().canHandleResource - , createTVEProxyElement - , MediaFactoryItemType.PROXY - ); - mediaInfos.push(mediaInfo); - - super(mediaInfos); - } - - override public function initializePlugin(resource:MediaResourceBase):void - { - pluginMetadata = resource.getMetadataValue(ADOBEPASS_PLUGIN_NAMESPACE); - } - - private function createTVEProxyElement():MediaElement - { - return new AdobePassProxyElement(null, pluginMetadata); - } - - public static var ADOBEPASS_PLUGIN_NAMESPACE:String = "http://www.adobe.com/products/adobepass/"; - } -} +package org.osmf.adobepass +{ + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.MediaFactoryItemType; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.PluginInfo; + import org.osmf.metadata.Metadata; + import org.osmf.net.NetLoader; + import org.osmf.adobepass.media.AdobePassProxyElement; + + public class AdobePassPluginInfo extends PluginInfo + { + private var mediaInfos:Vector.; + private var pluginMetadata:Object; + + public function AdobePassPluginInfo() + { + mediaInfos = new Vector.; + var mediaInfo:MediaFactoryItem = new MediaFactoryItem + ( "com.adobe.adobepass.AdobePassPluginInfo" + , new NetLoader().canHandleResource + , createTVEProxyElement + , MediaFactoryItemType.PROXY + ); + mediaInfos.push(mediaInfo); + + super(mediaInfos); + } + + override public function initializePlugin(resource:MediaResourceBase):void + { + pluginMetadata = resource.getMetadataValue(ADOBEPASS_PLUGIN_NAMESPACE); + } + + private function createTVEProxyElement():MediaElement + { + return new AdobePassProxyElement(null, pluginMetadata); + } + + public static var ADOBEPASS_PLUGIN_NAMESPACE:String = "http://www.adobe.com/products/adobepass/"; + } +} diff --git a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/entitlement/AccessEnablerHelper.as b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/entitlement/AccessEnablerHelper.as index 3f0ca26..ea6448a 100644 --- a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/entitlement/AccessEnablerHelper.as +++ b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/entitlement/AccessEnablerHelper.as @@ -1,391 +1,391 @@ -package org.osmf.adobepass.entitlement -{ - import flash.display.Loader; - import flash.display.Sprite; - import flash.display.Stage; - import flash.events.Event; - import flash.events.IOErrorEvent; - import flash.events.SecurityErrorEvent; - import flash.events.StatusEvent; - import flash.external.ExternalInterface; - import flash.geom.Point; - import flash.net.LocalConnection; - import flash.net.URLRequest; - import flash.system.ApplicationDomain; - import flash.system.LoaderContext; - import flash.system.Security; - import flash.system.SecurityDomain; - - import org.osmf.adobepass.events.AuthenticationEvent; - import org.osmf.adobepass.events.TokenEvent; - import org.osmf.adobepass.events.TrackingEvent; +package org.osmf.adobepass.entitlement +{ + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.Stage; + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.SecurityErrorEvent; + import flash.events.StatusEvent; + import flash.external.ExternalInterface; + import flash.geom.Point; + import flash.net.LocalConnection; + import flash.net.URLRequest; + import flash.system.ApplicationDomain; + import flash.system.LoaderContext; + import flash.system.Security; + import flash.system.SecurityDomain; + + import org.osmf.adobepass.events.AuthenticationEvent; + import org.osmf.adobepass.events.TokenEvent; + import org.osmf.adobepass.events.TrackingEvent; import org.osmf.utils.URL; - - /** - * This is a helper class that loads access enabler and - * and exercises the entitlement API over localconnection. - * - * The singleton pattern is used in order to support OSMF - * players that can play compositions. In this event we do not want - * to load the AccessEnabler for each MediaElement instance. - */ - public class AccessEnablerHelper extends Sprite - { - public static var instance:AccessEnablerHelper; - private var providerDialogURL:String; - - public static function getInstance(settings:Object = null):AccessEnablerHelper - { - if (instance == null) - { - instance = new AccessEnablerHelper(settings, new SingletonEnforcer()); - - } - return instance; - } - - public function AccessEnablerHelper(settings:Object, enforcer:SingletonEnforcer) - { - if (settings != null) - { - if (settings.size != null && settings.size is Point) - { - accessSwfMaxSize = settings.size; - } - - if (settings.accessEnablerURL != null) - { - accessEnablerURL = settings.accessEnablerURL; - } - - // Allow the access swf such that the Selection dialog can be displayed. - Security.allowDomain(accessEnablerURL); - Security.allowInsecureDomain(accessEnablerURL); - - if (settings.requestorID != null) - { - requestorID = settings.requestorID; - } - - if (settings.resourceID != null) - { - resourceID = settings.resourceID; - } - - if (settings.parent != null) - { - settings.parent.addChild(this); - } - - if (settings.externalCreateIFrame != null) - { - useExternalCreateIframe = (settings.externalCreateIFrame == "true"); - } - - if (settings.providerDialogURL != null - && settings.providerDialogURL.substr(settings.providerDialogURL.length - 4) == ".swf") - { - providerDialogURL = settings.providerDialogURL; - } - - } - - var u:URL = new URL(accessEnablerURL); - accessEnablerDomain = u.host; - - } - - /** - * This function triggers the entitlement workflow needed - * to get authorization for a resource - * - * Will load the access enabler if needed and setup the localconection communication - * - */ - public function checkAccess():void - { - if (uniqueName == null && !accessSwfLoaded) - { - var currentTime:Number = new Date().time; - uniqueName = currentTime.toString(); - callbackID += uniqueName; - listenerID += uniqueName; - - /* The tve access swf makes callbacks into the parent swf. Hence, enable SWF to swf access in a - cross-domain scenario. The code below allows opening a connection that will permit access swf - to invoke it. */ - try - { - conn = new LocalConnection(); - conn.addEventListener(StatusEvent.STATUS, onConnStatus); - conn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onReceivedError); - conn.client = this; - conn.allowDomain(accessEnablerDomain); - conn.connect(callbackID); - trace("[AccessEnablerProxy] listening on " + callbackID + "(" + accessEnablerDomain + ")"); - } - catch(e:Error) - { - trace("[AccessEnablerProxy] error opening localconnection: ", e.getStackTrace()); - } - - /* Load the access swf */ - if ((conn != null)) - { - trace("[AccessEnablerProxy] - loading entitlement swf..."); - accessSwfLoader = new Loader(); - var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain); - accessSwfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete); - accessSwfLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIOError); - accessSwfLoader.load(new URLRequest(accessEnablerURL + "?uniquename=" + uniqueName), context); - } - } - else - { - trace("[AccessEnablerProxy] - entitlement swf already loaded"); - getAuthorization(); - } - } - - private function onConnStatus(event:StatusEvent):void - {} - - private function onReceivedError(event:SecurityErrorEvent):void - {} - - /** - * After loading the access enabler, add it to the stage - * and center it. - * - * @param event - */ - private function onLoadComplete(event:Event):void - { - try - { - if (accessSwfLoaded) - { - resizeAccessSwf(); - } - addChild(accessSwfLoader); - } - catch (e:Error) - { - trace("[AccessEnablerProxy] - INVALID PARENT! Access Enabler would not be able to display it's GUI"); - trace(e.getStackTrace()); - } - dispatchEvent(event.clone()); - } - - private function onIOError(event:IOErrorEvent):void - { - trace("[AccessEnablerProxy] - ERROR LOADING ENABLEMENT SWF"); - } - - /** - * This will try to center the AccessEnabler on the stage - */ - private function resizeAccessSwf():void - { - // if the accessSwfSize is set this will center the ProviderDialog - accessSwfSize = new Point(accessSwfLoader.contentLoaderInfo.width, accessSwfLoader.contentLoaderInfo.height); - if ((accessSwfMaxSize.x > accessSwfSize.x) && (accessSwfMaxSize.y > accessSwfSize.y)) - { - accessSwfLoader.x = (accessSwfMaxSize.x - accessSwfSize.x) / 2; - accessSwfLoader.y = (accessSwfMaxSize.y - accessSwfSize.y) / 2; - } - } - - /** - * Invokes getAuthorization for a given resource. - * - * @private - */ - private function getAuthorization():void - { - try - { - conn.send(listenerID, "getAuthorization", resourceID); - trace("[AccessEnablerProxy] - getAuth sent"); - } - catch(e:Error) - {} - } - - /** - * Invokes setRequestor() and previously sets a - * custom provider dialog url if needed - * - */ - private function registerClient():void - { - try - { - if (providerDialogURL) - { - conn.send(listenerID, "setProviderDialogURL", providerDialogURL); - } - conn.send(listenerID, "setRequestor", requestorID); - trace("[AccessEnablerProxy] registerclient sent"); - } - catch(e:Error) - { - trace("[AccessEnablerProxy] registerclient error: " + e.getStackTrace()); - } - } - - /** - * Callback invoked by access swf to indicate it can receive API calls - * - * when receiving this we will try to call - * setRequestor() and getAuthorization() - * - */ - public function swfLoaded():void - { - trace("[AccessEnablerProxy] swfLoaded()"); - if (!accessSwfLoaded) - { - registerClient(); - } - getAuthorization(); - accessSwfLoaded = true; - } - - /** - * Callback invoked by access swf indicating the desired dimensions of the swf. - * - * We simply center the swf on stage when receiving it - * - * @param width - * @param height - */ - public function setMovieDimensions(width:int, height:int):void - { - resizeAccessSwf(); - } - - /** - * Callback invoked by access swf to indicate - * a token failure - * - * @param resourceID The original resource id for the requested token - * @param errorCode error code - * - */ - public function tokenRequestFailed(resourceID:String, errorCode:String, k:*):void - { - dispatchEvent(new TokenEvent(TokenEvent.TOKEN_REQUEST_FAILED)); - } - - /** - * Callback invoked by access swf to indicate - * a token aquisition success - * - * @param String resourceID the original resource id for the requested token - * @param String The token representation - * - */ - public function setToken(resourceID:String, token:String):void - { - dispatchEvent(new TokenEvent(TokenEvent.TOKEN_REQUEST_SUCCESS, token)); - } - - /** - * Callback invoked by access swf to indicate - * authentication status - * - * @param String authentication status - * @param String error code - * - */ - public function setAuthenticationStatus(authenticated:uint, errorCode:String):void - { - trace("[AccessEnablerProxy] setauthenticationstatus: " + authenticated + "," + errorCode); - - dispatchEvent( - new AuthenticationEvent( - authenticated == 1 ? AuthenticationEvent.AUTHN_SUCCESS : AuthenticationEvent.AUTHN_FAILED - , errorCode - )); - } - - /** - * Callback invoked by access swf to indicate - * that "mvpdframe" iframe needs to be displayed - * - * @param String the requested width - * @param String the requested height - * - */ - public function createIFrame(width:uint, height:uint):void - { - if (useExternalCreateIframe) - { - ExternalInterface.call("createIFrame", width, height); - } - else - { - var jsCode:String = CREATE_IFRAME_CODE - .replace("{w}", width) - .replace("{h}", height) - .replace("{whalf}", width / 2); - ExternalInterface.call("eval", jsCode); - } - } - - public function sendTrackingData(type:String, data:Array):void - { - trace(type, data); - dispatchEvent(new TrackingEvent(TrackingEvent.TRACKING, false, false, type, data)); - } - - /** - * LocalConnection object that opens invocations into this swf by cross domain swfs. - * Used by tve access swf to make callbacks. - */ - private var conn:LocalConnection; - - /** The loader object used to load tve access swf. */ - private var accessSwfLoader:Loader = null; - - /** The domain that hosts the tve access swf. */ - private var accessEnablerDomain:String; - - /** The default URL that serves the tve access swf */ - private var accessEnablerURL:String = "http://entitlement.auth.adobe.com/entitlement/AccessEnabler.swf"; - - /** Connection name used to make calls to tve access swf. */ - private var listenerID:String = "_accessEnabler"; - - /** Connection name for client's LocalConnection. This name will be used by tve - access swf to make callbacks into client swf. */ - private var callbackID:String = "_accessEnablerClient"; - - private var resourceID:String; - private var requestorID:String; - - private var uniqueName:String = null; - private var accessSwfLoaded:Boolean = false; - private var accessSwfMaxSize:Point = new Point(0, 0); - private var accessSwfSize:Point = new Point(0, 0); - private var useExternalCreateIframe:Boolean; - - private static const CREATE_IFRAME_CODE:String - = "ifrm = document.getElementById('mvpdframe');" + - "ifrm.style.width=\"{w}px\";" + - "ifrm.style.height=\"{h}px\";" + - "ifrm.style.frameborder=\"2\";" + - "ifrm.style.border=\"1\";" + - "ifrm.style.position=\"absolute\";" + - "ifrm.style.top=\"50px\";" + - "ifrm.style.left=\"50%\";" + - // "ifrm.style.zIndex=\"300\";" + - "ifrm.style.marginLeft=\"-{whalf}px\";" + - "ifrm.style.display=\"block\";"; - } -} - -internal class SingletonEnforcer -{ -} + + /** + * This is a helper class that loads access enabler and + * and exercises the entitlement API over localconnection. + * + * The singleton pattern is used in order to support OSMF + * players that can play compositions. In this event we do not want + * to load the AccessEnabler for each MediaElement instance. + */ + public class AccessEnablerHelper extends Sprite + { + public static var instance:AccessEnablerHelper; + private var providerDialogURL:String; + + public static function getInstance(settings:Object = null):AccessEnablerHelper + { + if (instance == null) + { + instance = new AccessEnablerHelper(settings, new SingletonEnforcer()); + + } + return instance; + } + + public function AccessEnablerHelper(settings:Object, enforcer:SingletonEnforcer) + { + if (settings != null) + { + if (settings.size != null && settings.size is Point) + { + accessSwfMaxSize = settings.size; + } + + if (settings.accessEnablerURL != null) + { + accessEnablerURL = settings.accessEnablerURL; + } + + // Allow the access swf such that the Selection dialog can be displayed. + Security.allowDomain(accessEnablerURL); + Security.allowInsecureDomain(accessEnablerURL); + + if (settings.requestorID != null) + { + requestorID = settings.requestorID; + } + + if (settings.resourceID != null) + { + resourceID = settings.resourceID; + } + + if (settings.parent != null) + { + settings.parent.addChild(this); + } + + if (settings.externalCreateIFrame != null) + { + useExternalCreateIframe = (settings.externalCreateIFrame == "true"); + } + + if (settings.providerDialogURL != null + && settings.providerDialogURL.substr(settings.providerDialogURL.length - 4) == ".swf") + { + providerDialogURL = settings.providerDialogURL; + } + + } + + var u:URL = new URL(accessEnablerURL); + accessEnablerDomain = u.host; + + } + + /** + * This function triggers the entitlement workflow needed + * to get authorization for a resource + * + * Will load the access enabler if needed and setup the localconection communication + * + */ + public function checkAccess():void + { + if (uniqueName == null && !accessSwfLoaded) + { + var currentTime:Number = new Date().time; + uniqueName = currentTime.toString(); + callbackID += uniqueName; + listenerID += uniqueName; + + /* The tve access swf makes callbacks into the parent swf. Hence, enable SWF to swf access in a + cross-domain scenario. The code below allows opening a connection that will permit access swf + to invoke it. */ + try + { + conn = new LocalConnection(); + conn.addEventListener(StatusEvent.STATUS, onConnStatus); + conn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onReceivedError); + conn.client = this; + conn.allowDomain(accessEnablerDomain); + conn.connect(callbackID); + trace("[AccessEnablerProxy] listening on " + callbackID + "(" + accessEnablerDomain + ")"); + } + catch(e:Error) + { + trace("[AccessEnablerProxy] error opening localconnection: ", e.getStackTrace()); + } + + /* Load the access swf */ + if ((conn != null)) + { + trace("[AccessEnablerProxy] - loading entitlement swf..."); + accessSwfLoader = new Loader(); + var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain); + accessSwfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete); + accessSwfLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIOError); + accessSwfLoader.load(new URLRequest(accessEnablerURL + "?uniquename=" + uniqueName), context); + } + } + else + { + trace("[AccessEnablerProxy] - entitlement swf already loaded"); + getAuthorization(); + } + } + + private function onConnStatus(event:StatusEvent):void + {} + + private function onReceivedError(event:SecurityErrorEvent):void + {} + + /** + * After loading the access enabler, add it to the stage + * and center it. + * + * @param event + */ + private function onLoadComplete(event:Event):void + { + try + { + if (accessSwfLoaded) + { + resizeAccessSwf(); + } + addChild(accessSwfLoader); + } + catch (e:Error) + { + trace("[AccessEnablerProxy] - INVALID PARENT! Access Enabler would not be able to display it's GUI"); + trace(e.getStackTrace()); + } + dispatchEvent(event.clone()); + } + + private function onIOError(event:IOErrorEvent):void + { + trace("[AccessEnablerProxy] - ERROR LOADING ENABLEMENT SWF"); + } + + /** + * This will try to center the AccessEnabler on the stage + */ + private function resizeAccessSwf():void + { + // if the accessSwfSize is set this will center the ProviderDialog + accessSwfSize = new Point(accessSwfLoader.contentLoaderInfo.width, accessSwfLoader.contentLoaderInfo.height); + if ((accessSwfMaxSize.x > accessSwfSize.x) && (accessSwfMaxSize.y > accessSwfSize.y)) + { + accessSwfLoader.x = (accessSwfMaxSize.x - accessSwfSize.x) / 2; + accessSwfLoader.y = (accessSwfMaxSize.y - accessSwfSize.y) / 2; + } + } + + /** + * Invokes getAuthorization for a given resource. + * + * @private + */ + private function getAuthorization():void + { + try + { + conn.send(listenerID, "getAuthorization", resourceID); + trace("[AccessEnablerProxy] - getAuth sent"); + } + catch(e:Error) + {} + } + + /** + * Invokes setRequestor() and previously sets a + * custom provider dialog url if needed + * + */ + private function registerClient():void + { + try + { + if (providerDialogURL) + { + conn.send(listenerID, "setProviderDialogURL", providerDialogURL); + } + conn.send(listenerID, "setRequestor", requestorID); + trace("[AccessEnablerProxy] registerclient sent"); + } + catch(e:Error) + { + trace("[AccessEnablerProxy] registerclient error: " + e.getStackTrace()); + } + } + + /** + * Callback invoked by access swf to indicate it can receive API calls + * + * when receiving this we will try to call + * setRequestor() and getAuthorization() + * + */ + public function swfLoaded():void + { + trace("[AccessEnablerProxy] swfLoaded()"); + if (!accessSwfLoaded) + { + registerClient(); + } + getAuthorization(); + accessSwfLoaded = true; + } + + /** + * Callback invoked by access swf indicating the desired dimensions of the swf. + * + * We simply center the swf on stage when receiving it + * + * @param width + * @param height + */ + public function setMovieDimensions(width:int, height:int):void + { + resizeAccessSwf(); + } + + /** + * Callback invoked by access swf to indicate + * a token failure + * + * @param resourceID The original resource id for the requested token + * @param errorCode error code + * + */ + public function tokenRequestFailed(resourceID:String, errorCode:String, k:*):void + { + dispatchEvent(new TokenEvent(TokenEvent.TOKEN_REQUEST_FAILED)); + } + + /** + * Callback invoked by access swf to indicate + * a token aquisition success + * + * @param String resourceID the original resource id for the requested token + * @param String The token representation + * + */ + public function setToken(resourceID:String, token:String):void + { + dispatchEvent(new TokenEvent(TokenEvent.TOKEN_REQUEST_SUCCESS, token)); + } + + /** + * Callback invoked by access swf to indicate + * authentication status + * + * @param String authentication status + * @param String error code + * + */ + public function setAuthenticationStatus(authenticated:uint, errorCode:String):void + { + trace("[AccessEnablerProxy] setauthenticationstatus: " + authenticated + "," + errorCode); + + dispatchEvent( + new AuthenticationEvent( + authenticated == 1 ? AuthenticationEvent.AUTHN_SUCCESS : AuthenticationEvent.AUTHN_FAILED + , errorCode + )); + } + + /** + * Callback invoked by access swf to indicate + * that "mvpdframe" iframe needs to be displayed + * + * @param String the requested width + * @param String the requested height + * + */ + public function createIFrame(width:uint, height:uint):void + { + if (useExternalCreateIframe) + { + ExternalInterface.call("createIFrame", width, height); + } + else + { + var jsCode:String = CREATE_IFRAME_CODE + .replace("{w}", width) + .replace("{h}", height) + .replace("{whalf}", width / 2); + ExternalInterface.call("eval", jsCode); + } + } + + public function sendTrackingData(type:String, data:Array):void + { + trace(type, data); + dispatchEvent(new TrackingEvent(TrackingEvent.TRACKING, false, false, type, data)); + } + + /** + * LocalConnection object that opens invocations into this swf by cross domain swfs. + * Used by tve access swf to make callbacks. + */ + private var conn:LocalConnection; + + /** The loader object used to load tve access swf. */ + private var accessSwfLoader:Loader = null; + + /** The domain that hosts the tve access swf. */ + private var accessEnablerDomain:String; + + /** The default URL that serves the tve access swf */ + private var accessEnablerURL:String = "http://entitlement.auth.adobe.com/entitlement/AccessEnabler.swf"; + + /** Connection name used to make calls to tve access swf. */ + private var listenerID:String = "_accessEnabler"; + + /** Connection name for client's LocalConnection. This name will be used by tve + access swf to make callbacks into client swf. */ + private var callbackID:String = "_accessEnablerClient"; + + private var resourceID:String; + private var requestorID:String; + + private var uniqueName:String = null; + private var accessSwfLoaded:Boolean = false; + private var accessSwfMaxSize:Point = new Point(0, 0); + private var accessSwfSize:Point = new Point(0, 0); + private var useExternalCreateIframe:Boolean; + + private static const CREATE_IFRAME_CODE:String + = "ifrm = document.getElementById('mvpdframe');" + + "ifrm.style.width=\"{w}px\";" + + "ifrm.style.height=\"{h}px\";" + + "ifrm.style.frameborder=\"2\";" + + "ifrm.style.border=\"1\";" + + "ifrm.style.position=\"absolute\";" + + "ifrm.style.top=\"50px\";" + + "ifrm.style.left=\"50%\";" + + // "ifrm.style.zIndex=\"300\";" + + "ifrm.style.marginLeft=\"-{whalf}px\";" + + "ifrm.style.display=\"block\";"; + } +} + +internal class SingletonEnforcer +{ +} diff --git a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/events/AuthenticationEvent.as b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/events/AuthenticationEvent.as index d65df0d..da857b7 100644 --- a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/events/AuthenticationEvent.as +++ b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/events/AuthenticationEvent.as @@ -1,32 +1,32 @@ -package org.osmf.adobepass.events -{ - import flash.events.Event; - - /** - * This event is dispatched on Authentication state changes. - */ - public class AuthenticationEvent extends Event - { - public static const AUTHN_SUCCESS:String = "authnSuccess"; - public static const AUTHN_FAILED:String = "authnFailed"; - - public function AuthenticationEvent(type:String, errorCode:String=null, bubbles:Boolean=false, cancelable:Boolean=false) - { - super(type, bubbles, cancelable); - _errorCode = errorCode; - } - - override public function clone():Event - { - return new AuthenticationEvent(type, errorCode, bubbles, cancelable); - } - - public function get errorCode():String - { - return _errorCode; - } - - private var _errorCode:String; - - } +package org.osmf.adobepass.events +{ + import flash.events.Event; + + /** + * This event is dispatched on Authentication state changes. + */ + public class AuthenticationEvent extends Event + { + public static const AUTHN_SUCCESS:String = "authnSuccess"; + public static const AUTHN_FAILED:String = "authnFailed"; + + public function AuthenticationEvent(type:String, errorCode:String=null, bubbles:Boolean=false, cancelable:Boolean=false) + { + super(type, bubbles, cancelable); + _errorCode = errorCode; + } + + override public function clone():Event + { + return new AuthenticationEvent(type, errorCode, bubbles, cancelable); + } + + public function get errorCode():String + { + return _errorCode; + } + + private var _errorCode:String; + + } } \ No newline at end of file diff --git a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/events/TokenEvent.as b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/events/TokenEvent.as index c225cdb..5d1ea94 100644 --- a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/events/TokenEvent.as +++ b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/events/TokenEvent.as @@ -1,32 +1,32 @@ -package org.osmf.adobepass.events -{ - import flash.events.Event; - - /** - * This event is dispatched on token request state changes. - */ - public class TokenEvent extends Event - { - public static const TOKEN_REQUEST_FAILED:String = "tokenRequestFailed"; - public static const TOKEN_REQUEST_SUCCESS:String = "tokenRequestSuccess"; - - public function TokenEvent(type:String, token:String=null, bubbles:Boolean=false, cancelable:Boolean=false) - { - super(type, bubbles, cancelable); - _token = token; - } - - override public function clone():Event - { - return new TokenEvent(type, token, bubbles, cancelable); - } - - public function get token():String - { - return _token; - } - - private var _token:String; - - } +package org.osmf.adobepass.events +{ + import flash.events.Event; + + /** + * This event is dispatched on token request state changes. + */ + public class TokenEvent extends Event + { + public static const TOKEN_REQUEST_FAILED:String = "tokenRequestFailed"; + public static const TOKEN_REQUEST_SUCCESS:String = "tokenRequestSuccess"; + + public function TokenEvent(type:String, token:String=null, bubbles:Boolean=false, cancelable:Boolean=false) + { + super(type, bubbles, cancelable); + _token = token; + } + + override public function clone():Event + { + return new TokenEvent(type, token, bubbles, cancelable); + } + + public function get token():String + { + return _token; + } + + private var _token:String; + + } } \ No newline at end of file diff --git a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/media/AdobePassProxyElement.as b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/media/AdobePassProxyElement.as index 6bb0b3d..3aaa9f0 100644 --- a/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/media/AdobePassProxyElement.as +++ b/lib/osmf/samples/AdobePassPlugin/src/org/osmf/adobepass/media/AdobePassProxyElement.as @@ -1,125 +1,125 @@ -package org.osmf.adobepass.media -{ - import flash.display.DisplayObject; - import flash.display.DisplayObjectContainer; - import flash.display.Sprite; - import flash.display.Stage; - import flash.events.Event; - import flash.geom.Point; - - import org.osmf.adobepass.entitlement.AccessEnablerHelper; - import org.osmf.adobepass.events.TokenEvent; - import org.osmf.adobepass.events.TrackingEvent; - import org.osmf.elements.ProxyElement; - import org.osmf.events.MediaElementEvent; - import org.osmf.media.MediaElement; - import org.osmf.metadata.Metadata; - import org.osmf.traits.DisplayObjectTrait; +package org.osmf.adobepass.media +{ + import flash.display.DisplayObject; + import flash.display.DisplayObjectContainer; + import flash.display.Sprite; + import flash.display.Stage; + import flash.events.Event; + import flash.geom.Point; + + import org.osmf.adobepass.entitlement.AccessEnablerHelper; + import org.osmf.adobepass.events.TokenEvent; + import org.osmf.adobepass.events.TrackingEvent; + import org.osmf.elements.ProxyElement; + import org.osmf.events.MediaElementEvent; + import org.osmf.media.MediaElement; + import org.osmf.metadata.Metadata; + import org.osmf.traits.DisplayObjectTrait; import org.osmf.traits.MediaTraitType; - - /** - * The AdobePassProxyElement class is a wrapper for the media supplied. - * It's purpose is to block the play trait to - * allow the processing of TVE Entitlement - */ - public class AdobePassProxyElement extends ProxyElement - { - private var settings:Object; - - public function AdobePassProxyElement(proxied:MediaElement, settings:Object) - { - super(proxied); - - this.settings = settings; - blockedTraits.push(MediaTraitType.PLAY); - - // If no parent is set, assume that the parrent is the display trait - if (hasTrait(MediaTraitType.DISPLAY_OBJECT) || settings.parent) - { - initTVE(); - } - else - { - // No display trait available yet, wait for one - addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - } - - private function onTraitAdd(event:MediaElementEvent):void - { - if (event.traitType == MediaTraitType.DISPLAY_OBJECT) - { - // Found a display trait - removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - initTVE(); - } - } - - private function initTVE():void - { - var displayable:DisplayObject - = (getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait).displayObject; - - if (displayable.stage) - { - completeInitTVE(displayable.stage); - } - else - { - // stage not available yet for current display trait - displayable.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); - } - } - - private function onAddedToStage(event:Event):void - { - // stage is available now, proceed with tve workflows - event.target.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); - completeInitTVE((event.target as DisplayObject).stage); - } - - private function completeInitTVE(stage:Stage):void - { - settings.parent = stage; - settings.size = new Point(stage.stageWidth, stage.stageHeight); - - _accessEnabler = AccessEnablerHelper.getInstance(settings); - - // Listen for authentication results - _accessEnabler.addEventListener(TokenEvent.TOKEN_REQUEST_FAILED, onTokenFailed); - _accessEnabler.addEventListener(TokenEvent.TOKEN_REQUEST_SUCCESS, onTokenSuccess); - _accessEnabler.addEventListener(TrackingEvent.TRACKING, onTracking); - - // Start tve entitlement - _accessEnabler.checkAccess(); - } - - private function onTracking(event:TrackingEvent):void - { - var trackingMetadata:Metadata = new Metadata(); - trackingMetadata.addValue("type", event.trackingType); - trackingMetadata.addValue("data", event.data); - trackingMetadata.addValue("adobePass", event.trackingType + ":" + event.data.join()); - - addMetadata("http://www.adobe.com/products/adobepass", trackingMetadata); - resource.addMetadataValue("http://www.adobe.com/products/adobepass", trackingMetadata); - } - - private function onTokenFailed(event:TokenEvent):void - { - dispatchEvent(event.clone()); - } - - private function onTokenSuccess(event:TokenEvent):void - { - // Unblock the play trait - var playTraitIndex:int = blockedTraits.indexOf(MediaTraitType.PLAY); - blockedTraits = blockedTraits.slice(playTraitIndex, playTraitIndex); - - dispatchEvent(event.clone()); - } - - private var _accessEnabler:AccessEnablerHelper; - - } + + /** + * The AdobePassProxyElement class is a wrapper for the media supplied. + * It's purpose is to block the play trait to + * allow the processing of TVE Entitlement + */ + public class AdobePassProxyElement extends ProxyElement + { + private var settings:Object; + + public function AdobePassProxyElement(proxied:MediaElement, settings:Object) + { + super(proxied); + + this.settings = settings; + blockedTraits.push(MediaTraitType.PLAY); + + // If no parent is set, assume that the parrent is the display trait + if (hasTrait(MediaTraitType.DISPLAY_OBJECT) || settings.parent) + { + initTVE(); + } + else + { + // No display trait available yet, wait for one + addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + } + + private function onTraitAdd(event:MediaElementEvent):void + { + if (event.traitType == MediaTraitType.DISPLAY_OBJECT) + { + // Found a display trait + removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + initTVE(); + } + } + + private function initTVE():void + { + var displayable:DisplayObject + = (getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait).displayObject; + + if (displayable.stage) + { + completeInitTVE(displayable.stage); + } + else + { + // stage not available yet for current display trait + displayable.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); + } + } + + private function onAddedToStage(event:Event):void + { + // stage is available now, proceed with tve workflows + event.target.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); + completeInitTVE((event.target as DisplayObject).stage); + } + + private function completeInitTVE(stage:Stage):void + { + settings.parent = stage; + settings.size = new Point(stage.stageWidth, stage.stageHeight); + + _accessEnabler = AccessEnablerHelper.getInstance(settings); + + // Listen for authentication results + _accessEnabler.addEventListener(TokenEvent.TOKEN_REQUEST_FAILED, onTokenFailed); + _accessEnabler.addEventListener(TokenEvent.TOKEN_REQUEST_SUCCESS, onTokenSuccess); + _accessEnabler.addEventListener(TrackingEvent.TRACKING, onTracking); + + // Start tve entitlement + _accessEnabler.checkAccess(); + } + + private function onTracking(event:TrackingEvent):void + { + var trackingMetadata:Metadata = new Metadata(); + trackingMetadata.addValue("type", event.trackingType); + trackingMetadata.addValue("data", event.data); + trackingMetadata.addValue("adobePass", event.trackingType + ":" + event.data.join()); + + addMetadata("http://www.adobe.com/products/adobepass", trackingMetadata); + resource.addMetadataValue("http://www.adobe.com/products/adobepass", trackingMetadata); + } + + private function onTokenFailed(event:TokenEvent):void + { + dispatchEvent(event.clone()); + } + + private function onTokenSuccess(event:TokenEvent):void + { + // Unblock the play trait + var playTraitIndex:int = blockedTraits.indexOf(MediaTraitType.PLAY); + blockedTraits = blockedTraits.slice(playTraitIndex, playTraitIndex); + + dispatchEvent(event.clone()); + } + + private var _accessEnabler:AccessEnablerHelper; + + } } \ No newline at end of file diff --git a/lib/osmf/samples/AdvertisementPlugin/.actionScriptProperties b/lib/osmf/samples/AdvertisementPlugin/.actionScriptProperties index c8de68a..f15ed48 100644 --- a/lib/osmf/samples/AdvertisementPlugin/.actionScriptProperties +++ b/lib/osmf/samples/AdvertisementPlugin/.actionScriptProperties @@ -1,40 +1,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/AdvertisementSample/.actionScriptProperties b/lib/osmf/samples/AdvertisementSample/.actionScriptProperties index f931084..12496e8 100644 --- a/lib/osmf/samples/AdvertisementSample/.actionScriptProperties +++ b/lib/osmf/samples/AdvertisementSample/.actionScriptProperties @@ -1,41 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/AkamaiBasicStreamingPlugin/.actionScriptProperties b/lib/osmf/samples/AkamaiBasicStreamingPlugin/.actionScriptProperties index 1bd078d..2226f8a 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPlugin/.actionScriptProperties +++ b/lib/osmf/samples/AkamaiBasicStreamingPlugin/.actionScriptProperties @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/AkamaiBasicStreamingPlugin/AkamaiBasicStreamingPlugin-build-config.xml b/lib/osmf/samples/AkamaiBasicStreamingPlugin/AkamaiBasicStreamingPlugin-build-config.xml index f81a437..ac1822e 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPlugin/AkamaiBasicStreamingPlugin-build-config.xml +++ b/lib/osmf/samples/AkamaiBasicStreamingPlugin/AkamaiBasicStreamingPlugin-build-config.xml @@ -22,18 +22,18 @@ - false - @@ -86,11 +86,11 @@ - @@ -98,8 +98,8 @@ - @@ -117,13 +117,13 @@ - @@ -132,11 +132,11 @@ flash.fonts.AFEFontManager flash.fonts.BatikFontManager - @@ -230,28 +230,28 @@ false - - - true - - true diff --git a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/AkamaiBasicStreamingPlugin.as b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/AkamaiBasicStreamingPlugin.as index b8a1271..01f796e 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/AkamaiBasicStreamingPlugin.as +++ b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/AkamaiBasicStreamingPlugin.as @@ -1,58 +1,58 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ - -package -{ - import com.akamai.osmf.AkamaiBasicStreamingPluginInfo; - - import flash.display.Sprite; - - import org.osmf.media.PluginInfo; - - /** - * The Akamai Basic Streaming Plugin for OSMF supports Akamai-specific - * behavior and functionality for streaming live and ondemand content - * as well as progressive download content over the Akamai network. - * Support for Akamai's connect-level and stream-level token - * authentication is included in this plugin. - **/ - public class AkamaiBasicStreamingPlugin extends Sprite - { - /** - * Constructor - **/ - public function AkamaiBasicStreamingPlugin() - { - _akamaiPluginInfo = new AkamaiBasicStreamingPluginInfo(); - } - - /** - * Gives the player the PluginInfo. - **/ - public function get pluginInfo():PluginInfo - { - return _akamaiPluginInfo; - } - - private var _akamaiPluginInfo:AkamaiBasicStreamingPluginInfo; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ + +package +{ + import com.akamai.osmf.AkamaiBasicStreamingPluginInfo; + + import flash.display.Sprite; + + import org.osmf.media.PluginInfo; + + /** + * The Akamai Basic Streaming Plugin for OSMF supports Akamai-specific + * behavior and functionality for streaming live and ondemand content + * as well as progressive download content over the Akamai network. + * Support for Akamai's connect-level and stream-level token + * authentication is included in this plugin. + **/ + public class AkamaiBasicStreamingPlugin extends Sprite + { + /** + * Constructor + **/ + public function AkamaiBasicStreamingPlugin() + { + _akamaiPluginInfo = new AkamaiBasicStreamingPluginInfo(); + } + + /** + * Gives the player the PluginInfo. + **/ + public function get pluginInfo():PluginInfo + { + return _akamaiPluginInfo; + } + + private var _akamaiPluginInfo:AkamaiBasicStreamingPluginInfo; + } +} diff --git a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetConnection.as b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetConnection.as index 09b475a..538133e 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetConnection.as +++ b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetConnection.as @@ -1,138 +1,138 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ - -package com.akamai.osmf.net -{ - import com.akamai.osmf.AkamaiBasicStreamingPluginInfo; - - import flash.events.NetStatusEvent; - import flash.net.NetConnection; - - import org.osmf.metadata.Metadata; - import org.osmf.net.FMSURL; - - CONFIG::LOGGING - { - import org.osmf.logging.*; - } - - /** - * The AkamaiNetConnection class extends NetConnection to provide - * Akamai CDN-specifc connection behavior. - **/ - public class AkamaiNetConnection extends NetConnection - { - /** - * Constructor. - **/ - public function AkamaiNetConnection(resourceMetadata:Metadata=null) - { - super(); - - if (resourceMetadata != null) - { - processResourceMetadata(resourceMetadata); - } - - _isLive = false; - this.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); - } - - private function processResourceMetadata(metadata:Metadata):void - { - authParams = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_CONNECT_AUTH_PARAMS) as String; - } - - private function onNetStatus(event:NetStatusEvent):void - { - debug("onNetStatus() - event.info.code="+event.info.code); - switch(event.info.code) - { - case "NetConnection.Call.Failed": - debug("onNetStatus() - event.info.description="+event.info.description); - break; - } - } - - /** - * Allows package level access to determine whether or not the - * connection requested is to a live stream. - **/ - internal function get isLive():Boolean - { - return _isLive; - }  - - /** - * @inheritDoc - **/ - override public function connect(command:String, ...parameters):void - { - if (command != null) - { - var theURL:FMSURL = new FMSURL(command); - _isLive = (theURL.appName.toLowerCase() == "live") ? true : false; - - // If we have auth params, append them if they are not already there - if (authParams && authParams.length > 0) - { - var authToken:String = theURL.getParamValue("auth"); - if (authToken == "") - { - command = command.indexOf("?") != -1 ? command + "&" + authParams : command + "?" + authParams; - } - } - } - super.connect(command, parameters); - } - - /** - * @inheritDoc - **/ - override public function close():void - { - super.close(); - removeEventListener(NetStatusEvent.NET_STATUS, onNetStatus); - } - - private function debug(msg:String):void - { - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug(msg); - } - } - } - - private var _isLive:Boolean; - private var authParams:String; - - CONFIG::LOGGING - { - private static const logger:org.osmf.logging.Logger = - org.osmf.logging.Log.getLogger("com.akamai.osmf.net.AkamaiNetConnection"); - } - - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ + +package com.akamai.osmf.net +{ + import com.akamai.osmf.AkamaiBasicStreamingPluginInfo; + + import flash.events.NetStatusEvent; + import flash.net.NetConnection; + + import org.osmf.metadata.Metadata; + import org.osmf.net.FMSURL; + + CONFIG::LOGGING + { + import org.osmf.logging.*; + } + + /** + * The AkamaiNetConnection class extends NetConnection to provide + * Akamai CDN-specifc connection behavior. + **/ + public class AkamaiNetConnection extends NetConnection + { + /** + * Constructor. + **/ + public function AkamaiNetConnection(resourceMetadata:Metadata=null) + { + super(); + + if (resourceMetadata != null) + { + processResourceMetadata(resourceMetadata); + } + + _isLive = false; + this.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); + } + + private function processResourceMetadata(metadata:Metadata):void + { + authParams = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_CONNECT_AUTH_PARAMS) as String; + } + + private function onNetStatus(event:NetStatusEvent):void + { + debug("onNetStatus() - event.info.code="+event.info.code); + switch(event.info.code) + { + case "NetConnection.Call.Failed": + debug("onNetStatus() - event.info.description="+event.info.description); + break; + } + } + + /** + * Allows package level access to determine whether or not the + * connection requested is to a live stream. + **/ + internal function get isLive():Boolean + { + return _isLive; + }  + + /** + * @inheritDoc + **/ + override public function connect(command:String, ...parameters):void + { + if (command != null) + { + var theURL:FMSURL = new FMSURL(command); + _isLive = (theURL.appName.toLowerCase() == "live") ? true : false; + + // If we have auth params, append them if they are not already there + if (authParams && authParams.length > 0) + { + var authToken:String = theURL.getParamValue("auth"); + if (authToken == "") + { + command = command.indexOf("?") != -1 ? command + "&" + authParams : command + "?" + authParams; + } + } + } + super.connect(command, parameters); + } + + /** + * @inheritDoc + **/ + override public function close():void + { + super.close(); + removeEventListener(NetStatusEvent.NET_STATUS, onNetStatus); + } + + private function debug(msg:String):void + { + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug(msg); + } + } + } + + private var _isLive:Boolean; + private var authParams:String; + + CONFIG::LOGGING + { + private static const logger:org.osmf.logging.Logger = + org.osmf.logging.Log.getLogger("com.akamai.osmf.net.AkamaiNetConnection"); + } + + } +} diff --git a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetConnectionFactory.as b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetConnectionFactory.as index 27f0086..28f3c7e 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetConnectionFactory.as +++ b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetConnectionFactory.as @@ -1,74 +1,74 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ - -package com.akamai.osmf.net -{ - import com.akamai.osmf.AkamaiBasicStreamingPluginInfo; - - import flash.net.NetConnection; - - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.net.NetConnectionFactory; - import org.osmf.utils.URL; - - /** - * The AkamaiNetConnectionFactory class extends NetConnectionFactory to - * provide the means to create a unique key for connection sharing and - * support token authentication. - * - **/ - public class AkamaiNetConnectionFactory extends NetConnectionFactory - { - /** - * Override so we can get to the resource metadata. - **/ - override public function create(resource:URLResource):void - { - _resourceMetadata = resource.getMetadataValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_NAMESPACE) as Metadata; - super.create(resource); - } - - /** - * @inheritDoc - **/ - override protected function createNetConnectionKey(resource:URLResource):String - { - var theURL:URL = new URL(resource.url); - var authToken:String = theURL.getParamValue("auth"); - var aifpToken:String = theURL.getParamValue("aifp"); - var slistToken:String = theURL.getParamValue("slist"); - - return super.createNetConnectionKey(resource) + authToken + aifpToken + slistToken; - } - - /** - * @inheritDoc - **/ - override protected function createNetConnection():NetConnection - { - return new AkamaiNetConnection(_resourceMetadata); - } - - private var _resourceMetadata:Metadata; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ + +package com.akamai.osmf.net +{ + import com.akamai.osmf.AkamaiBasicStreamingPluginInfo; + + import flash.net.NetConnection; + + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.net.NetConnectionFactory; + import org.osmf.utils.URL; + + /** + * The AkamaiNetConnectionFactory class extends NetConnectionFactory to + * provide the means to create a unique key for connection sharing and + * support token authentication. + * + **/ + public class AkamaiNetConnectionFactory extends NetConnectionFactory + { + /** + * Override so we can get to the resource metadata. + **/ + override public function create(resource:URLResource):void + { + _resourceMetadata = resource.getMetadataValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_NAMESPACE) as Metadata; + super.create(resource); + } + + /** + * @inheritDoc + **/ + override protected function createNetConnectionKey(resource:URLResource):String + { + var theURL:URL = new URL(resource.url); + var authToken:String = theURL.getParamValue("auth"); + var aifpToken:String = theURL.getParamValue("aifp"); + var slistToken:String = theURL.getParamValue("slist"); + + return super.createNetConnectionKey(resource) + authToken + aifpToken + slistToken; + } + + /** + * @inheritDoc + **/ + override protected function createNetConnection():NetConnection + { + return new AkamaiNetConnection(_resourceMetadata); + } + + private var _resourceMetadata:Metadata; + } +} diff --git a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetLoader.as b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetLoader.as index dfd36bd..cdb4fa4 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetLoader.as +++ b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetLoader.as @@ -1,117 +1,117 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ - -package com.akamai.osmf.net -{ - import flash.net.NetConnection; - import flash.net.NetStream; - import flash.utils.Dictionary; - - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.net.NetConnectionFactoryBase; - import org.osmf.net.rtmpstreaming.RTMPDynamicStreamingNetLoader; - import org.osmf.traits.LoadTrait; - - /** - * The AkamaiNetLoader class provides the means for - * creating a custom NetStream class, - * in this case, an AkamaiNetStream. - * - * @see AkamaiNetStream - **/ - public class AkamaiNetLoader extends RTMPDynamicStreamingNetLoader - { - /** - * @inheritDoc - **/ - public function AkamaiNetLoader(factory:NetConnectionFactoryBase) - { - super(factory); - } - - /** - * @private - **/ - public function get pluginMetadata():Metadata - { - return _pluginMetadata; - } - - public function set pluginMetadata(value:Metadata):void - { - _pluginMetadata = value; - } - - /** - * @inheritDoc - **/ - override protected function createNetStream(connection:NetConnection, resource:URLResource):NetStream - { - var ns:AkamaiNetStream = new AkamaiNetStream(connection, resource, this); - - return ns; - } - - CONFIG::FLASH_10_1 - { - /** - * @inheritDoc - **/ - override protected function createReconnectNetConnection():NetConnection - { - return new AkamaiNetConnection(); - } - } - - /** - * @inheritDoc - **/ - override protected function executeLoad(loadTrait:LoadTrait):void - { - super.executeLoad(loadTrait); - - if (loadTraitMap == null) - { - loadTraitMap = new Dictionary(); - } - - var resource:URLResource = (loadTrait.resource as URLResource); - if (resource != null) - { - loadTraitMap[resource] = loadTrait; - } - } - - /** - * Internal function to return the LoadTrait associated with - * the supplied resource. - **/ - internal function getLoadTrait(resource:URLResource):LoadTrait - { - return loadTraitMap[resource] as LoadTrait; - } - - private var loadTraitMap:Dictionary; - private var _pluginMetadata:Metadata; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ + +package com.akamai.osmf.net +{ + import flash.net.NetConnection; + import flash.net.NetStream; + import flash.utils.Dictionary; + + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.net.NetConnectionFactoryBase; + import org.osmf.net.rtmpstreaming.RTMPDynamicStreamingNetLoader; + import org.osmf.traits.LoadTrait; + + /** + * The AkamaiNetLoader class provides the means for + * creating a custom NetStream class, + * in this case, an AkamaiNetStream. + * + * @see AkamaiNetStream + **/ + public class AkamaiNetLoader extends RTMPDynamicStreamingNetLoader + { + /** + * @inheritDoc + **/ + public function AkamaiNetLoader(factory:NetConnectionFactoryBase) + { + super(factory); + } + + /** + * @private + **/ + public function get pluginMetadata():Metadata + { + return _pluginMetadata; + } + + public function set pluginMetadata(value:Metadata):void + { + _pluginMetadata = value; + } + + /** + * @inheritDoc + **/ + override protected function createNetStream(connection:NetConnection, resource:URLResource):NetStream + { + var ns:AkamaiNetStream = new AkamaiNetStream(connection, resource, this); + + return ns; + } + + CONFIG::FLASH_10_1 + { + /** + * @inheritDoc + **/ + override protected function createReconnectNetConnection():NetConnection + { + return new AkamaiNetConnection(); + } + } + + /** + * @inheritDoc + **/ + override protected function executeLoad(loadTrait:LoadTrait):void + { + super.executeLoad(loadTrait); + + if (loadTraitMap == null) + { + loadTraitMap = new Dictionary(); + } + + var resource:URLResource = (loadTrait.resource as URLResource); + if (resource != null) + { + loadTraitMap[resource] = loadTrait; + } + } + + /** + * Internal function to return the LoadTrait associated with + * the supplied resource. + **/ + internal function getLoadTrait(resource:URLResource):LoadTrait + { + return loadTraitMap[resource] as LoadTrait; + } + + private var loadTraitMap:Dictionary; + private var _pluginMetadata:Metadata; + } +} diff --git a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetStream.as b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetStream.as index e2d9f52..b6c0509 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetStream.as +++ b/lib/osmf/samples/AkamaiBasicStreamingPlugin/src/com/akamai/osmf/net/AkamaiNetStream.as @@ -1,448 +1,448 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ - -package com.akamai.osmf.net -{ - import com.akamai.osmf.AkamaiBasicStreamingPluginInfo; - - import flash.events.NetStatusEvent; - import flash.events.TimerEvent; - import flash.net.NetConnection; - import flash.net.NetStream; - import flash.net.NetStreamPlayOptions; - import flash.utils.Timer; - - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorCodes; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.net.DynamicStreamingResource; - import org.osmf.net.NetClient; - import org.osmf.traits.LoadTrait; - - CONFIG::LOGGING - { - import org.osmf.logging.*; - } - - - /** - * The AkamaiNetStream class extends NetStream to provide - * Akamai CDN-specific streaming behavior. - **/ - public class AkamaiNetStream extends NetStream - { - /** - * Constructor. - * - * @param connection The NetConnection object the stream will use. - * @param resource The URLResource representing the media. - * @param netLoader The AkamaiNetLoader used to instantiated this class. This - * parameter is necessary to allow this class to issue MediaError events on - * the load trait. - * - * @throws ArgumentError If connection param is null or is not an AkamaiNetConnection. - **/ - public function AkamaiNetStream(connection:NetConnection, resource:URLResource, netLoader:AkamaiNetLoader) - { - super(connection); - _nc = connection as AkamaiNetConnection; - - if (_nc == null && ((connection as NetConnection) == null)) - { - throw new ArgumentError("The connection argument must be a valid NetConnection object!"); - } - - _resource = resource; - _netLoader = netLoader; - - // Set default values - _liveRetryInterval = LIVE_RETRY_INTERVAL; - _liveStreamMasterTimeout = LIVE_RETRY_TIMEOUT; - _retryLiveStreamsIfUnavailable = true; - this.bufferTime = (resource is DynamicStreamingResource) ? DEFAULT_MBR_BUFFER_TIME : DEFAULT_BUFFER_TIME; - - // Check for plugin metadata that might override the default values - processPluginMetadata(); - - if (_nc != null && _nc.isLive) - { - // Add a callback for the FCSubscribe call - (_nc.client as NetClient).addHandler("onFCSubscribe", this.onFCSubscribe); - - addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); - - _liveStreamRetryTimer = new Timer(_liveRetryInterval); - _liveStreamRetryTimer.addEventListener(TimerEvent.TIMER, onRetryLiveStream); - - _liveStreamTimeoutTimer = new Timer(_liveStreamMasterTimeout, 1); - _liveStreamTimeoutTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onLiveStreamTimeout); - } - - // Check for resource metadata - var metadata:Metadata = resource.getMetadataValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_NAMESPACE) as Metadata; - if (metadata) - { - processResourceMetadata(metadata); - } - } - - /** - * @inheritDoc - **/ - override public function play(...arguments):void - { - // If we have auth params, append them - if (authParams && authParams.length > 0) - { - var streamName:String = arguments[0] as String; - arguments[0] = streamName.indexOf("?") != -1 ? streamName + "&" + authParams : streamName + "?" + authParams; - } - - if (_nc != null && _nc.isLive) - { - _pendingLiveStreamName = arguments[0] as String; - arguments[1] = -1; - _liveStreamTimeoutTimer.reset(); - _liveStreamTimeoutTimer.start(); - } - - super.play.apply(this, arguments); - } - - /** - * @inheritDoc - **/ - override public function play2(nso:NetStreamPlayOptions):void - { - var firstPlay:Boolean = (nso.oldStreamName == null); - - // Strip off the auth params unless this is the first play - if (!firstPlay) - { - nso.streamName = nso.streamName.split("?")[0]; - nso.oldStreamName = nso.oldStreamName.split("?")[0]; - } - else if (authParams && authParams.length > 0) - { - nso.streamName = nso.streamName.indexOf("?") != -1 ? - nso.streamName + "&" + authParams : - nso.streamName + "?" + authParams; - } - - super.play2(nso); - - if (_nc != null && _nc.isLive) - { - _pendingLiveStreamName = nso.streamName; - _liveStreamTimeoutTimer.reset(); - _liveStreamTimeoutTimer.start(); - } - } - - /** - * @inheritDoc - **/ - override public function close():void - { - debug("close() method called."); - super.close(); - - if (_nc != null && _nc.isLive) - { - cleanupAllLiveTimers(); - removeEventListener(NetStatusEvent.NET_STATUS, onNetStatus); - } - } - - /** - * If this property is true, then if a live stream is playing - * and becomes unpublished due to both the primary and backup - * encoders ceasing to publish, the class will automatically - * enter into a retry cycle, where it will attempt to play the - * streams again. Similarly, if a play request is made and the - * live stream is not found, the class will reattempt the - * streams at a predefined interval. This interval is set by - * the liveRetryInterval. The retries will cease and timeout - * once the liveRetryTimeout value has elapsed without a - * successfull play. - * - * @default true - **/ - public function get retryLiveStreamsIfUnavailable():Boolean - { - return _retryLiveStreamsIfUnavailable; - } - - public function set retryLiveStreamsIfUnavailable(value:Boolean):void - { - _retryLiveStreamsIfUnavailable = value; - } - - /** - * Defines the live stream retry interval in seconds - * - * @default 15 seconds - * @see #retryLiveStreamsIfUnavailable - **/ - public function get liveRetryInterval():Number - { - return _liveRetryInterval/1000; - } - - public function set liveRetryInterval(value:Number):void - { - _liveRetryInterval = value*1000; - } - - /** - * The maximum number of seconds the class should wait before - * timing out while trying to locate a live stream on the network. - * This time begins decrementing the moment a play - * request is made against a live stream, or after the class - * receives an UnpublishNotify event while still playing a live - * stream, in which case it attempts to automatically reconnect. - * After this master time out has been triggered, the class will issue - * a MediaErrorEvent on the LoadTrait with a MediaErrorCode of - * NETSTREAM_STREAM_NOT_FOUND. - * - * @default 1200 - **/ - public function get liveStreamMasterTimeout():Number - { - return _liveStreamMasterTimeout / 1000; - } - - public function set liveStreamMasterTimeout(numOfSeconds:Number):void - { - _liveStreamMasterTimeout = numOfSeconds * 1000; - _liveStreamTimeoutTimer.delay = _liveStreamMasterTimeout; - } - - /** - * Looks for any plugin metadata and sets private variables - * directly. This method is safe to call from the constructor - * since no properties or methods of this class are called. - **/ - private function processPluginMetadata():void - { - var metadata:Metadata = _netLoader.pluginMetadata; - if (metadata != null) - { - // The master time out for playing a live stream (in seconds) - var value:Object = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_LIVE_TIMEOUT); - if (value != null && Number(value) > 0) - { - _liveStreamMasterTimeout = Number(value) * 1000; - } - - // Determines whether we should retry live streams when they fail - value = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_RETRY_LIVE); - if (value != null) - { - _retryLiveStreamsIfUnavailable = value as Boolean; - } - - // The interval at which live streams will be retried if encoders fail - value = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_RETRY_INTERVAL); - if (value != null && Number(value) > 0) - { - _liveRetryInterval = Number(value) * 1000; - } - } - } - - /** - * Looks for any resource metadata. - **/ - private function processResourceMetadata(metadata:Metadata):void - { - authParams = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_STREAM_AUTH_PARAMS) as String; - } - - /** - * Makes the FCSubscribe call to the server and - * starts the timeout timers. - **/ - private function fcsubscribe(streamName:String):void - { - _nc.call("FCSubscribe", null, streamName); - } - - /** - * Handles the case of never being able to successfully start - * the live stream. This is the master timeout. - **/ - private function onLiveStreamTimeout(e:TimerEvent):void - { - cleanupAllLiveTimers(); - - if (_resource != null && _netLoader != null && _netLoader is AkamaiNetLoader) - { - var loadTrait:LoadTrait = _netLoader.getLoadTrait(_resource); - debug("onLiveStreamTimeout() about to dispatch a MediaError with code MediaErrorCodes.NETSTREAM_STREAM_NOT_FOUND due to time out."); - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, - new MediaError(MediaErrorCodes.NETSTREAM_STREAM_NOT_FOUND, "Live stream timed out."))); - } - } - - /** - * Retries the FCSubscribe call on the server. - *

- * If the primary and secondary encoders crash, the stream - * is cleaned up and no longer subscribed to through the live chain, so - * we need to issue an FCSubscribe again and the player will need to - * re-issue a play request on either the play trait or the MediaPlayer - * or the stream doesn't get subscribed to all the way from the - * entry point. - **/ - private function onRetryLiveStream(e:TimerEvent):void - { - debug("onRetryLiveStream() called."); - if (_retryLiveStreamsIfUnavailable) - { - // When subscribing to a live stream we need to strip off query params - fcsubscribe(_pendingLiveStreamName.split("?")[0].toString()); - } - else - { - onLiveStreamTimeout(null); - } - } - - /** - * Resets all timers. - **/ - private function resetAllLiveTimers(restart:Boolean=false):void - { - if (_liveStreamRetryTimer != null && _liveStreamTimeoutTimer != null) - { - _liveStreamRetryTimer.reset(); - _liveStreamTimeoutTimer.reset(); - - if (restart) - { - _liveStreamRetryTimer.start(); - _liveStreamTimeoutTimer.start(); - } - } - } - - /** - * Cleans up all live timers and their listeners. - **/ - private function cleanupAllLiveTimers():void - { - if (_liveStreamRetryTimer != null) - { - _liveStreamRetryTimer.stop(); - _liveStreamRetryTimer.removeEventListener(TimerEvent.TIMER, onRetryLiveStream); - _liveStreamRetryTimer = null; - } - - if (_liveStreamTimeoutTimer != null) - { - _liveStreamTimeoutTimer.stop(); - _liveStreamTimeoutTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onLiveStreamTimeout); - _liveStreamTimeoutTimer = null; - } - } - - /** - * The callback function from the FCSubscribe call. - * These are the only two info.codes available. - **/ - private function onFCSubscribe(info:Object):void - { - debug("onFCSubscribe() - info.code="+info.code); - - switch (info.code) - { - case "NetStream.Play.Start": - resetAllLiveTimers(); - break; - case "NetStream.Play.StreamNotFound": - if (_liveStreamRetryTimer != null && !_liveStreamRetryTimer.running) - { - // If our first play attempt has failed, let's try to resubscribe right away - onRetryLiveStream(null); - _liveStreamRetryTimer.reset(); - _liveStreamRetryTimer.start(); - } - break; - } - } - - private function onNetStatus(event:NetStatusEvent):void - { - debug("onNetStatus() - event.info.code="+event.info.code); - - switch (event.info.code) - { - case "NetStream.Play.PublishNotify": - resetAllLiveTimers(); - break; - case "NetStream.Play.UnpublishNotify": - if (!_liveStreamRetryTimer.running) - { - onRetryLiveStream(null); - resetAllLiveTimers(true); - } - break; - } - } - - private function debug(msg:String):void - { - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug(msg); - } - } - } - - private var _nc:AkamaiNetConnection; - private var _netLoader:AkamaiNetLoader; - private var _pendingLiveStreamName:String; - private var _resource:URLResource - private var _liveStreamRetryTimer:Timer; - private var _liveStreamTimeoutTimer:Timer; - private var _liveRetryInterval:Number; - private var _liveStreamMasterTimeout:Number; - private var _retryLiveStreamsIfUnavailable:Boolean; - private var authParams:String; - - private const LIVE_RETRY_INTERVAL:Number = 15000; // 15 seconds - private const LIVE_RETRY_TIMEOUT:Number = 1200000; // 20 minutes - private const DEFAULT_BUFFER_TIME:Number = 3; - private const DEFAULT_MBR_BUFFER_TIME:Number = 8; - - CONFIG::LOGGING - { - private static const logger:org.osmf.logging.Logger = - org.osmf.logging.Log.getLogger("com.akamai.osmf.net.AkamaiNetStream"); - } - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ + +package com.akamai.osmf.net +{ + import com.akamai.osmf.AkamaiBasicStreamingPluginInfo; + + import flash.events.NetStatusEvent; + import flash.events.TimerEvent; + import flash.net.NetConnection; + import flash.net.NetStream; + import flash.net.NetStreamPlayOptions; + import flash.utils.Timer; + + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorCodes; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.net.DynamicStreamingResource; + import org.osmf.net.NetClient; + import org.osmf.traits.LoadTrait; + + CONFIG::LOGGING + { + import org.osmf.logging.*; + } + + + /** + * The AkamaiNetStream class extends NetStream to provide + * Akamai CDN-specific streaming behavior. + **/ + public class AkamaiNetStream extends NetStream + { + /** + * Constructor. + * + * @param connection The NetConnection object the stream will use. + * @param resource The URLResource representing the media. + * @param netLoader The AkamaiNetLoader used to instantiated this class. This + * parameter is necessary to allow this class to issue MediaError events on + * the load trait. + * + * @throws ArgumentError If connection param is null or is not an AkamaiNetConnection. + **/ + public function AkamaiNetStream(connection:NetConnection, resource:URLResource, netLoader:AkamaiNetLoader) + { + super(connection); + _nc = connection as AkamaiNetConnection; + + if (_nc == null && ((connection as NetConnection) == null)) + { + throw new ArgumentError("The connection argument must be a valid NetConnection object!"); + } + + _resource = resource; + _netLoader = netLoader; + + // Set default values + _liveRetryInterval = LIVE_RETRY_INTERVAL; + _liveStreamMasterTimeout = LIVE_RETRY_TIMEOUT; + _retryLiveStreamsIfUnavailable = true; + this.bufferTime = (resource is DynamicStreamingResource) ? DEFAULT_MBR_BUFFER_TIME : DEFAULT_BUFFER_TIME; + + // Check for plugin metadata that might override the default values + processPluginMetadata(); + + if (_nc != null && _nc.isLive) + { + // Add a callback for the FCSubscribe call + (_nc.client as NetClient).addHandler("onFCSubscribe", this.onFCSubscribe); + + addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); + + _liveStreamRetryTimer = new Timer(_liveRetryInterval); + _liveStreamRetryTimer.addEventListener(TimerEvent.TIMER, onRetryLiveStream); + + _liveStreamTimeoutTimer = new Timer(_liveStreamMasterTimeout, 1); + _liveStreamTimeoutTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onLiveStreamTimeout); + } + + // Check for resource metadata + var metadata:Metadata = resource.getMetadataValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_NAMESPACE) as Metadata; + if (metadata) + { + processResourceMetadata(metadata); + } + } + + /** + * @inheritDoc + **/ + override public function play(...arguments):void + { + // If we have auth params, append them + if (authParams && authParams.length > 0) + { + var streamName:String = arguments[0] as String; + arguments[0] = streamName.indexOf("?") != -1 ? streamName + "&" + authParams : streamName + "?" + authParams; + } + + if (_nc != null && _nc.isLive) + { + _pendingLiveStreamName = arguments[0] as String; + arguments[1] = -1; + _liveStreamTimeoutTimer.reset(); + _liveStreamTimeoutTimer.start(); + } + + super.play.apply(this, arguments); + } + + /** + * @inheritDoc + **/ + override public function play2(nso:NetStreamPlayOptions):void + { + var firstPlay:Boolean = (nso.oldStreamName == null); + + // Strip off the auth params unless this is the first play + if (!firstPlay) + { + nso.streamName = nso.streamName.split("?")[0]; + nso.oldStreamName = nso.oldStreamName.split("?")[0]; + } + else if (authParams && authParams.length > 0) + { + nso.streamName = nso.streamName.indexOf("?") != -1 ? + nso.streamName + "&" + authParams : + nso.streamName + "?" + authParams; + } + + super.play2(nso); + + if (_nc != null && _nc.isLive) + { + _pendingLiveStreamName = nso.streamName; + _liveStreamTimeoutTimer.reset(); + _liveStreamTimeoutTimer.start(); + } + } + + /** + * @inheritDoc + **/ + override public function close():void + { + debug("close() method called."); + super.close(); + + if (_nc != null && _nc.isLive) + { + cleanupAllLiveTimers(); + removeEventListener(NetStatusEvent.NET_STATUS, onNetStatus); + } + } + + /** + * If this property is true, then if a live stream is playing + * and becomes unpublished due to both the primary and backup + * encoders ceasing to publish, the class will automatically + * enter into a retry cycle, where it will attempt to play the + * streams again. Similarly, if a play request is made and the + * live stream is not found, the class will reattempt the + * streams at a predefined interval. This interval is set by + * the liveRetryInterval. The retries will cease and timeout + * once the liveRetryTimeout value has elapsed without a + * successfull play. + * + * @default true + **/ + public function get retryLiveStreamsIfUnavailable():Boolean + { + return _retryLiveStreamsIfUnavailable; + } + + public function set retryLiveStreamsIfUnavailable(value:Boolean):void + { + _retryLiveStreamsIfUnavailable = value; + } + + /** + * Defines the live stream retry interval in seconds + * + * @default 15 seconds + * @see #retryLiveStreamsIfUnavailable + **/ + public function get liveRetryInterval():Number + { + return _liveRetryInterval/1000; + } + + public function set liveRetryInterval(value:Number):void + { + _liveRetryInterval = value*1000; + } + + /** + * The maximum number of seconds the class should wait before + * timing out while trying to locate a live stream on the network. + * This time begins decrementing the moment a play + * request is made against a live stream, or after the class + * receives an UnpublishNotify event while still playing a live + * stream, in which case it attempts to automatically reconnect. + * After this master time out has been triggered, the class will issue + * a MediaErrorEvent on the LoadTrait with a MediaErrorCode of + * NETSTREAM_STREAM_NOT_FOUND. + * + * @default 1200 + **/ + public function get liveStreamMasterTimeout():Number + { + return _liveStreamMasterTimeout / 1000; + } + + public function set liveStreamMasterTimeout(numOfSeconds:Number):void + { + _liveStreamMasterTimeout = numOfSeconds * 1000; + _liveStreamTimeoutTimer.delay = _liveStreamMasterTimeout; + } + + /** + * Looks for any plugin metadata and sets private variables + * directly. This method is safe to call from the constructor + * since no properties or methods of this class are called. + **/ + private function processPluginMetadata():void + { + var metadata:Metadata = _netLoader.pluginMetadata; + if (metadata != null) + { + // The master time out for playing a live stream (in seconds) + var value:Object = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_LIVE_TIMEOUT); + if (value != null && Number(value) > 0) + { + _liveStreamMasterTimeout = Number(value) * 1000; + } + + // Determines whether we should retry live streams when they fail + value = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_RETRY_LIVE); + if (value != null) + { + _retryLiveStreamsIfUnavailable = value as Boolean; + } + + // The interval at which live streams will be retried if encoders fail + value = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_RETRY_INTERVAL); + if (value != null && Number(value) > 0) + { + _liveRetryInterval = Number(value) * 1000; + } + } + } + + /** + * Looks for any resource metadata. + **/ + private function processResourceMetadata(metadata:Metadata):void + { + authParams = metadata.getValue(AkamaiBasicStreamingPluginInfo.AKAMAI_METADATA_KEY_STREAM_AUTH_PARAMS) as String; + } + + /** + * Makes the FCSubscribe call to the server and + * starts the timeout timers. + **/ + private function fcsubscribe(streamName:String):void + { + _nc.call("FCSubscribe", null, streamName); + } + + /** + * Handles the case of never being able to successfully start + * the live stream. This is the master timeout. + **/ + private function onLiveStreamTimeout(e:TimerEvent):void + { + cleanupAllLiveTimers(); + + if (_resource != null && _netLoader != null && _netLoader is AkamaiNetLoader) + { + var loadTrait:LoadTrait = _netLoader.getLoadTrait(_resource); + debug("onLiveStreamTimeout() about to dispatch a MediaError with code MediaErrorCodes.NETSTREAM_STREAM_NOT_FOUND due to time out."); + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, + new MediaError(MediaErrorCodes.NETSTREAM_STREAM_NOT_FOUND, "Live stream timed out."))); + } + } + + /** + * Retries the FCSubscribe call on the server. + *

+ * If the primary and secondary encoders crash, the stream + * is cleaned up and no longer subscribed to through the live chain, so + * we need to issue an FCSubscribe again and the player will need to + * re-issue a play request on either the play trait or the MediaPlayer + * or the stream doesn't get subscribed to all the way from the + * entry point. + **/ + private function onRetryLiveStream(e:TimerEvent):void + { + debug("onRetryLiveStream() called."); + if (_retryLiveStreamsIfUnavailable) + { + // When subscribing to a live stream we need to strip off query params + fcsubscribe(_pendingLiveStreamName.split("?")[0].toString()); + } + else + { + onLiveStreamTimeout(null); + } + } + + /** + * Resets all timers. + **/ + private function resetAllLiveTimers(restart:Boolean=false):void + { + if (_liveStreamRetryTimer != null && _liveStreamTimeoutTimer != null) + { + _liveStreamRetryTimer.reset(); + _liveStreamTimeoutTimer.reset(); + + if (restart) + { + _liveStreamRetryTimer.start(); + _liveStreamTimeoutTimer.start(); + } + } + } + + /** + * Cleans up all live timers and their listeners. + **/ + private function cleanupAllLiveTimers():void + { + if (_liveStreamRetryTimer != null) + { + _liveStreamRetryTimer.stop(); + _liveStreamRetryTimer.removeEventListener(TimerEvent.TIMER, onRetryLiveStream); + _liveStreamRetryTimer = null; + } + + if (_liveStreamTimeoutTimer != null) + { + _liveStreamTimeoutTimer.stop(); + _liveStreamTimeoutTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onLiveStreamTimeout); + _liveStreamTimeoutTimer = null; + } + } + + /** + * The callback function from the FCSubscribe call. + * These are the only two info.codes available. + **/ + private function onFCSubscribe(info:Object):void + { + debug("onFCSubscribe() - info.code="+info.code); + + switch (info.code) + { + case "NetStream.Play.Start": + resetAllLiveTimers(); + break; + case "NetStream.Play.StreamNotFound": + if (_liveStreamRetryTimer != null && !_liveStreamRetryTimer.running) + { + // If our first play attempt has failed, let's try to resubscribe right away + onRetryLiveStream(null); + _liveStreamRetryTimer.reset(); + _liveStreamRetryTimer.start(); + } + break; + } + } + + private function onNetStatus(event:NetStatusEvent):void + { + debug("onNetStatus() - event.info.code="+event.info.code); + + switch (event.info.code) + { + case "NetStream.Play.PublishNotify": + resetAllLiveTimers(); + break; + case "NetStream.Play.UnpublishNotify": + if (!_liveStreamRetryTimer.running) + { + onRetryLiveStream(null); + resetAllLiveTimers(true); + } + break; + } + } + + private function debug(msg:String):void + { + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug(msg); + } + } + } + + private var _nc:AkamaiNetConnection; + private var _netLoader:AkamaiNetLoader; + private var _pendingLiveStreamName:String; + private var _resource:URLResource + private var _liveStreamRetryTimer:Timer; + private var _liveStreamTimeoutTimer:Timer; + private var _liveRetryInterval:Number; + private var _liveStreamMasterTimeout:Number; + private var _retryLiveStreamsIfUnavailable:Boolean; + private var authParams:String; + + private const LIVE_RETRY_INTERVAL:Number = 15000; // 15 seconds + private const LIVE_RETRY_TIMEOUT:Number = 1200000; // 20 minutes + private const DEFAULT_BUFFER_TIME:Number = 3; + private const DEFAULT_MBR_BUFFER_TIME:Number = 8; + + CONFIG::LOGGING + { + private static const logger:org.osmf.logging.Logger = + org.osmf.logging.Log.getLogger("com.akamai.osmf.net.AkamaiNetStream"); + } + } +} diff --git a/lib/osmf/samples/AkamaiBasicStreamingPluginIntegrationTest/.actionScriptProperties b/lib/osmf/samples/AkamaiBasicStreamingPluginIntegrationTest/.actionScriptProperties index 20297fd..b7b8fd9 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPluginIntegrationTest/.actionScriptProperties +++ b/lib/osmf/samples/AkamaiBasicStreamingPluginIntegrationTest/.actionScriptProperties @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/AkamaiBasicStreamingPluginIntegrationTest/.flexProperties b/lib/osmf/samples/AkamaiBasicStreamingPluginIntegrationTest/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/AkamaiBasicStreamingPluginIntegrationTest/.flexProperties +++ b/lib/osmf/samples/AkamaiBasicStreamingPluginIntegrationTest/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/AkamaiSample/.actionScriptProperties b/lib/osmf/samples/AkamaiSample/.actionScriptProperties index c4eeaa1..1205d31 100644 --- a/lib/osmf/samples/AkamaiSample/.actionScriptProperties +++ b/lib/osmf/samples/AkamaiSample/.actionScriptProperties @@ -1,53 +1,53 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/AkamaiSample/.flexProperties b/lib/osmf/samples/AkamaiSample/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/AkamaiSample/.flexProperties +++ b/lib/osmf/samples/AkamaiSample/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/AkamaiSample/AkamaiPluginSample-build-config.xml b/lib/osmf/samples/AkamaiSample/AkamaiPluginSample-build-config.xml index c8c98f4..6c295c3 100644 --- a/lib/osmf/samples/AkamaiSample/AkamaiPluginSample-build-config.xml +++ b/lib/osmf/samples/AkamaiSample/AkamaiPluginSample-build-config.xml @@ -29,8 +29,8 @@ - @@ -44,10 +44,10 @@ true - @@ -138,11 +138,11 @@ - @@ -150,8 +150,8 @@ - @@ -170,13 +170,13 @@ - @@ -187,12 +187,12 @@ flash.fonts.CFFFontManager - @@ -324,19 +324,19 @@ halo - - - @@ -344,10 +344,10 @@ true - - diff --git a/lib/osmf/samples/AkamaiSample/html-template/AC_OETags.js b/lib/osmf/samples/AkamaiSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/AkamaiSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/AkamaiSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '

'; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
'; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/AkamaiSample/html-template/history/historyFrame.html b/lib/osmf/samples/AkamaiSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/AkamaiSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/AkamaiSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/AkamaiSample/html-template/index.template.html b/lib/osmf/samples/AkamaiSample/html-template/index.template.html index 9ec96e1..30e79fd 100644 --- a/lib/osmf/samples/AkamaiSample/html-template/index.template.html +++ b/lib/osmf/samples/AkamaiSample/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/AkamaiSample/src/AkamaiPluginSample.css b/lib/osmf/samples/AkamaiSample/src/AkamaiPluginSample.css index 8207cae..223fad1 100644 --- a/lib/osmf/samples/AkamaiSample/src/AkamaiPluginSample.css +++ b/lib/osmf/samples/AkamaiSample/src/AkamaiPluginSample.css @@ -1,104 +1,104 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -@namespace mx "library://ns.adobe.com/flex/mx"; - -@font-face { - src: local("Verdana"); - embedAsCFF: false; - fontFamily: "Verdana"; - unicodeRange:'U+0020-U+007E'; -} - -@font-face { - src: local("Verdana"); - embedAsCFF: false; - fontFamily: "Verdana"; - fontWeight: bold; - unicodeRange:'U+0020-U+007E'; -} - -global { - color: #FFFFFF; - fontFamily: "Verdana"; - fontSize: 11px; - fontWeight: normal; -} - -.title { - fontSize: 20px; - fontWeight: normal; -} - -.timeCode { - fontSize: 10px; - color: #999999; -} - -.error { - fontSize: 10px; - color: #FF1111; -} - -mx|Label { - fontSize: 10px; - color: #aaaaaa; -} - -mx|ComboBox { - color: #333333; - themeColor: "haloSilver"; -} - -mx|Button { - themeColor: "haloSilver"; -} - -mx|RadioButton { - themeColor: "haloSilver"; -} - -mx|TextInput { - color: #000000; -} - -mx|TextArea { - color: #111111; - disabledColor: #111111; -} - -mx|HSlider { - themeColor: "haloSilver"; - dataTipStyleName: "dataTip"; - dataTipOffset: 6; -} - -mx|TileList { - themeColor: "haloSilver"; - backgroundColor: #000000; - color: #111111; - borderColor: #111111; -} - -.dataTip { - backgroundColor: black; -} - +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +@namespace mx "library://ns.adobe.com/flex/mx"; + +@font-face { + src: local("Verdana"); + embedAsCFF: false; + fontFamily: "Verdana"; + unicodeRange:'U+0020-U+007E'; +} + +@font-face { + src: local("Verdana"); + embedAsCFF: false; + fontFamily: "Verdana"; + fontWeight: bold; + unicodeRange:'U+0020-U+007E'; +} + +global { + color: #FFFFFF; + fontFamily: "Verdana"; + fontSize: 11px; + fontWeight: normal; +} + +.title { + fontSize: 20px; + fontWeight: normal; +} + +.timeCode { + fontSize: 10px; + color: #999999; +} + +.error { + fontSize: 10px; + color: #FF1111; +} + +mx|Label { + fontSize: 10px; + color: #aaaaaa; +} + +mx|ComboBox { + color: #333333; + themeColor: "haloSilver"; +} + +mx|Button { + themeColor: "haloSilver"; +} + +mx|RadioButton { + themeColor: "haloSilver"; +} + +mx|TextInput { + color: #000000; +} + +mx|TextArea { + color: #111111; + disabledColor: #111111; +} + +mx|HSlider { + themeColor: "haloSilver"; + dataTipStyleName: "dataTip"; + dataTipOffset: 6; +} + +mx|TileList { + themeColor: "haloSilver"; + backgroundColor: #000000; + color: #111111; + borderColor: #111111; +} + +.dataTip { + backgroundColor: black; +} + diff --git a/lib/osmf/samples/AkamaiSample/src/AkamaiPluginSample.mxml b/lib/osmf/samples/AkamaiSample/src/AkamaiPluginSample.mxml index 2dfd655..846238f 100644 --- a/lib/osmf/samples/AkamaiSample/src/AkamaiPluginSample.mxml +++ b/lib/osmf/samples/AkamaiSample/src/AkamaiPluginSample.mxml @@ -1,861 +1,861 @@ - - - - - - - = feed.entries; - - // Build the playlist UI - for each (var entry:Entry in entries) - { - var playlistItem:PlaylistItem = new PlaylistItem(entry); - playlist.addItem(playlistItem); - } - - if (tileList.dataProvider == null) - { - tileList.dataProvider = playlist; - } - tileList.selectedIndex = 0; - playSelectedPlaylistItem(); - } - - private function playSelectedPlaylistItem():void - { - var playlistItem:PlaylistItem = tileList.selectedItem as PlaylistItem; - var metadata:Metadata; - - if (MASTPluginLoaded) - { - metadata = createMASTMetadata(); - } - - var mediaGenerator:AkamaiSyndicationMediaGenerator = - new AkamaiSyndicationMediaGenerator(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata, mediaFactory); - - setupMediaElementListeners(false); - mediaElement = mediaGenerator.createMediaElement(playlistItem.entry); - setupMediaElementListeners(); - playMediaElement(); - } - - private function setupMediaElementListeners(add:Boolean=true):void - { - if (mediaElement == null) - { - return; - } - - if (add) - { - // Listen for traits to be added, so we can adjust the UI. For example, enable the seek bar - // when the seekable trait is added - mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - mediaElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); - mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - if (loadTrait != null) - { - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onMediaLoadStateChange); - - } - } - else - { - mediaElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - mediaElement.removeEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); - mediaElement.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - } - } - - private function playMediaElement():void - { - setMediaElement(mediaElement); - } - - private function setMediaElement(value:MediaElement):void - { - if (mediaPlayer.media != null) - { - mediaContainerUIComponent.container.removeMediaElement(mediaPlayer.media); - } - - if (value != null) - { - mediaContainerUIComponent.container.addMediaElement(value); - } - - mediaPlayer.media = value; - } - - private function unloadMedia():void - { - setMediaElement(null); - - setupMediaElementListeners(false); - mediaElement = null; - enablePlayerControls(false); - clearPlaylist(); - } - - private function clearPlaylist():void - { - playlist.removeAll(); - } - - private function loadPlugin(source:String):void - { - var pluginResource:MediaResourceBase; - - if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file") - { - // This is a URL, create a URLResource - pluginResource = new URLResource(source); - } - else - { - // Assume this is a class - var pluginInfoRef:Class = flash.utils.getDefinitionByName(source) as Class; - pluginResource = new PluginInfoResource(new pluginInfoRef); - } - - if (pluginResourceMap == null) - { - pluginResourceMap = new Dictionary(); - } - - pluginResourceMap[source] = pluginResource; - loadPluginFromResource(pluginResource); - } - - private function loadPluginFromResource(pluginResource:MediaResourceBase):void - { - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); - mediaFactory.loadPlugin(pluginResource); - } - - private function onPluginLoaded(event:MediaFactoryEvent):void - { - var selection:Object = cbPlugin.selectedItem; - appendInfoText("Plugin LOADED: " + selection.label); - removeMediaFactoryEventListeners(); - } - - private function onPluginLoadFailed(event:MediaFactoryEvent):void - { - var selection:Object = cbPlugin.selectedItem; - appendInfoText("Plugin LOAD FAILED: " + selection.label); - removeMediaFactoryEventListeners(); - } - - private function removeMediaFactoryEventListeners():void - { - mediaFactory.removeEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); - mediaFactory.removeEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); - } - - private function pluginComboBoxChanged(event:DropdownEvent):void - { - var cb:ComboBox = event.currentTarget as ComboBox; - var selection:Object = cb.selectedItem; - - urlInput.text = selection.url; - } - - private function urlComboBoxChanged(event:Event):void - { - var cb:ComboBox = event.currentTarget as ComboBox; - var selection:Object = cb.selectedItem; - - mediaInput.text = selection.url; - } - - private function onMediaSizeChange(event:DisplayObjectEvent):void - { - var width:int = event.newWidth; - var height:int = event.newHeight; - - // Scale to native or smaller - if (width > MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) - { - if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) - { - mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; - mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); - } - else - { - mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); - mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; - } - } - else if (width > 0 && height > 0) - { - mediaContainerUIComponent.width = event.newWidth; - mediaContainerUIComponent.height = event.newHeight; - } - } - - private function onDurationChange(event:TimeEvent):void - { - seekBar.maximum = event.time; - lblDuration.text = TimeUtil.formatAsTimeCode(event.time); - } - - private function onCurrentTimeChange(event:TimeEvent):void - { - if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) - { - seekBar.value = event.time; - lblPlayhead.text = TimeUtil.formatAsTimeCode(event.time); - - if (bufferTrait) - { - currentBufferLength = bufferTrait.bufferLength; - } - } - } - - private function onMediaComplete(event:TimeEvent):void - { - if (event.type == TimeEvent.COMPLETE) - { - if (playlist.length) - { - var newIndex:int = (tileList.selectedIndex == (playlist.length - 1)) ? 0 : tileList.selectedIndex + 1; - tileList.selectedIndex = newIndex; - tileList.scrollToIndex(newIndex); - playSelectedPlaylistItem(); - } - else if (isLive) - { - // Handle the case where the primary and secondary encoders crashed - this.mediaPlayer.play(); - } - } - } - - private function onMediaLoadStateChange(event:LoadEvent):void - { - var loadTrait:NetStreamLoadTrait; - - switch(event.loadState) - { - case LoadState.READY: - appendInfoText("Media loaded."); - break; - case LoadState.UNLOADING: - appendInfoText("Media unloaded."); - break; - } - } - - private function onSeekingChange(event:SeekEvent):void - { - if (event.seeking == false) - { - waitForSeek = false; - } - } - - private function toggleDragging(state:Boolean):void - { - sliderDragging = state; - if (!state) - { - waitForSeek = true; - if (mediaPlayer.canSeek) - { - mediaPlayer.seek(seekBar.value); - } - } - } - - private function onTraitAdd(event:MediaElementEvent):void - { - switch (event.traitType) - { - case MediaTraitType.SEEK: - seekBar.enabled = seekBar.visible = true; - break; - case MediaTraitType.DYNAMIC_STREAM: - var dsTrait:DynamicStreamTrait = (event.target as MediaElement).getTrait(event.traitType) as DynamicStreamTrait; - setupSwitchingChangeListener(dsTrait); - break; - case MediaTraitType.TIME: - var timeTrait:TimeTrait = (event.target as MediaElement).getTrait(event.traitType) as TimeTrait; - timeTrait.addEventListener(TimeEvent.COMPLETE, onMediaComplete); - break; - case MediaTraitType.LOAD: - var loadTrait:LoadTrait = (event.target as MediaElement).getTrait(event.traitType) as LoadTrait; - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onMediaLoadStateChange); - break; - case MediaTraitType.BUFFER: - bufferTrait = (event.target as MediaElement).getTrait(MediaTraitType.BUFFER) as BufferTrait; - // For experimentation purposes. If you'd like to set a custom buffer length, here is how - // to do it: - //bufferTrait.bufferTime = 3; - break; - } - } - - private function onTraitRemove(event:MediaElementEvent):void - { - switch (event.traitType) - { - case MediaTraitType.SEEK: - seekBar.enabled = seekBar.visible = false; - break; - case MediaTraitType.DYNAMIC_STREAM: - var dsTrait:DynamicStreamTrait = (event.target as MediaElement).getTrait(event.traitType) as DynamicStreamTrait; - setupSwitchingChangeListener(dsTrait, false); - break; - case MediaTraitType.TIME: - var timeTrait:TimeTrait = (event.target as MediaElement).getTrait(event.traitType) as TimeTrait; - timeTrait.removeEventListener(TimeEvent.COMPLETE, onMediaComplete); - break; - case MediaTraitType.LOAD: - var loadTrait:LoadTrait = (event.target as MediaElement).getTrait(event.traitType) as LoadTrait; - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onMediaLoadStateChange); - break; - } - } - - private function setupSwitchingChangeListener(dsTrait:DynamicStreamTrait, add:Boolean=true):void - { - if (add) - { - dsTrait.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, onSwitchingChange); - } - else - { - dsTrait.removeEventListener(DynamicStreamEvent.SWITCHING_CHANGE, onSwitchingChange); - } - } - - private function onSwitchingChange(event:DynamicStreamEvent):void - { - var dsTrait:DynamicStreamTrait = event.target as DynamicStreamTrait; - var msg:String = "Switching change " - var showCurrentIndex:Boolean = false; - - if (event.switching) - { - msg += "REQUESTED"; - } - else - { - msg += "COMPLETE"; - showCurrentIndex = true; - } - - appendInfoText(msg); - - if (showCurrentIndex) - { - var streamMsg:String = "Current streaming profile index: " + dsTrait.currentIndex + " of " + dsTrait.maxAllowedIndex; - appendInfoText(streamMsg); - - streamMsg = "Current bitrate = " + dsTrait.getBitrateForIndex(dsTrait.currentIndex) + "kbps"; - appendInfoText(streamMsg); - } - } - - private function onCanPauseChange(event:PlayEvent):void - { - playBtn.enabled = event.canPause; - } - - private function onPlayStateChange(event:PlayEvent):void - { - if (event.playState == PlayState.PLAYING) - { - enablePlayerControls(); - } - } - - private function appendInfoText(...args):void - { - var lineNum:int = currentInfoLineNum++; - - if (taInfo.text.length) - { - taInfo.text += "\n"; - } - - taInfo.text += lineNum + ":" + args; - callLater(autoScrollInfoText); - } - - private function clearInfoText():void - { - taInfo.text = ""; - currentInfoLineNum = 1; - } - - private function autoScrollInfoText():void - { - taInfo.verticalScrollPosition = taInfo.maxVerticalScrollPosition; - } - - private function onMediaError(event:MediaErrorEvent):void - { - var msg:String = "ERROR : error ID="+event.error.errorID; - - if (event.error.message != null && event.error.message.length > 0) - { - msg += " message="+event.error.message; - } - if (event.error.detail != null && event.error.detail.length > 0) - { - msg += " detail=" + event.error.detail; - } - - appendInfoText(msg); - } - - private function onClickPlayBtn():void - { - if (mediaPlayer.playing) - { - playBtn.label = "Play"; - mediaPlayer.pause(); - } - else if (mediaPlayer.paused && mediaPlayer.canPlay) - { - playBtn.label = "Pause"; - mediaPlayer.play(); - } - } - - private function enablePlayerControls(enable:Boolean=true):void - { - playBtn.enabled = (mediaPlayer != null) ? mediaPlayer.canPause : enable; - mediaContainerHolder.alpha = (enable ? 1.0 : .33); - - currentBufferLength = NaN; - } - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + = feed.entries; + + // Build the playlist UI + for each (var entry:Entry in entries) + { + var playlistItem:PlaylistItem = new PlaylistItem(entry); + playlist.addItem(playlistItem); + } + + if (tileList.dataProvider == null) + { + tileList.dataProvider = playlist; + } + tileList.selectedIndex = 0; + playSelectedPlaylistItem(); + } + + private function playSelectedPlaylistItem():void + { + var playlistItem:PlaylistItem = tileList.selectedItem as PlaylistItem; + var metadata:Metadata; + + if (MASTPluginLoaded) + { + metadata = createMASTMetadata(); + } + + var mediaGenerator:AkamaiSyndicationMediaGenerator = + new AkamaiSyndicationMediaGenerator(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata, mediaFactory); + + setupMediaElementListeners(false); + mediaElement = mediaGenerator.createMediaElement(playlistItem.entry); + setupMediaElementListeners(); + playMediaElement(); + } + + private function setupMediaElementListeners(add:Boolean=true):void + { + if (mediaElement == null) + { + return; + } + + if (add) + { + // Listen for traits to be added, so we can adjust the UI. For example, enable the seek bar + // when the seekable trait is added + mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + mediaElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); + mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + if (loadTrait != null) + { + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onMediaLoadStateChange); + + } + } + else + { + mediaElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + mediaElement.removeEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); + mediaElement.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + } + } + + private function playMediaElement():void + { + setMediaElement(mediaElement); + } + + private function setMediaElement(value:MediaElement):void + { + if (mediaPlayer.media != null) + { + mediaContainerUIComponent.container.removeMediaElement(mediaPlayer.media); + } + + if (value != null) + { + mediaContainerUIComponent.container.addMediaElement(value); + } + + mediaPlayer.media = value; + } + + private function unloadMedia():void + { + setMediaElement(null); + + setupMediaElementListeners(false); + mediaElement = null; + enablePlayerControls(false); + clearPlaylist(); + } + + private function clearPlaylist():void + { + playlist.removeAll(); + } + + private function loadPlugin(source:String):void + { + var pluginResource:MediaResourceBase; + + if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file") + { + // This is a URL, create a URLResource + pluginResource = new URLResource(source); + } + else + { + // Assume this is a class + var pluginInfoRef:Class = flash.utils.getDefinitionByName(source) as Class; + pluginResource = new PluginInfoResource(new pluginInfoRef); + } + + if (pluginResourceMap == null) + { + pluginResourceMap = new Dictionary(); + } + + pluginResourceMap[source] = pluginResource; + loadPluginFromResource(pluginResource); + } + + private function loadPluginFromResource(pluginResource:MediaResourceBase):void + { + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); + mediaFactory.loadPlugin(pluginResource); + } + + private function onPluginLoaded(event:MediaFactoryEvent):void + { + var selection:Object = cbPlugin.selectedItem; + appendInfoText("Plugin LOADED: " + selection.label); + removeMediaFactoryEventListeners(); + } + + private function onPluginLoadFailed(event:MediaFactoryEvent):void + { + var selection:Object = cbPlugin.selectedItem; + appendInfoText("Plugin LOAD FAILED: " + selection.label); + removeMediaFactoryEventListeners(); + } + + private function removeMediaFactoryEventListeners():void + { + mediaFactory.removeEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); + mediaFactory.removeEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); + } + + private function pluginComboBoxChanged(event:DropdownEvent):void + { + var cb:ComboBox = event.currentTarget as ComboBox; + var selection:Object = cb.selectedItem; + + urlInput.text = selection.url; + } + + private function urlComboBoxChanged(event:Event):void + { + var cb:ComboBox = event.currentTarget as ComboBox; + var selection:Object = cb.selectedItem; + + mediaInput.text = selection.url; + } + + private function onMediaSizeChange(event:DisplayObjectEvent):void + { + var width:int = event.newWidth; + var height:int = event.newHeight; + + // Scale to native or smaller + if (width > MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) + { + if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) + { + mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; + mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); + } + else + { + mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); + mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; + } + } + else if (width > 0 && height > 0) + { + mediaContainerUIComponent.width = event.newWidth; + mediaContainerUIComponent.height = event.newHeight; + } + } + + private function onDurationChange(event:TimeEvent):void + { + seekBar.maximum = event.time; + lblDuration.text = TimeUtil.formatAsTimeCode(event.time); + } + + private function onCurrentTimeChange(event:TimeEvent):void + { + if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) + { + seekBar.value = event.time; + lblPlayhead.text = TimeUtil.formatAsTimeCode(event.time); + + if (bufferTrait) + { + currentBufferLength = bufferTrait.bufferLength; + } + } + } + + private function onMediaComplete(event:TimeEvent):void + { + if (event.type == TimeEvent.COMPLETE) + { + if (playlist.length) + { + var newIndex:int = (tileList.selectedIndex == (playlist.length - 1)) ? 0 : tileList.selectedIndex + 1; + tileList.selectedIndex = newIndex; + tileList.scrollToIndex(newIndex); + playSelectedPlaylistItem(); + } + else if (isLive) + { + // Handle the case where the primary and secondary encoders crashed + this.mediaPlayer.play(); + } + } + } + + private function onMediaLoadStateChange(event:LoadEvent):void + { + var loadTrait:NetStreamLoadTrait; + + switch(event.loadState) + { + case LoadState.READY: + appendInfoText("Media loaded."); + break; + case LoadState.UNLOADING: + appendInfoText("Media unloaded."); + break; + } + } + + private function onSeekingChange(event:SeekEvent):void + { + if (event.seeking == false) + { + waitForSeek = false; + } + } + + private function toggleDragging(state:Boolean):void + { + sliderDragging = state; + if (!state) + { + waitForSeek = true; + if (mediaPlayer.canSeek) + { + mediaPlayer.seek(seekBar.value); + } + } + } + + private function onTraitAdd(event:MediaElementEvent):void + { + switch (event.traitType) + { + case MediaTraitType.SEEK: + seekBar.enabled = seekBar.visible = true; + break; + case MediaTraitType.DYNAMIC_STREAM: + var dsTrait:DynamicStreamTrait = (event.target as MediaElement).getTrait(event.traitType) as DynamicStreamTrait; + setupSwitchingChangeListener(dsTrait); + break; + case MediaTraitType.TIME: + var timeTrait:TimeTrait = (event.target as MediaElement).getTrait(event.traitType) as TimeTrait; + timeTrait.addEventListener(TimeEvent.COMPLETE, onMediaComplete); + break; + case MediaTraitType.LOAD: + var loadTrait:LoadTrait = (event.target as MediaElement).getTrait(event.traitType) as LoadTrait; + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onMediaLoadStateChange); + break; + case MediaTraitType.BUFFER: + bufferTrait = (event.target as MediaElement).getTrait(MediaTraitType.BUFFER) as BufferTrait; + // For experimentation purposes. If you'd like to set a custom buffer length, here is how + // to do it: + //bufferTrait.bufferTime = 3; + break; + } + } + + private function onTraitRemove(event:MediaElementEvent):void + { + switch (event.traitType) + { + case MediaTraitType.SEEK: + seekBar.enabled = seekBar.visible = false; + break; + case MediaTraitType.DYNAMIC_STREAM: + var dsTrait:DynamicStreamTrait = (event.target as MediaElement).getTrait(event.traitType) as DynamicStreamTrait; + setupSwitchingChangeListener(dsTrait, false); + break; + case MediaTraitType.TIME: + var timeTrait:TimeTrait = (event.target as MediaElement).getTrait(event.traitType) as TimeTrait; + timeTrait.removeEventListener(TimeEvent.COMPLETE, onMediaComplete); + break; + case MediaTraitType.LOAD: + var loadTrait:LoadTrait = (event.target as MediaElement).getTrait(event.traitType) as LoadTrait; + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onMediaLoadStateChange); + break; + } + } + + private function setupSwitchingChangeListener(dsTrait:DynamicStreamTrait, add:Boolean=true):void + { + if (add) + { + dsTrait.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, onSwitchingChange); + } + else + { + dsTrait.removeEventListener(DynamicStreamEvent.SWITCHING_CHANGE, onSwitchingChange); + } + } + + private function onSwitchingChange(event:DynamicStreamEvent):void + { + var dsTrait:DynamicStreamTrait = event.target as DynamicStreamTrait; + var msg:String = "Switching change " + var showCurrentIndex:Boolean = false; + + if (event.switching) + { + msg += "REQUESTED"; + } + else + { + msg += "COMPLETE"; + showCurrentIndex = true; + } + + appendInfoText(msg); + + if (showCurrentIndex) + { + var streamMsg:String = "Current streaming profile index: " + dsTrait.currentIndex + " of " + dsTrait.maxAllowedIndex; + appendInfoText(streamMsg); + + streamMsg = "Current bitrate = " + dsTrait.getBitrateForIndex(dsTrait.currentIndex) + "kbps"; + appendInfoText(streamMsg); + } + } + + private function onCanPauseChange(event:PlayEvent):void + { + playBtn.enabled = event.canPause; + } + + private function onPlayStateChange(event:PlayEvent):void + { + if (event.playState == PlayState.PLAYING) + { + enablePlayerControls(); + } + } + + private function appendInfoText(...args):void + { + var lineNum:int = currentInfoLineNum++; + + if (taInfo.text.length) + { + taInfo.text += "\n"; + } + + taInfo.text += lineNum + ":" + args; + callLater(autoScrollInfoText); + } + + private function clearInfoText():void + { + taInfo.text = ""; + currentInfoLineNum = 1; + } + + private function autoScrollInfoText():void + { + taInfo.verticalScrollPosition = taInfo.maxVerticalScrollPosition; + } + + private function onMediaError(event:MediaErrorEvent):void + { + var msg:String = "ERROR : error ID="+event.error.errorID; + + if (event.error.message != null && event.error.message.length > 0) + { + msg += " message="+event.error.message; + } + if (event.error.detail != null && event.error.detail.length > 0) + { + msg += " detail=" + event.error.detail; + } + + appendInfoText(msg); + } + + private function onClickPlayBtn():void + { + if (mediaPlayer.playing) + { + playBtn.label = "Play"; + mediaPlayer.pause(); + } + else if (mediaPlayer.paused && mediaPlayer.canPlay) + { + playBtn.label = "Pause"; + mediaPlayer.play(); + } + } + + private function enablePlayerControls(enable:Boolean=true):void + { + playBtn.enabled = (mediaPlayer != null) ? mediaPlayer.canPause : enable; + mediaContainerHolder.alpha = (enable ? 1.0 : .33); + + currentBufferLength = NaN; + } + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/AkamaiSample/src/com/akamai/osmf/samples/AkamaiSyndicationMediaGenerator.as b/lib/osmf/samples/AkamaiSample/src/com/akamai/osmf/samples/AkamaiSyndicationMediaGenerator.as index f108afd..b4297c0 100644 --- a/lib/osmf/samples/AkamaiSample/src/com/akamai/osmf/samples/AkamaiSyndicationMediaGenerator.as +++ b/lib/osmf/samples/AkamaiSample/src/com/akamai/osmf/samples/AkamaiSyndicationMediaGenerator.as @@ -1,64 +1,64 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package com.akamai.osmf.samples -{ - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.syndication.media.SyndicationMediaGenerator; - import org.osmf.syndication.model.Entry; - - /** - * This is an example of a custom syndication media generator. - * The purpose of this class is to allow us to add metadata on - * the resource for a MediaElement. - **/ - public class AkamaiSyndicationMediaGenerator extends SyndicationMediaGenerator - { - public function AkamaiSyndicationMediaGenerator(namespaceURL:String, metadata:Metadata, mediaFactory:MediaFactory=null) - { - super(mediaFactory); - - this.namespaceURL = namespaceURL; - this.metadata = metadata; - } - - override public function createMediaElement(entry:Entry):MediaElement - { - var mediaElement:MediaElement; - var resource:URLResource = new URLResource(entry.enclosure.url); - - if (metadata) - { - resource.addMetadataValue(namespaceURL, metadata); - } - - mediaElement = mediaFactory.createMediaElement(resource); - return mediaElement; - } - - private var namespaceURL:String; - private var metadata:Metadata; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package com.akamai.osmf.samples +{ + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.syndication.media.SyndicationMediaGenerator; + import org.osmf.syndication.model.Entry; + + /** + * This is an example of a custom syndication media generator. + * The purpose of this class is to allow us to add metadata on + * the resource for a MediaElement. + **/ + public class AkamaiSyndicationMediaGenerator extends SyndicationMediaGenerator + { + public function AkamaiSyndicationMediaGenerator(namespaceURL:String, metadata:Metadata, mediaFactory:MediaFactory=null) + { + super(mediaFactory); + + this.namespaceURL = namespaceURL; + this.metadata = metadata; + } + + override public function createMediaElement(entry:Entry):MediaElement + { + var mediaElement:MediaElement; + var resource:URLResource = new URLResource(entry.enclosure.url); + + if (metadata) + { + resource.addMetadataValue(namespaceURL, metadata); + } + + mediaElement = mediaFactory.createMediaElement(resource); + return mediaElement; + } + + private var namespaceURL:String; + private var metadata:Metadata; + } +} diff --git a/lib/osmf/samples/AkamaiSample/src/com/akamai/osmf/samples/PlaylistItem.as b/lib/osmf/samples/AkamaiSample/src/com/akamai/osmf/samples/PlaylistItem.as index e260e91..5f83eae 100644 --- a/lib/osmf/samples/AkamaiSample/src/com/akamai/osmf/samples/PlaylistItem.as +++ b/lib/osmf/samples/AkamaiSample/src/com/akamai/osmf/samples/PlaylistItem.as @@ -1,80 +1,80 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package com.akamai.osmf.samples -{ - import org.osmf.syndication.model.Entry; - import org.osmf.syndication.model.extensions.FeedExtension; - import org.osmf.syndication.model.extensions.mrss.MediaRSSExtension; - import org.osmf.syndication.model.extensions.mrss.MediaRSSThumbnail; - import org.osmf.syndication.model.rss20.RSSItem; - - public class PlaylistItem - { - public function PlaylistItem(entry:Entry):void - { - _entry = entry; - } - - public function get title():String - { - return entry.title.text; - } - - public function get thumbnail():MediaRSSThumbnail - { - return getRSSThumbnail(); - } - - public function get entry():Entry - { - return _entry; - } - - private function getRSSThumbnail():MediaRSSThumbnail - { - var thumbnail:MediaRSSThumbnail; - - // Get the RSS item - var rssItem:RSSItem = entry as RSSItem; - if (rssItem != null) - { - // Check for feed extenstions - for each (var feedExtension:FeedExtension in rssItem.feedExtensions) - { - var mrssExtension:MediaRSSExtension = feedExtension as MediaRSSExtension; - if (mrssExtension == null) - { - continue; - } - - // There could be multiple thumbnails so we'll pick the first one - var thumbnails:Vector. = mrssExtension.thumbnails; - thumbnail = thumbnails[0]; - break; - } - } - return thumbnail; - } - - private var _entry:Entry; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package com.akamai.osmf.samples +{ + import org.osmf.syndication.model.Entry; + import org.osmf.syndication.model.extensions.FeedExtension; + import org.osmf.syndication.model.extensions.mrss.MediaRSSExtension; + import org.osmf.syndication.model.extensions.mrss.MediaRSSThumbnail; + import org.osmf.syndication.model.rss20.RSSItem; + + public class PlaylistItem + { + public function PlaylistItem(entry:Entry):void + { + _entry = entry; + } + + public function get title():String + { + return entry.title.text; + } + + public function get thumbnail():MediaRSSThumbnail + { + return getRSSThumbnail(); + } + + public function get entry():Entry + { + return _entry; + } + + private function getRSSThumbnail():MediaRSSThumbnail + { + var thumbnail:MediaRSSThumbnail; + + // Get the RSS item + var rssItem:RSSItem = entry as RSSItem; + if (rssItem != null) + { + // Check for feed extenstions + for each (var feedExtension:FeedExtension in rssItem.feedExtensions) + { + var mrssExtension:MediaRSSExtension = feedExtension as MediaRSSExtension; + if (mrssExtension == null) + { + continue; + } + + // There could be multiple thumbnails so we'll pick the first one + var thumbnails:Vector. = mrssExtension.thumbnails; + thumbnail = thumbnails[0]; + break; + } + } + return thumbnail; + } + + private var _entry:Entry; + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/.actionScriptProperties b/lib/osmf/samples/CaptioningPlugin/.actionScriptProperties index bbaa00f..7494f53 100644 --- a/lib/osmf/samples/CaptioningPlugin/.actionScriptProperties +++ b/lib/osmf/samples/CaptioningPlugin/.actionScriptProperties @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/CaptioningPlugin/src/CaptioningPlugin.as b/lib/osmf/samples/CaptioningPlugin/src/CaptioningPlugin.as index 1517543..9971d82 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/CaptioningPlugin.as +++ b/lib/osmf/samples/CaptioningPlugin/src/CaptioningPlugin.as @@ -1,67 +1,67 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - - import org.osmf.captioning.CaptioningPluginInfo; - import org.osmf.media.PluginInfo; - - /** - * The root level object of the Caption Plugin. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class CaptioningPlugin extends Sprite - { - /** - * Constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function CaptioningPlugin() - { - _pluginInfo = new CaptioningPluginInfo(); - } - - /** - * Gives the player the PluginInfo. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get pluginInfo():PluginInfo - { - return _pluginInfo; - } - - private var _pluginInfo:CaptioningPluginInfo; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + + import org.osmf.captioning.CaptioningPluginInfo; + import org.osmf.media.PluginInfo; + + /** + * The root level object of the Caption Plugin. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class CaptioningPlugin extends Sprite + { + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function CaptioningPlugin() + { + _pluginInfo = new CaptioningPluginInfo(); + } + + /** + * Gives the player the PluginInfo. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get pluginInfo():PluginInfo + { + return _pluginInfo; + } + + private var _pluginInfo:CaptioningPluginInfo; + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/CaptioningPluginInfo.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/CaptioningPluginInfo.as index 1333e9b..10e8fed 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/CaptioningPluginInfo.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/CaptioningPluginInfo.as @@ -1,77 +1,77 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning -{ - import __AS3__.vec.Vector; - - import org.osmf.captioning.media.CaptioningProxyElement; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.MediaFactoryItemType; - import org.osmf.media.PluginInfo; - import org.osmf.net.NetLoader; - - /** - * Encapsulation of a Captioning plugin. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class CaptioningPluginInfo extends PluginInfo - { - // Constants for specifying the Timed Text document URL on the resource metadata - public static const CAPTIONING_METADATA_NAMESPACE:String = "http://www.osmf.org/captioning/1.0"; - public static const CAPTIONING_METADATA_KEY_URI:String = "uri"; - - // Constants for the temporal metadata (captions) - public static const CAPTIONING_TEMPORAL_METADATA_NAMESPACE:String = "http://www.osmf.org/temporal/captioning"; - - /** - * Constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function CaptioningPluginInfo() - { - var items:Vector. = new Vector.(); - - var loader:NetLoader = new NetLoader(); - var item:MediaFactoryItem = new MediaFactoryItem("org.osmf.captioning.CaptioningPluginInfo", - loader.canHandleResource, - createCaptioningProxyElement, - MediaFactoryItemType.PROXY); - items.push(item); - - super(items); - } - - private function createCaptioningProxyElement():MediaElement - { - return new CaptioningProxyElement(); - } - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning +{ + import __AS3__.vec.Vector; + + import org.osmf.captioning.media.CaptioningProxyElement; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.MediaFactoryItemType; + import org.osmf.media.PluginInfo; + import org.osmf.net.NetLoader; + + /** + * Encapsulation of a Captioning plugin. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class CaptioningPluginInfo extends PluginInfo + { + // Constants for specifying the Timed Text document URL on the resource metadata + public static const CAPTIONING_METADATA_NAMESPACE:String = "http://www.osmf.org/captioning/1.0"; + public static const CAPTIONING_METADATA_KEY_URI:String = "uri"; + + // Constants for the temporal metadata (captions) + public static const CAPTIONING_TEMPORAL_METADATA_NAMESPACE:String = "http://www.osmf.org/temporal/captioning"; + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function CaptioningPluginInfo() + { + var items:Vector. = new Vector.(); + + var loader:NetLoader = new NetLoader(); + var item:MediaFactoryItem = new MediaFactoryItem("org.osmf.captioning.CaptioningPluginInfo", + loader.canHandleResource, + createCaptioningProxyElement, + MediaFactoryItemType.PROXY); + items.push(item); + + super(items); + } + + private function createCaptioningProxyElement():MediaElement + { + return new CaptioningProxyElement(); + } + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/loader/CaptioningLoader.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/loader/CaptioningLoader.as index ed6dc24..2cf9e07 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/loader/CaptioningLoader.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/loader/CaptioningLoader.as @@ -1,213 +1,213 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning.loader -{ - import org.osmf.captioning.model.CaptioningDocument; - import org.osmf.captioning.parsers.DFXPParser; - import org.osmf.captioning.parsers.ICaptioningParser; - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.utils.HTTPLoadTrait; - import org.osmf.utils.HTTPLoader; - - CONFIG::LOGGING - { - import org.osmf.logging.*; - } - - /** - * Loader class for the CaptioningProxyElement. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class CaptioningLoader extends LoaderBase - { - /** - * Constructor. - * - * @param httpLoader The HTTPLoader to be used by this CaptioningLoader - * to retrieve the Timed Text document. If null, a new one will be - * created. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function CaptioningLoader(httpLoader:HTTPLoader=null) - { - super(); - - this.httpLoader = httpLoader != null ? httpLoader : new HTTPLoader(); - } - - /** - * @private - */ - override public function canHandleResource(resource:MediaResourceBase):Boolean - { - return httpLoader.canHandleResource(resource); - } - - /** - * Loads a Timed Text document. - *

Updates the LoadTrait's loadState property to LOADING - * while loading and to READY upon completing a successful load and parse of the - * Timed Text document.

- * - * @see org.osmf.traits.LoadState - * @param loadTrait The LoadTrait to be loaded. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - override protected function executeLoad(loadTrait:LoadTrait):void - { - updateLoadTrait(loadTrait, LoadState.LOADING); - - httpLoader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - - // Create a temporary LoadTrait for this purpose, so that our main - // LoadTrait doesn't reflect any of the state changes from the - // loading of the URL, and so that we can catch any errors. - var httpLoadTrait:HTTPLoadTrait = new HTTPLoadTrait(httpLoader, loadTrait.resource); - - httpLoadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug("Downloading document at " + URLResource(httpLoadTrait.resource).url); - } - } - - httpLoader.load(httpLoadTrait); - - function onHTTPLoaderStateChange(event:LoaderEvent):void - { - if (event.newState == LoadState.READY) - { - // This is a terminal state, so remove all listeners. - httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - var parser:ICaptioningParser = createCaptioningParser(); - var captioningDocument:CaptioningDocument; - - try - { - captioningDocument = parser.parse(httpLoadTrait.urlLoader.data.toString()); - } - catch(e:Error) - { - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug("Error parsing captioning document: " + e.errorID + "-" + e.message); - } - } - updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); - } - - CaptioningLoadTrait(loadTrait).document = captioningDocument; - updateLoadTrait(loadTrait, LoadState.READY); - - } - else if (event.newState == LoadState.LOAD_ERROR) - { - // This is a terminal state, so remove the listener. But - // don't remove the error event listener, as that will be - // removed when the error event for this failure is - // dispatched. - httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug("Error loading captioning document");; - } - } - - updateLoadTrait(loadTrait, event.newState); - } - } - - function onLoadError(event:MediaErrorEvent):void - { - // Only remove this listener, as there will be a corresponding - // event for the load failure. - httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - loadTrait.dispatchEvent(event.clone()); - } - } - - /** - * Unloads the document. - * - *

Updates the LoadTrait's loadState property to UNLOADING - * while unloading and to CONSTRUCTED upon completing a successful unload.

- * - * @param LoadTrait LoadTrait to be unloaded. - * @see org.osmf.traits.LoadState - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - override protected function executeUnload(loadTrait:LoadTrait):void - { - // Nothing to do. - updateLoadTrait(loadTrait, LoadState.UNLOADING); - updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); - } - - /** - * Override to create your own parser. - */ - protected function createCaptioningParser():ICaptioningParser - { - return new DFXPParser(); - } - - private var httpLoader:HTTPLoader; - - CONFIG::LOGGING - { - private static const logger:org.osmf.logging.Logger = org.osmf.logging.Log.getLogger("org.osmf.captioning.loader.CaptioningLoader"); - } - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning.loader +{ + import org.osmf.captioning.model.CaptioningDocument; + import org.osmf.captioning.parsers.DFXPParser; + import org.osmf.captioning.parsers.ICaptioningParser; + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.utils.HTTPLoadTrait; + import org.osmf.utils.HTTPLoader; + + CONFIG::LOGGING + { + import org.osmf.logging.*; + } + + /** + * Loader class for the CaptioningProxyElement. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class CaptioningLoader extends LoaderBase + { + /** + * Constructor. + * + * @param httpLoader The HTTPLoader to be used by this CaptioningLoader + * to retrieve the Timed Text document. If null, a new one will be + * created. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function CaptioningLoader(httpLoader:HTTPLoader=null) + { + super(); + + this.httpLoader = httpLoader != null ? httpLoader : new HTTPLoader(); + } + + /** + * @private + */ + override public function canHandleResource(resource:MediaResourceBase):Boolean + { + return httpLoader.canHandleResource(resource); + } + + /** + * Loads a Timed Text document. + *

Updates the LoadTrait's loadState property to LOADING + * while loading and to READY upon completing a successful load and parse of the + * Timed Text document.

+ * + * @see org.osmf.traits.LoadState + * @param loadTrait The LoadTrait to be loaded. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + override protected function executeLoad(loadTrait:LoadTrait):void + { + updateLoadTrait(loadTrait, LoadState.LOADING); + + httpLoader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + + // Create a temporary LoadTrait for this purpose, so that our main + // LoadTrait doesn't reflect any of the state changes from the + // loading of the URL, and so that we can catch any errors. + var httpLoadTrait:HTTPLoadTrait = new HTTPLoadTrait(httpLoader, loadTrait.resource); + + httpLoadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug("Downloading document at " + URLResource(httpLoadTrait.resource).url); + } + } + + httpLoader.load(httpLoadTrait); + + function onHTTPLoaderStateChange(event:LoaderEvent):void + { + if (event.newState == LoadState.READY) + { + // This is a terminal state, so remove all listeners. + httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + var parser:ICaptioningParser = createCaptioningParser(); + var captioningDocument:CaptioningDocument; + + try + { + captioningDocument = parser.parse(httpLoadTrait.urlLoader.data.toString()); + } + catch(e:Error) + { + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug("Error parsing captioning document: " + e.errorID + "-" + e.message); + } + } + updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); + } + + CaptioningLoadTrait(loadTrait).document = captioningDocument; + updateLoadTrait(loadTrait, LoadState.READY); + + } + else if (event.newState == LoadState.LOAD_ERROR) + { + // This is a terminal state, so remove the listener. But + // don't remove the error event listener, as that will be + // removed when the error event for this failure is + // dispatched. + httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug("Error loading captioning document");; + } + } + + updateLoadTrait(loadTrait, event.newState); + } + } + + function onLoadError(event:MediaErrorEvent):void + { + // Only remove this listener, as there will be a corresponding + // event for the load failure. + httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + loadTrait.dispatchEvent(event.clone()); + } + } + + /** + * Unloads the document. + * + *

Updates the LoadTrait's loadState property to UNLOADING + * while unloading and to CONSTRUCTED upon completing a successful unload.

+ * + * @param LoadTrait LoadTrait to be unloaded. + * @see org.osmf.traits.LoadState + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + override protected function executeUnload(loadTrait:LoadTrait):void + { + // Nothing to do. + updateLoadTrait(loadTrait, LoadState.UNLOADING); + updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); + } + + /** + * Override to create your own parser. + */ + protected function createCaptioningParser():ICaptioningParser + { + return new DFXPParser(); + } + + private var httpLoader:HTTPLoader; + + CONFIG::LOGGING + { + private static const logger:org.osmf.logging.Logger = org.osmf.logging.Log.getLogger("org.osmf.captioning.loader.CaptioningLoader"); + } + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/media/CaptioningProxyElement.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/media/CaptioningProxyElement.as index bbe5812..2ab6796 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/media/CaptioningProxyElement.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/media/CaptioningProxyElement.as @@ -1,206 +1,206 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning.media -{ - import org.osmf.captioning.CaptioningPluginInfo; - import org.osmf.captioning.loader.CaptioningLoadTrait; - import org.osmf.captioning.loader.CaptioningLoader; - import org.osmf.captioning.model.Caption; - import org.osmf.captioning.model.CaptioningDocument; - import org.osmf.elements.ProxyElement; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.metadata.TimelineMetadata; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - - /** - * The CaptioningProxyElement class is a wrapper for the media supplied. - * It's purpose is to override the loadable trait to allow the retrieval and - * processing of an Timed Text file used for captioning. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class CaptioningProxyElement extends ProxyElement - { - /** - * Constant for the MediaError that is triggered when the proxiedElement - * is invalid (e.g. doesn't have the captioning metadata). - **/ - public static const MEDIA_ERROR_INVALID_PROXIED_ELEMENT:int = 2201; - - /** - * Constructor. - * - * @inheritDoc - * - * @param continueLoadOnFailure Specifies whether or not the - * class should continue the load process if the captioning - * document fails to load. The default value is true. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function CaptioningProxyElement(proxiedElement:MediaElement=null, continueLoadOnFailure:Boolean=true) - { - super(proxiedElement); - - _continueLoadOnFailure = continueLoadOnFailure; - } - - /** - * Specifies whether or not this class should continue loading - * the media element when the captioning document - * fails to load. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get continueLoadOnFailure():Boolean - { - return _continueLoadOnFailure; - } - - /** - * @private - */ - override public function set proxiedElement(value:MediaElement):void - { - super.proxiedElement = value; - - if (value != null) - { - // Override the LoadTrait with our own custom LoadTrait, - // which retrieves the Timed Text document, parses it, and sets up - // the object model representing the caption data. - - // Get the Timed Text url resource from the metadata of the element - // that is wrapped. - var mediaElement:MediaElement = super.proxiedElement; - var tempResource:MediaResourceBase = (mediaElement && mediaElement.resource != null) ? mediaElement.resource : resource; - if (tempResource == null) - { - dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, - new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); - } - else - { - var metadata:Metadata = tempResource.getMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE) as Metadata; - if (metadata == null) - { - if (!_continueLoadOnFailure) - { - dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, - new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); - } - } - else - { - var timedTextURL:String = metadata.getValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI); - if (timedTextURL != null) - { - loadTrait = new CaptioningLoadTrait(new CaptioningLoader(), new URLResource(timedTextURL)); - - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange, false, 99); - addTrait(MediaTraitType.LOAD, loadTrait); - } - else if (!_continueLoadOnFailure) - { - dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, - new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); - } - } - } - } - } - - private function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - var document:CaptioningDocument = loadTrait.document; - var mediaElement:MediaElement = super.proxiedElement; - - // Create a TimelineMetadata object to associate the captions with - // the media element. - var captionMetadata:TimelineMetadata = proxiedElement.getMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE) as TimelineMetadata; - if (captionMetadata == null) - { - captionMetadata = new TimelineMetadata(proxiedElement); - proxiedElement.addMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE, captionMetadata); - } - - for (var i:int = 0; i < document.numCaptions; i++) - { - var caption:Caption = document.getCaptionAt(i); - captionMetadata.addMarker(caption); - } - - cleanUp(); - } - else if (event.loadState == LoadState.LOAD_ERROR) - { - if (!_continueLoadOnFailure) - { - dispatchEvent(event.clone()); - } - else - { - cleanUp(); - } - } - } - - private function cleanUp():void - { - // Our work is done, remove the custom LoadTrait. This will - // expose the base LoadTrait, which we can then use to do - // the actual load. - removeTrait(MediaTraitType.LOAD); - - var loadTrait:LoadTrait = getTrait(MediaTraitType.LOAD) as LoadTrait; - if (loadTrait != null && loadTrait.loadState == LoadState.UNINITIALIZED) - { - loadTrait.load(); - } - } - - private var loadTrait:CaptioningLoadTrait; - private var _continueLoadOnFailure:Boolean; - - private static const ERROR_MISSING_CAPTION_METADATA:String = "Media Element is missing Captioning metadata"; - private static const ERROR_MISSING_RESOURCE:String = "Media Element is missing a valid resource"; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning.media +{ + import org.osmf.captioning.CaptioningPluginInfo; + import org.osmf.captioning.loader.CaptioningLoadTrait; + import org.osmf.captioning.loader.CaptioningLoader; + import org.osmf.captioning.model.Caption; + import org.osmf.captioning.model.CaptioningDocument; + import org.osmf.elements.ProxyElement; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.metadata.TimelineMetadata; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + + /** + * The CaptioningProxyElement class is a wrapper for the media supplied. + * It's purpose is to override the loadable trait to allow the retrieval and + * processing of an Timed Text file used for captioning. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class CaptioningProxyElement extends ProxyElement + { + /** + * Constant for the MediaError that is triggered when the proxiedElement + * is invalid (e.g. doesn't have the captioning metadata). + **/ + public static const MEDIA_ERROR_INVALID_PROXIED_ELEMENT:int = 2201; + + /** + * Constructor. + * + * @inheritDoc + * + * @param continueLoadOnFailure Specifies whether or not the + * class should continue the load process if the captioning + * document fails to load. The default value is true. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function CaptioningProxyElement(proxiedElement:MediaElement=null, continueLoadOnFailure:Boolean=true) + { + super(proxiedElement); + + _continueLoadOnFailure = continueLoadOnFailure; + } + + /** + * Specifies whether or not this class should continue loading + * the media element when the captioning document + * fails to load. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get continueLoadOnFailure():Boolean + { + return _continueLoadOnFailure; + } + + /** + * @private + */ + override public function set proxiedElement(value:MediaElement):void + { + super.proxiedElement = value; + + if (value != null) + { + // Override the LoadTrait with our own custom LoadTrait, + // which retrieves the Timed Text document, parses it, and sets up + // the object model representing the caption data. + + // Get the Timed Text url resource from the metadata of the element + // that is wrapped. + var mediaElement:MediaElement = super.proxiedElement; + var tempResource:MediaResourceBase = (mediaElement && mediaElement.resource != null) ? mediaElement.resource : resource; + if (tempResource == null) + { + dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, + new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); + } + else + { + var metadata:Metadata = tempResource.getMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE) as Metadata; + if (metadata == null) + { + if (!_continueLoadOnFailure) + { + dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, + new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); + } + } + else + { + var timedTextURL:String = metadata.getValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI); + if (timedTextURL != null) + { + loadTrait = new CaptioningLoadTrait(new CaptioningLoader(), new URLResource(timedTextURL)); + + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange, false, 99); + addTrait(MediaTraitType.LOAD, loadTrait); + } + else if (!_continueLoadOnFailure) + { + dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, + new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); + } + } + } + } + } + + private function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + var document:CaptioningDocument = loadTrait.document; + var mediaElement:MediaElement = super.proxiedElement; + + // Create a TimelineMetadata object to associate the captions with + // the media element. + var captionMetadata:TimelineMetadata = proxiedElement.getMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE) as TimelineMetadata; + if (captionMetadata == null) + { + captionMetadata = new TimelineMetadata(proxiedElement); + proxiedElement.addMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE, captionMetadata); + } + + for (var i:int = 0; i < document.numCaptions; i++) + { + var caption:Caption = document.getCaptionAt(i); + captionMetadata.addMarker(caption); + } + + cleanUp(); + } + else if (event.loadState == LoadState.LOAD_ERROR) + { + if (!_continueLoadOnFailure) + { + dispatchEvent(event.clone()); + } + else + { + cleanUp(); + } + } + } + + private function cleanUp():void + { + // Our work is done, remove the custom LoadTrait. This will + // expose the base LoadTrait, which we can then use to do + // the actual load. + removeTrait(MediaTraitType.LOAD); + + var loadTrait:LoadTrait = getTrait(MediaTraitType.LOAD) as LoadTrait; + if (loadTrait != null && loadTrait.loadState == LoadState.UNINITIALIZED) + { + loadTrait.load(); + } + } + + private var loadTrait:CaptioningLoadTrait; + private var _continueLoadOnFailure:Boolean; + + private static const ERROR_MISSING_CAPTION_METADATA:String = "Media Element is missing Captioning metadata"; + private static const ERROR_MISSING_RESOURCE:String = "Media Element is missing a valid resource"; + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/Caption.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/Caption.as index 999304f..703b1c7 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/Caption.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/Caption.as @@ -1,160 +1,160 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning.model -{ - import __AS3__.vec.Vector; - - import flash.errors.IllegalOperationError; - - import org.osmf.metadata.TimelineMarker; - import org.osmf.utils.OSMFStrings; - - /** - * Represents a caption, including text and style formatting information, - * as well as when to show the caption and when to hide it. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class Caption extends TimelineMarker - { - /** - * Constructor. - * - * @param id The caption id if supplied (optional). - * @param start The time in seconds the media when the caption should appear. - * @param end The time in seconds the media when the caption should no longer appear. - * @param captionText The caption text to display. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function Caption(id:uint, start:Number, end:Number, captionText:String) - { - var duration:Number = end > 0 ? (end - start) : NaN; - super(start, duration); - - _id = id; - _captionText = captionText; - } - - /** - * Adds a CaptionFormat to this class' internal collection. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function addCaptionFormat(value:CaptionFormat):void - { - if (_formats == null) - { - _formats = new Vector.(); - } - - _formats.push(value); - } - - /** - * Returns the number of CaptionFormat objects in this class' - * internal collection. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get numCaptionFormats():int - { - var num:int = 0; - - if (_formats != null) - { - num = _formats.length; - } - - return num; - } - - /** - * Returns the CaptionFormat object at the index specified. - * - * @throws IllegalOperationError If index argument is out of range. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function getCaptionFormatAt(index:int):CaptionFormat - { - if (_formats == null || index >= _formats.length || index < 0) - { - throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); - } - - return _formats[index]; - } - - /** - * Returns the caption text which will include embedded HTML - * tags. To get the caption text without embedded HTML tags, - * use the clearText property. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get text():String - { - return _captionText; - } - - /** - * Returns the caption text without embedded HTML tags. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get clearText():String - { - var clrTxt:String = ""; - if (_captionText != null && _captionText.length > 0) - { - clrTxt = _captionText.replace(/<(.|\n)*?>/g, ""); - } - return clrTxt; - } - - private var _id:uint; - private var _captionText:String; // The text to display, can contain embedded html tags, such as
- private var _formats:Vector.; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning.model +{ + import __AS3__.vec.Vector; + + import flash.errors.IllegalOperationError; + + import org.osmf.metadata.TimelineMarker; + import org.osmf.utils.OSMFStrings; + + /** + * Represents a caption, including text and style formatting information, + * as well as when to show the caption and when to hide it. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class Caption extends TimelineMarker + { + /** + * Constructor. + * + * @param id The caption id if supplied (optional). + * @param start The time in seconds the media when the caption should appear. + * @param end The time in seconds the media when the caption should no longer appear. + * @param captionText The caption text to display. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function Caption(id:uint, start:Number, end:Number, captionText:String) + { + var duration:Number = end > 0 ? (end - start) : NaN; + super(start, duration); + + _id = id; + _captionText = captionText; + } + + /** + * Adds a CaptionFormat to this class' internal collection. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function addCaptionFormat(value:CaptionFormat):void + { + if (_formats == null) + { + _formats = new Vector.(); + } + + _formats.push(value); + } + + /** + * Returns the number of CaptionFormat objects in this class' + * internal collection. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get numCaptionFormats():int + { + var num:int = 0; + + if (_formats != null) + { + num = _formats.length; + } + + return num; + } + + /** + * Returns the CaptionFormat object at the index specified. + * + * @throws IllegalOperationError If index argument is out of range. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function getCaptionFormatAt(index:int):CaptionFormat + { + if (_formats == null || index >= _formats.length || index < 0) + { + throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); + } + + return _formats[index]; + } + + /** + * Returns the caption text which will include embedded HTML + * tags. To get the caption text without embedded HTML tags, + * use the clearText property. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get text():String + { + return _captionText; + } + + /** + * Returns the caption text without embedded HTML tags. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get clearText():String + { + var clrTxt:String = ""; + if (_captionText != null && _captionText.length > 0) + { + clrTxt = _captionText.replace(/<(.|\n)*?>/g, ""); + } + return clrTxt; + } + + private var _id:uint; + private var _captionText:String; // The text to display, can contain embedded html tags, such as
+ private var _formats:Vector.; + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptionFormat.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptionFormat.as index eb9382e..9a70a5d 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptionFormat.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptionFormat.as @@ -1,111 +1,111 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning.model -{ - /** - * Represents formatting for a caption object. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class CaptionFormat - { - public static const UNDEFINED_INDEX:int = -1; - - /** - * Creates a CaptionFormat object specifying the Style - * object and the zero-based start and end indices of the range. - * - * @param style The instance of CaptionStyle object to apply. - * @param start The optional zero-based index position specifying - * the first character of the desired range of text. - * @param end The optional zero-based index position specifying the - * last character of the desired range of text. - * - * @throws ArgumentError If the style argument is null. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function CaptionFormat(style:CaptionStyle, start:int = UNDEFINED_INDEX, end:int = UNDEFINED_INDEX) - { - // What good is a caption format without a style? - if (style == null) - { - throw new ArgumentError(MISSING_STYLE_ERROR_MSG); - } - _startIndex = start; - _endIndex = end; - _style = style; - } - - /** - * Get the start index supplied to the constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get startIndex():int - { - return _startIndex; - } - - /** - * Get the end index supplied to the constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get endIndex():int - { - return _endIndex; - } - - /** - * Get the style object supplied to the constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get style():CaptionStyle - { - return _style; - } - - private var _startIndex:int; - private var _endIndex:int; - private var _style:CaptionStyle; - - private static const MISSING_STYLE_ERROR_MSG:String = "CaptionStyle is required for CaptionFormat objects"; - - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning.model +{ + /** + * Represents formatting for a caption object. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class CaptionFormat + { + public static const UNDEFINED_INDEX:int = -1; + + /** + * Creates a CaptionFormat object specifying the Style + * object and the zero-based start and end indices of the range. + * + * @param style The instance of CaptionStyle object to apply. + * @param start The optional zero-based index position specifying + * the first character of the desired range of text. + * @param end The optional zero-based index position specifying the + * last character of the desired range of text. + * + * @throws ArgumentError If the style argument is null. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function CaptionFormat(style:CaptionStyle, start:int = UNDEFINED_INDEX, end:int = UNDEFINED_INDEX) + { + // What good is a caption format without a style? + if (style == null) + { + throw new ArgumentError(MISSING_STYLE_ERROR_MSG); + } + _startIndex = start; + _endIndex = end; + _style = style; + } + + /** + * Get the start index supplied to the constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get startIndex():int + { + return _startIndex; + } + + /** + * Get the end index supplied to the constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get endIndex():int + { + return _endIndex; + } + + /** + * Get the style object supplied to the constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get style():CaptionStyle + { + return _style; + } + + private var _startIndex:int; + private var _endIndex:int; + private var _style:CaptionStyle; + + private static const MISSING_STYLE_ERROR_MSG:String = "CaptionStyle is required for CaptionFormat objects"; + + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptionStyle.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptionStyle.as index 749221b..b7bba24 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptionStyle.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptionStyle.as @@ -1,260 +1,260 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning.model -{ - /** - * This class represents a caption style. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class CaptionStyle - { - /** - * Creates a Style object. - * - * @param id The ID is usually provided in the captioning document. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function CaptionStyle(id:String) - { - _id = id; - } - - /** - * Get the CaptionStyle ID. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get id():String - { - return _id; - } - - /** - * The background color for the control rendering - * the captioning text in a hexadecimal format; - * for example, 0xff0000 is red. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get backgroundColor():Object - { - return _backgroundColor; - } - - public function set backgroundColor(value:Object):void - { - _backgroundColor = value; - } - - /** - * The alpha transparency of the background color as - * a Number between 0 and 1. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get backgroundColorAlpha():Object - { - return _backgroundColorAlpha; - } - - public function set backgroundColorAlpha(value:Object):void - { - _backgroundColorAlpha = value; - } - - /** - * The text color of the caption in a hexadecimal format; - * for example, 0xff0000 is red. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get textColor():Object - { - return _textColor; - } - - public function set textColor(value:Object):void - { - _textColor = value; - } - - /** - * The alpha transparency of the text color as - * a Number between 0 and 1. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - - public function get textColorAlpha():Object - { - return _textColorAlpha; - } - - public function set textColorAlpha(value:Object):void - { - _textColorAlpha = value; - } - - /** - * The font family. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get fontFamily():String - { - return _fontFamily; - } - - public function set fontFamily(value:String):void - { - _fontFamily = value; - } - - /** - * The font size in pixels. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get fontSize():int - { - return _fontSize; - } - - public function set fontSize(value:int):void - { - _fontSize = value; - } - - /** - * The font style, normal or italic. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get fontStyle():String - { - return _fontStyle; - } - - public function set fontStyle(value:String):void - { - _fontStyle = value; - } - - /** - * The font weight, normal or bold. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get fontWeight():String - { - return _fontWeight; - } - - public function set fontWeight(value:String):void - { - _fontWeight = value; - } - - /** - * The text alignment, left, center, or right. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get textAlign():String - { - return _textAlign; - } - - public function set textAlign(value:String):void - { - _textAlign = value; - } - - /** - * The word wrap option. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get wrapOption():Boolean - { - return _wrapOption; - } - - public function set wrapOption(value:Boolean):void - { - _wrapOption = value; - } - - private var _id:String; - private var _backgroundColor:Object; - private var _backgroundColorAlpha:Object; - private var _textColor:Object; - private var _textColorAlpha:Object; - private var _fontFamily:String; - private var _fontSize:int; - private var _fontStyle:String; - private var _fontWeight:String; - private var _textAlign:String; - private var _wrapOption:Boolean; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning.model +{ + /** + * This class represents a caption style. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class CaptionStyle + { + /** + * Creates a Style object. + * + * @param id The ID is usually provided in the captioning document. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function CaptionStyle(id:String) + { + _id = id; + } + + /** + * Get the CaptionStyle ID. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get id():String + { + return _id; + } + + /** + * The background color for the control rendering + * the captioning text in a hexadecimal format; + * for example, 0xff0000 is red. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get backgroundColor():Object + { + return _backgroundColor; + } + + public function set backgroundColor(value:Object):void + { + _backgroundColor = value; + } + + /** + * The alpha transparency of the background color as + * a Number between 0 and 1. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get backgroundColorAlpha():Object + { + return _backgroundColorAlpha; + } + + public function set backgroundColorAlpha(value:Object):void + { + _backgroundColorAlpha = value; + } + + /** + * The text color of the caption in a hexadecimal format; + * for example, 0xff0000 is red. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get textColor():Object + { + return _textColor; + } + + public function set textColor(value:Object):void + { + _textColor = value; + } + + /** + * The alpha transparency of the text color as + * a Number between 0 and 1. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + + public function get textColorAlpha():Object + { + return _textColorAlpha; + } + + public function set textColorAlpha(value:Object):void + { + _textColorAlpha = value; + } + + /** + * The font family. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get fontFamily():String + { + return _fontFamily; + } + + public function set fontFamily(value:String):void + { + _fontFamily = value; + } + + /** + * The font size in pixels. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get fontSize():int + { + return _fontSize; + } + + public function set fontSize(value:int):void + { + _fontSize = value; + } + + /** + * The font style, normal or italic. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get fontStyle():String + { + return _fontStyle; + } + + public function set fontStyle(value:String):void + { + _fontStyle = value; + } + + /** + * The font weight, normal or bold. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get fontWeight():String + { + return _fontWeight; + } + + public function set fontWeight(value:String):void + { + _fontWeight = value; + } + + /** + * The text alignment, left, center, or right. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get textAlign():String + { + return _textAlign; + } + + public function set textAlign(value:String):void + { + _textAlign = value; + } + + /** + * The word wrap option. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get wrapOption():Boolean + { + return _wrapOption; + } + + public function set wrapOption(value:Boolean):void + { + _wrapOption = value; + } + + private var _id:String; + private var _backgroundColor:Object; + private var _backgroundColorAlpha:Object; + private var _textColor:Object; + private var _textColorAlpha:Object; + private var _fontFamily:String; + private var _fontSize:int; + private var _fontStyle:String; + private var _fontWeight:String; + private var _textAlign:String; + private var _wrapOption:Boolean; + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptioningDocument.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptioningDocument.as index ce473d2..a847c7d 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptioningDocument.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/model/CaptioningDocument.as @@ -1,218 +1,218 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning.model -{ - import __AS3__.vec.Vector; - - import flash.errors.IllegalOperationError; - - import org.osmf.utils.OSMFStrings; - - /** - * This class represents the root level object - * in the Captioning document object model. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class CaptioningDocument - { - /** - * The title, if it was found in the metadata in the header. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get title():String - { - return _title; - } - - public function set title(value:String):void - { - _title = value; - } - - /** - * The description, if it was found in the metadata in the header. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get description():String - { - return _desc; - } - - public function set description(value:String):void - { - _desc = value; - } - - /** - * The copyright, if it was found in the metadata in the header. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get copyright():String - { - return _copyright; - } - - public function set copyright(value:String):void - { - _copyright = value; - } - - /** - * Add a style to the internal collection of styles. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function addStyle(style:CaptionStyle):void - { - if (_styles == null) - { - _styles = new Vector.(); - } - - _styles.push(style); - } - - /** - * Returns the number of style objects in this class' - * internal collection. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get numStyles():int - { - var num:int = 0; - - if (_styles != null) - { - num = _styles.length; - } - - return num; - } - - /** - * Returns the style object at the index specified. - * - * @throws IllegalOperationError If index argument is out of range. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function getStyleAt(index:int):CaptionStyle - { - if (_styles == null || index >= _styles.length) - { - throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); - } - - return _styles[index]; - } - - /** - * Add a caption object. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function addCaption(caption:Caption):void - { - if (_captions == null) - { - _captions = new Vector.(); - } - _captions.push(caption); - } - - /** - * Returns the number of caption objects in this class' - * internal collection. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function get numCaptions():int - { - var num:int = 0; - - if (_captions != null) - { - num = _captions.length; - } - - return num; - } - - /** - * Returns the caption object at the index specified. - * - * @throws IllegalOperationError If index argument is out of range. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function getCaptionAt(index:int):Caption - { - if (_captions == null || index >= _captions.length) - { - throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); - } - - return _captions[index]; - } - - private var _title:String; - private var _desc:String; - private var _copyright:String; - private var _captions:Vector.; - private var _styles:Vector.; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning.model +{ + import __AS3__.vec.Vector; + + import flash.errors.IllegalOperationError; + + import org.osmf.utils.OSMFStrings; + + /** + * This class represents the root level object + * in the Captioning document object model. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class CaptioningDocument + { + /** + * The title, if it was found in the metadata in the header. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get title():String + { + return _title; + } + + public function set title(value:String):void + { + _title = value; + } + + /** + * The description, if it was found in the metadata in the header. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get description():String + { + return _desc; + } + + public function set description(value:String):void + { + _desc = value; + } + + /** + * The copyright, if it was found in the metadata in the header. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get copyright():String + { + return _copyright; + } + + public function set copyright(value:String):void + { + _copyright = value; + } + + /** + * Add a style to the internal collection of styles. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function addStyle(style:CaptionStyle):void + { + if (_styles == null) + { + _styles = new Vector.(); + } + + _styles.push(style); + } + + /** + * Returns the number of style objects in this class' + * internal collection. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get numStyles():int + { + var num:int = 0; + + if (_styles != null) + { + num = _styles.length; + } + + return num; + } + + /** + * Returns the style object at the index specified. + * + * @throws IllegalOperationError If index argument is out of range. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function getStyleAt(index:int):CaptionStyle + { + if (_styles == null || index >= _styles.length) + { + throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); + } + + return _styles[index]; + } + + /** + * Add a caption object. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function addCaption(caption:Caption):void + { + if (_captions == null) + { + _captions = new Vector.(); + } + _captions.push(caption); + } + + /** + * Returns the number of caption objects in this class' + * internal collection. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function get numCaptions():int + { + var num:int = 0; + + if (_captions != null) + { + num = _captions.length; + } + + return num; + } + + /** + * Returns the caption object at the index specified. + * + * @throws IllegalOperationError If index argument is out of range. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function getCaptionAt(index:int):Caption + { + if (_captions == null || index >= _captions.length) + { + throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); + } + + return _captions[index]; + } + + private var _title:String; + private var _desc:String; + private var _copyright:String; + private var _captions:Vector.; + private var _styles:Vector.; + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/parsers/DFXPParser.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/parsers/DFXPParser.as index cc98fd5..eb6e5ef 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/parsers/DFXPParser.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/parsers/DFXPParser.as @@ -1,753 +1,753 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning.parsers -{ - import flash.utils.Dictionary; - - import org.osmf.captioning.model.Caption; - import org.osmf.captioning.model.CaptionFormat; - import org.osmf.captioning.model.CaptionStyle; - import org.osmf.captioning.model.CaptioningDocument; - import org.osmf.utils.TimeUtil; - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - } - - /** - * This class parses a W3C Timed Text DFXP file and - * creates a document object model representation of - * the file by returning a CaptioningDocument object - * from the parse method. A load failure translates to - * an OSMF media load failed message. - * - * A subset of the W3C Timed Text Authoring Format 1.0 - Distribution - * Format Exchange Profile (DFXP) is supported by this parser. - * - * The subset supported by this class is specified here: - *
    - *
  • tt tag
  • - *
      - *
    • All attributes of the tt tag are ignored.
    • - *
    • head tag
    • - *
        - *
      • head tag is not required.
      • - *
      • metadata tag is supported. The title, - * description, and copyright attribute values are available via properties - * of this class.
      • - *
      • layout tag and any child tags are ignored.
      • - *
      • styling tag is supported.
      • - *
          - *
        • style tags are supported.
        • - *
            - *
          • Each style tag must have a unique ID and the - * following attributes are supported:
          • - *
              - *
            • tts:fontFamily
            • - *
            • tts:fontSize
            • - *
                - *
              • Support for only one value. If two values - * are present only the first is used.
              • - *
              • Units are ignored, pixels are assumed.
              • - *
              • Percentages are not supported (e.g. 50%).
              • - *
              • Increment/decrement is not supported (e.g. +5).
              • - *
              - *
            • tts:fontStyle
            • - *
            • tts:fontWeight
            • - *
            • tts:textAlign
            • - *
            • tts:wrapOption
            • - *
            • tts:backgroundColor
            • - *
            • tts:color
            • - *
            - *
          - *
        - *
      - *
    • body tag
    • - *
        - *
      • body tag is required.
      • - *
      • Only one body tag is supported.
      • - *
      • All attributes of the body tag are ignored.
      • - *
      • div tag
      • - *
          - *
        • Supported but not required.
        • - *
        • Support for one div tag only.
        • - *
        • All attributes of the div tag are ignored.
        • - *
        • p tag
        • - *
            - *
          • Support for one or many.
          • - *
          • p tags contain the caption text and optionally any styles.
          • - *
          • Support for the attributes begin, dur, and end only. All other attributes are ignored.
          • - *
              - *
            • If begin is absent, zero is assumed.
            • - *
            • If both dur and end are present, dur will be ignored.
            • - *
            • The following time values are supported:
            • - *
            - *
              - *
            • full clock format in "hours:minutes:seconds:fraction" (e.g. 00:03:00:00).
            • - *
            • offset time (e.g. 10s for ten seconds or 1m for one minute).
            • - *
            • offset times without units (e.g. 10) are assumed to be seconds.
            • - *
            - *
          • styles can be 'inline', using a span tag, or referenced with a style ID
          • - *
          • span tags are supported.
          • - *
              - *
            • suppport for style attributes only, all other attributes are ignored.
            • - *
            • nested span tags are not supported.
            • - *
            - *
          • The br tag is supported.
          • - *
          - *
        - *
      - * - *
    - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public class DFXPParser implements ICaptioningParser - { - /** - * Constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function DFXPParser() - { - super(); - - namedColorMap = new Dictionary(); - - namedColorMap["transparent"]= 0x000000; - namedColorMap["black"] = 0x000000; - namedColorMap["silver"] = 0xc0c0c0; - namedColorMap["gray"] = 0x808080; - namedColorMap["white"] = 0xffffff; - namedColorMap["maroon"] = 0x800000; - namedColorMap["red"] = 0xff0000; - namedColorMap["purple"] = 0x800080; - namedColorMap["fuchsia"] = 0xff00ff; - namedColorMap["magenta"] = 0xff00ff; - namedColorMap["green"] = 0x008000; - namedColorMap["lime"] = 0x00ff00; - namedColorMap["olive"] = 0x808000; - namedColorMap["yellow"] = 0xffff00; - namedColorMap["navy"] = 0x000080; - namedColorMap["blue"] = 0x0000ff; - namedColorMap["teal"] = 0x008080; - namedColorMap["aqua"] = 0x00ffff; - namedColorMap["cyan"] = 0x00ffff; - } - - /** - * Parses the raw data passed in which should represent - * a W3C Timed Text DFXP file and returns a CaptioningDocument - * object which represents the root level object of the file's - * document object model. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public function parse(rawData:String):CaptioningDocument - { - var document:CaptioningDocument = new CaptioningDocument(); - var saveXMLIgnoreWhitespace:Boolean = XML.ignoreWhitespace; - var saveXMLPrettyPrinting:Boolean = XML.prettyPrinting; - - // Remove line ending whitespaces - var xmlStr:String = rawData.replace(/\s+$/, ""); - - // Remove whitespaces between tags - xmlStr = xmlStr.replace(/>\s+<"); - - // Tell the XML class to show white space in text nodes - XML.ignoreWhitespace = false; - // Tell the XML class not to normalize white space for toString() method calls - XML.prettyPrinting = false; - - try - { - var xml:XML = new XML(xmlStr); - } - catch (e:Error) - { - debugLog("Unhandled exception in DFXPParser : "+e.message); - throw e; - } - finally - { - XML.ignoreWhitespace = saveXMLIgnoreWhitespace; - XML.prettyPrinting = saveXMLPrettyPrinting; - } - - rootNamespace = xml.namespace(); - - ns = xml.namespace(); - ttm = xml.namespace("ttm"); - tts = xml.namespace("tts"); - - try - { - parseHead(document, xml); - parseBody(document, xml); - } - catch (err:Error) - { - debugLog("Unhandled exception in DFXPParser : "+err.message); - throw err; - } - - return document; - } - - - private function parseHead(doc:CaptioningDocument, xml:XML):void - { - // Metadata - not required - try - { - doc.title = xml..ttm::title.text(); - doc.description = xml..ttm::desc.text(); - doc.copyright = xml..ttm::copyright.text(); - } - catch (err:Error) - { - // Catch only this one: "Error #1080: Illegal value for namespace." This - // means the document is missing some of the metadata tags we tried to - // access, not a fatal error. - if (err.errorID != 1080) - { - throw err; - } - } - - // Styles - not required - var styling:XMLList = xml..ns::styling; - - if (styling.length()) - { - var styles:XMLList = styling.children(); - for (var i:uint = 0; i < styles.length(); i++) - { - var styleNode:XML = styles[i]; - var styleObj:CaptionStyle = createStyleObject(styleNode); - - doc.addStyle(styleObj); - } - } - } - - /** - * Creates a CaptionStyle from a style node. - */ - private function createStyleObject(styleNode:XML):CaptionStyle - { - var id:String = styleNode.@*::id; - var styleObj:CaptionStyle = new CaptionStyle(id); - - var colorValue:Object; - - var color:String = styleNode.@tts::backgroundColor; - if (color != "") - { - colorValue = parseColor(color); - styleObj.backgroundColor = colorValue.color; - styleObj.backgroundColorAlpha = colorValue.alpha; - } - styleObj.textAlign = styleNode.@tts::textAlign; - - color = styleNode.@tts::color; - if (color != "") - { - colorValue = parseColor(color); - styleObj.textColor = colorValue.color; - styleObj.textColorAlpha = colorValue.alpha; - } - - styleObj.fontFamily = parseFontFamily(styleNode.@tts::fontFamily); - - var fontSize:String = parseFontSize(styleNode.@tts::fontSize); - styleObj.fontSize = parseInt(fontSize); - - styleObj.fontStyle = styleNode.@tts::fontStyle; - styleObj.fontWeight = styleNode.@tts::fontWeight; - styleObj.wrapOption = (String(styleNode.@tts::wrapOption).toLowerCase() == "nowrap") ? false : true; - - return styleObj; - } - - /** - * Takes a string in the valid formats specified by the W3C Timed Text - * standard which include:
      - *
    • #rrggbb - each color value is a hexadecimal digit, such as #ff0000 for red
    • - *
    • #rrggbbaa - each color value is a hexadecial digit, such as #ff0000ff for fully opaque red
    • - *
    • rgb(red, green, blue) - each value has a range from 0 - 255
    • - *
    • rgba(red, green, blue, alpha) - each value has a range from 0 - 255
    • - *
    - * - * and returns an Object with the following properties:
      - *
    • color : a hexadecimal value representing the color, for example, 0xff0000 is red.
    • - *
    • alpha : a Number between 0 and 1 specifying the alpha transparency
    • - *
    - */ - private function parseColor(colorStr:String):Object - { - var colorValue:Object; - var alphaValue:Object; - - // First check for #rrggbb and #rrggbbaa formats - var pattern:RegExp = /^\s*#([\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f])([\dA-Fa-f][\dA-Fa-f])?\s*$/; - var result:Array = colorStr.match(pattern); - - if (result != null) - { - colorValue = parseInt(result[1], 16); - if (result.length == 3) - { - alphaValue = Number(parseInt(result[2])/255); - } - } - else - { - // Next check for rgb(r,g,b) and rgba(r, g, b, a) formats - pattern = /^\s*rgb(a)?\((\d+),(\d+),(\d+)(\)|(,(\d+)\)))\s*$/i; - result = colorStr.match(pattern); - - if (result != null && result.length >= 5) - { - colorValue = (parseInt(result[2]) << 16) + (parseInt(result[3]) << 8) + parseInt(result[4]); - if (result.length == 8 && result[7] != undefined) - { - alphaValue = Number(parseInt(result[7])/255); - } - } - else - { - // Check for named color values - colorValue = namedColorMap[colorStr.toLowerCase()]; - if (colorValue == null) - { - // Finally, just take what we got - colorValue = parseInt(colorStr); - if (isNaN(int(colorValue))) - { - colorValue = null; - debugLog("Invalid DFXP document: invalid color value of " + colorStr); - } - } - } - } - - return {color:colorValue, alpha:alphaValue}; - } - - - private function parseFontSize(rawFontSize:String):String - { - if (!rawFontSize || rawFontSize == "") - { - return ""; - } - - var returnValue:String = ""; - - // Check for percentage, e.g., 50% - var perRegExp:RegExp = new RegExp(/^\s*\d+%.*$/); - var perResult:Object = perRegExp.exec(rawFontSize); - - if (perResult) - { - // Percentages not supported - debugLog("Invalid DFXP document: percentages are not supported for font size."); - returnValue = ""; - } - else - { - // Check for increment, e.g., +5 - var incRegExp:RegExp = new RegExp(/^\s*[\+\-]\d.*/); - var incResult:Object = incRegExp.exec(rawFontSize); - - if (incResult) - { - // Increment not supported - debugLog("Invalid DFXP document: increment values are not supported for font size."); - returnValue = ""; - } - else - { - var regExp:RegExp = new RegExp(/^\s*(\d+).*$/); - var result:Object = regExp.exec(rawFontSize); - - if (result && (result[1] != undefined)) - { - returnValue = result[1]; - } - } - } - return returnValue; - } - - private function parseFontFamily(rawFontFamily:String):String - { - if (!rawFontFamily || rawFontFamily == "") - { - return ""; - } - - var retVal:String = ""; - var regExp:RegExp = new RegExp(/^\s*([^,\s]+)\s*((,\s*([^,\s]+)\s*)*)$/); - var done:Boolean = false; - - do - { - var result:Object = regExp.exec(rawFontFamily); - if (!result) - { - done = true; - } - else - { - if (retVal.length > 0) - { - retVal += ","; - } - - // These generic family names are right out of the W3C spec. We need to map them to one of the Flash player's - // three default fonts: "_sans", "_serif", and "_typewriter". The Flash player will find the closest font - // on the user's system at run-time. - switch (result[1]) - { - case "default": - case "serif": - case "proportionalSerif": - retVal += "_serif"; - break; - - case "monospace": - case "monospaceSansSerif": - case "monospaceSerif": - retVal += "_typewriter"; - break; - - case "sansSerif": - case "proportionalSansSerif": - retVal += "_sans"; - break; - - default: - retVal += result[1]; - break; - } - - if ((result[2] != undefined) && (result[2] != "")) - { - rawFontFamily = result[2].slice(1); - } - else - { - done = true; - } - } - - } while (!done); - - return retVal; - } - - private function parseBody(doc:CaptioningDocument, xml:XML):void - { - // The tag is required - var body:XMLList = xml..ns::body; - if (body.length() <= 0) - { - debugLog("Invalid DFXP document: tag is required."); - } - else - { - // Support for one
    tag only, but it is not required - var div:XMLList = xml..ns::div; - - // Support for 1 to many

    tags, these tags contain the timing info, they can appear in any order - var p:XMLList = div.length() ? div.children() : (body.length() ? body.children() : new XMLList()); - - // Captions should be in

    tags - for (var i:uint = 0; i < p.length(); i++) - { - var pNode:XML = p[i]; - - // According the W3C, foreign namespaces should be ignored for p tags - if (rootNamespace == pNode.namespace()) - { - parsePTag(doc, pNode, i); - } - else - { - debugLog("Ignoring this tag, foreign namespaces not supported: \""+pNode+"\""); - } - } - } - } - - private function parsePTag(doc:CaptioningDocument, pNode:XML, index:uint):void - { - // For timing attributes, we support 'begin', 'dur', 'end', all others are ignored. - // If the attribute 'begin' is missing, we default to zero. - // If both 'dur' and 'end' are present, the 'end' attribute is used - - var begin:String = pNode.@begin; - var end:String = pNode.@end; - var dur:String = pNode.@dur; - - // If no 'begin' default to 0 seconds - if (begin == "") - { - begin = "0s"; - } - - // Format begin in seconds - var beginSecs:Number = TimeUtil.parseTime(begin); - - var endSecs:Number = 0; - - // If we found both 'end' and 'dur', ignore 'dur' - if (end != "") - { - endSecs = TimeUtil.parseTime(end); - } - else if (dur != "") - { - endSecs = beginSecs + TimeUtil.parseTime(dur); - } - - var captionFormatList:Array = new Array(); - - // Create the caption text, we don't support nested span tags - var text:String = new String("

    "); - - var children:XMLList = pNode.children(); - for (var i:uint = 0; i < children.length(); i++) - { - var child:XML = children[i]; - switch (child.nodeKind()) - { - case "text": - text += formatCCText(child.toString()); - break; - case "element": - switch (child.localName()) - { - case "set": - case "metadata": - break; // We don't support these in

    tags - case "span": - var styleStartIndex:uint = calcClearTextLength(text); - var spanText:String; - - var stylesList:Array = new Array(); - - text += parseSpanTag(doc, child, stylesList); - - var styleEndIndex:uint = calcClearTextLength(text); - - for each (var styleObject:CaptionStyle in stylesList) - { - var fmtObj:CaptionFormat = new CaptionFormat(styleObject, styleStartIndex, styleEndIndex); - captionFormatList.push(fmtObj); - } - break; - case "br": - text += "
    "; - break; - default: - text += formatCCText(child.toString()); - break; - } - break; - } - } - - text += "

    "; - - var captionItem:Caption = new Caption(index, beginSecs, endSecs, text); - - // If there is a style attribute, parse that - var styleObj:CaptionStyle = parseStyleAttrib(doc, pNode); - if (styleObj) - { - var formatObj:CaptionFormat = new CaptionFormat(styleObj); - captionItem.addCaptionFormat(formatObj); - } - - // If there were styles in the span tag(s), add those - for (i = 0; i < captionFormatList.length; i++) - { - captionItem.addCaptionFormat(captionFormatList[i]); - } - - doc.addCaption(captionItem); - } - - /** - * If an element has a style attribute specifying a style id, such as

    Caption text

    , - * this method looks up the style object read from the head tag and returns it. - * - * If an element has an attribute in the TT Style namespace, such as some green text, - * this method parses that attribute and returns a new style object. - */ - private function parseStyleAttrib(doc:CaptioningDocument, node:XML):CaptionStyle - { - var styleId:String = node.@style; - var captionStyle:CaptionStyle = null; - - // See if it references a style tag with an ID attribute - if (styleId != "") - { - for (var i:uint; i < doc.numStyles; i++) - { - if (doc.getStyleAt(i).id == styleId) - { - captionStyle = doc.getStyleAt(i); - } - } - } - else - { - try - { - var attributes:XMLList = node.@tts::*; - } - catch (err:Error) - { - // Catch only this one: "Error #1080: Illegal value for namespace." This - // means the document is missing the xmlns:tts declartion in the tt tag, - // not a fatal error. - if (err.errorID != 1080) - { - throw err; - } - } - - for (i = 0; (attributes != null) && (i < attributes.length()); i++) - { - var attrib:XML = attributes[i]; - var localName:String = attrib.localName(); - - if (localName == "inherit") - { - continue; - } - else - { - captionStyle = createStyleObject(node); - } - } - } - return captionStyle; - } - - private function parseSpanTag(doc:CaptioningDocument, spanNode:XML, styles:Array):String - { - // Look for style attribute - var styleObj:CaptionStyle = parseStyleAttrib(doc, spanNode); - - if (styleObj != null) - { - styles.push(styleObj); - } - - var ccText:String = new String(); - var children:XMLList = spanNode.children(); - - for (var i:uint = 0; i < children.length(); i++ ) - { - var child:XML = children[i]; - - switch (child.nodeKind()) - { - case "text": - ccText += formatCCText(child.toString()); - break; - case "element": - switch (child.localName()) - { - case "set": - case "metadata": - break; // We don't support these in tags - case "br": - ccText += "
    "; - break; - default: - ccText += child.toString(); - break; - } - break; - } - } - - return ccText; - } - - private function formatCCText(txt:String):String - { - var retString:String = txt.replace(/\s+/g, " "); - return retString; - } - - /** - * Utility method to calculate the length - * of a string non-inclusive of any HTML tags. - */ - private function calcClearTextLength(txt:String):int - { - var clrTxt:String = txt.replace(/<(.|\n)*?>/g, ""); - return clrTxt.length; - } - - private function debugLog(msg:String):void - { - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug(msg); - } - } - } - - private var ns:Namespace; - private var ttm:Namespace; - private var tts:Namespace; - private var rootNamespace:Namespace; - private var namedColorMap:Dictionary; - - CONFIG::LOGGING - { - private static const logger:Logger = org.osmf.logging.Log.getLogger("org.osmf.captioning.parsers.DFXPParser"); - } - - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning.parsers +{ + import flash.utils.Dictionary; + + import org.osmf.captioning.model.Caption; + import org.osmf.captioning.model.CaptionFormat; + import org.osmf.captioning.model.CaptionStyle; + import org.osmf.captioning.model.CaptioningDocument; + import org.osmf.utils.TimeUtil; + CONFIG::LOGGING + { + import org.osmf.logging.Logger; + } + + /** + * This class parses a W3C Timed Text DFXP file and + * creates a document object model representation of + * the file by returning a CaptioningDocument object + * from the parse method. A load failure translates to + * an OSMF media load failed message. + * + * A subset of the W3C Timed Text Authoring Format 1.0 - Distribution + * Format Exchange Profile (DFXP) is supported by this parser. + * + * The subset supported by this class is specified here: + *
      + *
    • tt tag
    • + *
        + *
      • All attributes of the tt tag are ignored.
      • + *
      • head tag
      • + *
          + *
        • head tag is not required.
        • + *
        • metadata tag is supported. The title, + * description, and copyright attribute values are available via properties + * of this class.
        • + *
        • layout tag and any child tags are ignored.
        • + *
        • styling tag is supported.
        • + *
            + *
          • style tags are supported.
          • + *
              + *
            • Each style tag must have a unique ID and the + * following attributes are supported:
            • + *
                + *
              • tts:fontFamily
              • + *
              • tts:fontSize
              • + *
                  + *
                • Support for only one value. If two values + * are present only the first is used.
                • + *
                • Units are ignored, pixels are assumed.
                • + *
                • Percentages are not supported (e.g. 50%).
                • + *
                • Increment/decrement is not supported (e.g. +5).
                • + *
                + *
              • tts:fontStyle
              • + *
              • tts:fontWeight
              • + *
              • tts:textAlign
              • + *
              • tts:wrapOption
              • + *
              • tts:backgroundColor
              • + *
              • tts:color
              • + *
              + *
            + *
          + *
        + *
      • body tag
      • + *
          + *
        • body tag is required.
        • + *
        • Only one body tag is supported.
        • + *
        • All attributes of the body tag are ignored.
        • + *
        • div tag
        • + *
            + *
          • Supported but not required.
          • + *
          • Support for one div tag only.
          • + *
          • All attributes of the div tag are ignored.
          • + *
          • p tag
          • + *
              + *
            • Support for one or many.
            • + *
            • p tags contain the caption text and optionally any styles.
            • + *
            • Support for the attributes begin, dur, and end only. All other attributes are ignored.
            • + *
                + *
              • If begin is absent, zero is assumed.
              • + *
              • If both dur and end are present, dur will be ignored.
              • + *
              • The following time values are supported:
              • + *
              + *
                + *
              • full clock format in "hours:minutes:seconds:fraction" (e.g. 00:03:00:00).
              • + *
              • offset time (e.g. 10s for ten seconds or 1m for one minute).
              • + *
              • offset times without units (e.g. 10) are assumed to be seconds.
              • + *
              + *
            • styles can be 'inline', using a span tag, or referenced with a style ID
            • + *
            • span tags are supported.
            • + *
                + *
              • suppport for style attributes only, all other attributes are ignored.
              • + *
              • nested span tags are not supported.
              • + *
              + *
            • The br tag is supported.
            • + *
            + *
          + *
        + * + *
      + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public class DFXPParser implements ICaptioningParser + { + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function DFXPParser() + { + super(); + + namedColorMap = new Dictionary(); + + namedColorMap["transparent"]= 0x000000; + namedColorMap["black"] = 0x000000; + namedColorMap["silver"] = 0xc0c0c0; + namedColorMap["gray"] = 0x808080; + namedColorMap["white"] = 0xffffff; + namedColorMap["maroon"] = 0x800000; + namedColorMap["red"] = 0xff0000; + namedColorMap["purple"] = 0x800080; + namedColorMap["fuchsia"] = 0xff00ff; + namedColorMap["magenta"] = 0xff00ff; + namedColorMap["green"] = 0x008000; + namedColorMap["lime"] = 0x00ff00; + namedColorMap["olive"] = 0x808000; + namedColorMap["yellow"] = 0xffff00; + namedColorMap["navy"] = 0x000080; + namedColorMap["blue"] = 0x0000ff; + namedColorMap["teal"] = 0x008080; + namedColorMap["aqua"] = 0x00ffff; + namedColorMap["cyan"] = 0x00ffff; + } + + /** + * Parses the raw data passed in which should represent + * a W3C Timed Text DFXP file and returns a CaptioningDocument + * object which represents the root level object of the file's + * document object model. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public function parse(rawData:String):CaptioningDocument + { + var document:CaptioningDocument = new CaptioningDocument(); + var saveXMLIgnoreWhitespace:Boolean = XML.ignoreWhitespace; + var saveXMLPrettyPrinting:Boolean = XML.prettyPrinting; + + // Remove line ending whitespaces + var xmlStr:String = rawData.replace(/\s+$/, ""); + + // Remove whitespaces between tags + xmlStr = xmlStr.replace(/>\s+<"); + + // Tell the XML class to show white space in text nodes + XML.ignoreWhitespace = false; + // Tell the XML class not to normalize white space for toString() method calls + XML.prettyPrinting = false; + + try + { + var xml:XML = new XML(xmlStr); + } + catch (e:Error) + { + debugLog("Unhandled exception in DFXPParser : "+e.message); + throw e; + } + finally + { + XML.ignoreWhitespace = saveXMLIgnoreWhitespace; + XML.prettyPrinting = saveXMLPrettyPrinting; + } + + rootNamespace = xml.namespace(); + + ns = xml.namespace(); + ttm = xml.namespace("ttm"); + tts = xml.namespace("tts"); + + try + { + parseHead(document, xml); + parseBody(document, xml); + } + catch (err:Error) + { + debugLog("Unhandled exception in DFXPParser : "+err.message); + throw err; + } + + return document; + } + + + private function parseHead(doc:CaptioningDocument, xml:XML):void + { + // Metadata - not required + try + { + doc.title = xml..ttm::title.text(); + doc.description = xml..ttm::desc.text(); + doc.copyright = xml..ttm::copyright.text(); + } + catch (err:Error) + { + // Catch only this one: "Error #1080: Illegal value for namespace." This + // means the document is missing some of the metadata tags we tried to + // access, not a fatal error. + if (err.errorID != 1080) + { + throw err; + } + } + + // Styles - not required + var styling:XMLList = xml..ns::styling; + + if (styling.length()) + { + var styles:XMLList = styling.children(); + for (var i:uint = 0; i < styles.length(); i++) + { + var styleNode:XML = styles[i]; + var styleObj:CaptionStyle = createStyleObject(styleNode); + + doc.addStyle(styleObj); + } + } + } + + /** + * Creates a CaptionStyle from a style node. + */ + private function createStyleObject(styleNode:XML):CaptionStyle + { + var id:String = styleNode.@*::id; + var styleObj:CaptionStyle = new CaptionStyle(id); + + var colorValue:Object; + + var color:String = styleNode.@tts::backgroundColor; + if (color != "") + { + colorValue = parseColor(color); + styleObj.backgroundColor = colorValue.color; + styleObj.backgroundColorAlpha = colorValue.alpha; + } + styleObj.textAlign = styleNode.@tts::textAlign; + + color = styleNode.@tts::color; + if (color != "") + { + colorValue = parseColor(color); + styleObj.textColor = colorValue.color; + styleObj.textColorAlpha = colorValue.alpha; + } + + styleObj.fontFamily = parseFontFamily(styleNode.@tts::fontFamily); + + var fontSize:String = parseFontSize(styleNode.@tts::fontSize); + styleObj.fontSize = parseInt(fontSize); + + styleObj.fontStyle = styleNode.@tts::fontStyle; + styleObj.fontWeight = styleNode.@tts::fontWeight; + styleObj.wrapOption = (String(styleNode.@tts::wrapOption).toLowerCase() == "nowrap") ? false : true; + + return styleObj; + } + + /** + * Takes a string in the valid formats specified by the W3C Timed Text + * standard which include:
        + *
      • #rrggbb - each color value is a hexadecimal digit, such as #ff0000 for red
      • + *
      • #rrggbbaa - each color value is a hexadecial digit, such as #ff0000ff for fully opaque red
      • + *
      • rgb(red, green, blue) - each value has a range from 0 - 255
      • + *
      • rgba(red, green, blue, alpha) - each value has a range from 0 - 255
      • + *
      + * + * and returns an Object with the following properties:
        + *
      • color : a hexadecimal value representing the color, for example, 0xff0000 is red.
      • + *
      • alpha : a Number between 0 and 1 specifying the alpha transparency
      • + *
      + */ + private function parseColor(colorStr:String):Object + { + var colorValue:Object; + var alphaValue:Object; + + // First check for #rrggbb and #rrggbbaa formats + var pattern:RegExp = /^\s*#([\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f])([\dA-Fa-f][\dA-Fa-f])?\s*$/; + var result:Array = colorStr.match(pattern); + + if (result != null) + { + colorValue = parseInt(result[1], 16); + if (result.length == 3) + { + alphaValue = Number(parseInt(result[2])/255); + } + } + else + { + // Next check for rgb(r,g,b) and rgba(r, g, b, a) formats + pattern = /^\s*rgb(a)?\((\d+),(\d+),(\d+)(\)|(,(\d+)\)))\s*$/i; + result = colorStr.match(pattern); + + if (result != null && result.length >= 5) + { + colorValue = (parseInt(result[2]) << 16) + (parseInt(result[3]) << 8) + parseInt(result[4]); + if (result.length == 8 && result[7] != undefined) + { + alphaValue = Number(parseInt(result[7])/255); + } + } + else + { + // Check for named color values + colorValue = namedColorMap[colorStr.toLowerCase()]; + if (colorValue == null) + { + // Finally, just take what we got + colorValue = parseInt(colorStr); + if (isNaN(int(colorValue))) + { + colorValue = null; + debugLog("Invalid DFXP document: invalid color value of " + colorStr); + } + } + } + } + + return {color:colorValue, alpha:alphaValue}; + } + + + private function parseFontSize(rawFontSize:String):String + { + if (!rawFontSize || rawFontSize == "") + { + return ""; + } + + var returnValue:String = ""; + + // Check for percentage, e.g., 50% + var perRegExp:RegExp = new RegExp(/^\s*\d+%.*$/); + var perResult:Object = perRegExp.exec(rawFontSize); + + if (perResult) + { + // Percentages not supported + debugLog("Invalid DFXP document: percentages are not supported for font size."); + returnValue = ""; + } + else + { + // Check for increment, e.g., +5 + var incRegExp:RegExp = new RegExp(/^\s*[\+\-]\d.*/); + var incResult:Object = incRegExp.exec(rawFontSize); + + if (incResult) + { + // Increment not supported + debugLog("Invalid DFXP document: increment values are not supported for font size."); + returnValue = ""; + } + else + { + var regExp:RegExp = new RegExp(/^\s*(\d+).*$/); + var result:Object = regExp.exec(rawFontSize); + + if (result && (result[1] != undefined)) + { + returnValue = result[1]; + } + } + } + return returnValue; + } + + private function parseFontFamily(rawFontFamily:String):String + { + if (!rawFontFamily || rawFontFamily == "") + { + return ""; + } + + var retVal:String = ""; + var regExp:RegExp = new RegExp(/^\s*([^,\s]+)\s*((,\s*([^,\s]+)\s*)*)$/); + var done:Boolean = false; + + do + { + var result:Object = regExp.exec(rawFontFamily); + if (!result) + { + done = true; + } + else + { + if (retVal.length > 0) + { + retVal += ","; + } + + // These generic family names are right out of the W3C spec. We need to map them to one of the Flash player's + // three default fonts: "_sans", "_serif", and "_typewriter". The Flash player will find the closest font + // on the user's system at run-time. + switch (result[1]) + { + case "default": + case "serif": + case "proportionalSerif": + retVal += "_serif"; + break; + + case "monospace": + case "monospaceSansSerif": + case "monospaceSerif": + retVal += "_typewriter"; + break; + + case "sansSerif": + case "proportionalSansSerif": + retVal += "_sans"; + break; + + default: + retVal += result[1]; + break; + } + + if ((result[2] != undefined) && (result[2] != "")) + { + rawFontFamily = result[2].slice(1); + } + else + { + done = true; + } + } + + } while (!done); + + return retVal; + } + + private function parseBody(doc:CaptioningDocument, xml:XML):void + { + // The tag is required + var body:XMLList = xml..ns::body; + if (body.length() <= 0) + { + debugLog("Invalid DFXP document: tag is required."); + } + else + { + // Support for one
      tag only, but it is not required + var div:XMLList = xml..ns::div; + + // Support for 1 to many

      tags, these tags contain the timing info, they can appear in any order + var p:XMLList = div.length() ? div.children() : (body.length() ? body.children() : new XMLList()); + + // Captions should be in

      tags + for (var i:uint = 0; i < p.length(); i++) + { + var pNode:XML = p[i]; + + // According the W3C, foreign namespaces should be ignored for p tags + if (rootNamespace == pNode.namespace()) + { + parsePTag(doc, pNode, i); + } + else + { + debugLog("Ignoring this tag, foreign namespaces not supported: \""+pNode+"\""); + } + } + } + } + + private function parsePTag(doc:CaptioningDocument, pNode:XML, index:uint):void + { + // For timing attributes, we support 'begin', 'dur', 'end', all others are ignored. + // If the attribute 'begin' is missing, we default to zero. + // If both 'dur' and 'end' are present, the 'end' attribute is used + + var begin:String = pNode.@begin; + var end:String = pNode.@end; + var dur:String = pNode.@dur; + + // If no 'begin' default to 0 seconds + if (begin == "") + { + begin = "0s"; + } + + // Format begin in seconds + var beginSecs:Number = TimeUtil.parseTime(begin); + + var endSecs:Number = 0; + + // If we found both 'end' and 'dur', ignore 'dur' + if (end != "") + { + endSecs = TimeUtil.parseTime(end); + } + else if (dur != "") + { + endSecs = beginSecs + TimeUtil.parseTime(dur); + } + + var captionFormatList:Array = new Array(); + + // Create the caption text, we don't support nested span tags + var text:String = new String("

      "); + + var children:XMLList = pNode.children(); + for (var i:uint = 0; i < children.length(); i++) + { + var child:XML = children[i]; + switch (child.nodeKind()) + { + case "text": + text += formatCCText(child.toString()); + break; + case "element": + switch (child.localName()) + { + case "set": + case "metadata": + break; // We don't support these in

      tags + case "span": + var styleStartIndex:uint = calcClearTextLength(text); + var spanText:String; + + var stylesList:Array = new Array(); + + text += parseSpanTag(doc, child, stylesList); + + var styleEndIndex:uint = calcClearTextLength(text); + + for each (var styleObject:CaptionStyle in stylesList) + { + var fmtObj:CaptionFormat = new CaptionFormat(styleObject, styleStartIndex, styleEndIndex); + captionFormatList.push(fmtObj); + } + break; + case "br": + text += "
      "; + break; + default: + text += formatCCText(child.toString()); + break; + } + break; + } + } + + text += "

      "; + + var captionItem:Caption = new Caption(index, beginSecs, endSecs, text); + + // If there is a style attribute, parse that + var styleObj:CaptionStyle = parseStyleAttrib(doc, pNode); + if (styleObj) + { + var formatObj:CaptionFormat = new CaptionFormat(styleObj); + captionItem.addCaptionFormat(formatObj); + } + + // If there were styles in the span tag(s), add those + for (i = 0; i < captionFormatList.length; i++) + { + captionItem.addCaptionFormat(captionFormatList[i]); + } + + doc.addCaption(captionItem); + } + + /** + * If an element has a style attribute specifying a style id, such as

      Caption text

      , + * this method looks up the style object read from the head tag and returns it. + * + * If an element has an attribute in the TT Style namespace, such as some green text, + * this method parses that attribute and returns a new style object. + */ + private function parseStyleAttrib(doc:CaptioningDocument, node:XML):CaptionStyle + { + var styleId:String = node.@style; + var captionStyle:CaptionStyle = null; + + // See if it references a style tag with an ID attribute + if (styleId != "") + { + for (var i:uint; i < doc.numStyles; i++) + { + if (doc.getStyleAt(i).id == styleId) + { + captionStyle = doc.getStyleAt(i); + } + } + } + else + { + try + { + var attributes:XMLList = node.@tts::*; + } + catch (err:Error) + { + // Catch only this one: "Error #1080: Illegal value for namespace." This + // means the document is missing the xmlns:tts declartion in the tt tag, + // not a fatal error. + if (err.errorID != 1080) + { + throw err; + } + } + + for (i = 0; (attributes != null) && (i < attributes.length()); i++) + { + var attrib:XML = attributes[i]; + var localName:String = attrib.localName(); + + if (localName == "inherit") + { + continue; + } + else + { + captionStyle = createStyleObject(node); + } + } + } + return captionStyle; + } + + private function parseSpanTag(doc:CaptioningDocument, spanNode:XML, styles:Array):String + { + // Look for style attribute + var styleObj:CaptionStyle = parseStyleAttrib(doc, spanNode); + + if (styleObj != null) + { + styles.push(styleObj); + } + + var ccText:String = new String(); + var children:XMLList = spanNode.children(); + + for (var i:uint = 0; i < children.length(); i++ ) + { + var child:XML = children[i]; + + switch (child.nodeKind()) + { + case "text": + ccText += formatCCText(child.toString()); + break; + case "element": + switch (child.localName()) + { + case "set": + case "metadata": + break; // We don't support these in tags + case "br": + ccText += "
      "; + break; + default: + ccText += child.toString(); + break; + } + break; + } + } + + return ccText; + } + + private function formatCCText(txt:String):String + { + var retString:String = txt.replace(/\s+/g, " "); + return retString; + } + + /** + * Utility method to calculate the length + * of a string non-inclusive of any HTML tags. + */ + private function calcClearTextLength(txt:String):int + { + var clrTxt:String = txt.replace(/<(.|\n)*?>/g, ""); + return clrTxt.length; + } + + private function debugLog(msg:String):void + { + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug(msg); + } + } + } + + private var ns:Namespace; + private var ttm:Namespace; + private var tts:Namespace; + private var rootNamespace:Namespace; + private var namedColorMap:Dictionary; + + CONFIG::LOGGING + { + private static const logger:Logger = org.osmf.logging.Log.getLogger("org.osmf.captioning.parsers.DFXPParser"); + } + + } +} diff --git a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/parsers/ICaptioningParser.as b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/parsers/ICaptioningParser.as index 6960f85..475c43d 100644 --- a/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/parsers/ICaptioningParser.as +++ b/lib/osmf/samples/CaptioningPlugin/src/org/osmf/captioning/parsers/ICaptioningParser.as @@ -1,51 +1,51 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioning.parsers -{ - import org.osmf.captioning.model.CaptioningDocument; - - /** - * This interface represents a captioning parser and - * allows a plugin developer the means to create a - * custom captioning plugin using a different file - * format. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - public interface ICaptioningParser - { - /** - * The parse method parses the captiong document - * and returns the root level of the Captioning - * document object model. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.0 - * @productversion OSMF 1.0 - */ - function parse(rawData:String):CaptioningDocument; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioning.parsers +{ + import org.osmf.captioning.model.CaptioningDocument; + + /** + * This interface represents a captioning parser and + * allows a plugin developer the means to create a + * custom captioning plugin using a different file + * format. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + public interface ICaptioningParser + { + /** + * The parse method parses the captiong document + * and returns the root level of the Captioning + * document object model. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.0 + * @productversion OSMF 1.0 + */ + function parse(rawData:String):CaptioningDocument; + } +} diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/.actionScriptProperties b/lib/osmf/samples/CaptioningPluginIntegrationTest/.actionScriptProperties index ece3d6a..fd9f5b6 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/.actionScriptProperties +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/.actionScriptProperties @@ -1,20 +1,20 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/.flexProperties b/lib/osmf/samples/CaptioningPluginIntegrationTest/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/.flexProperties +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/CaptioningPluginIntegrationTest.mxml b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/CaptioningPluginIntegrationTest.mxml index d562002..27c7e0a 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/CaptioningPluginIntegrationTest.mxml +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/CaptioningPluginIntegrationTest.mxml @@ -1,48 +1,48 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/CaptioningPluginIntegrationTests.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/CaptioningPluginIntegrationTests.as index 93ec51a..4e2f7f8 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/CaptioningPluginIntegrationTests.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/CaptioningPluginIntegrationTests.as @@ -1,22 +1,22 @@ -package org.osmf -{ - import flexunit.framework.TestSuite; - - import org.osmf.test.captioning.TestCaptioningPluginInfo; - import org.osmf.test.captioning.loader.TestCaptioningLoader; - import org.osmf.test.captioning.media.TestCaptioningProxyElement; - import org.osmf.test.captioning.parsers.TestDFXPParser; - - public class CaptioningPluginIntegrationTests extends TestSuite - { - public function CaptioningPluginIntegrationTests(param:Object=null) - { - super(param); - - addTestSuite(TestCaptioningPluginInfo); - addTestSuite(TestCaptioningLoader); - addTestSuite(TestCaptioningProxyElement); - addTestSuite(TestDFXPParser); - } - } -} +package org.osmf +{ + import flexunit.framework.TestSuite; + + import org.osmf.test.captioning.TestCaptioningPluginInfo; + import org.osmf.test.captioning.loader.TestCaptioningLoader; + import org.osmf.test.captioning.media.TestCaptioningProxyElement; + import org.osmf.test.captioning.parsers.TestDFXPParser; + + public class CaptioningPluginIntegrationTests extends TestSuite + { + public function CaptioningPluginIntegrationTests(param:Object=null) + { + super(param); + + addTestSuite(TestCaptioningPluginInfo); + addTestSuite(TestCaptioningLoader); + addTestSuite(TestCaptioningProxyElement); + addTestSuite(TestDFXPParser); + } + } +} diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/flexunit/TestCaseEx.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/flexunit/TestCaseEx.as index 97d6eb0..fee85fb 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/flexunit/TestCaseEx.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/flexunit/TestCaseEx.as @@ -1,116 +1,116 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.flexunit -{ - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.utils.Dictionary; - - import flexunit.framework.TestCase; - - /** - * Defines an extended version of flex unit's TestCase class, providing - * a number of additional assert methods. - */ - public class TestCaseEx extends TestCase - { - /** - * @inheritDoc - */ - public function TestCaseEx(methodName:String=null) - { - super(methodName); - } - - // Utils - // - - /** - * Asserts that a function throws an exception on being invoked. - * - * @param f The function that's expected to throw an exception. - * @param arguments The arguments to pass to the function on its invocation. - * @return The result of the function invocation. - * - */ - protected function assertThrows(f:Function, ...arguments):* - { - var result:*; - - try - { - result = f.apply(null,arguments); - fail(); - } - catch(e:Error) - { - } - - return result; - } - - /** - * Asserts that one or more events get dispatched on a function being - * invoked. - * - * @param dispatcher The expected dispatcher of the events. - * @param types The types of the events that the dispatcher is expected to dispatch. - * @param f The function that's expected to trigger the event dispatching. - * @param arguments The arguments to pass to the function on its invocation. - * @return The result of the function invocation. - * - */ - protected function assertDispatches(dispatcher:EventDispatcher, types:Array, f:Function, ...arguments):* - { - var result:*; - var dispatched:Dictionary = new Dictionary(); - function handler(event:Event):void - { - dispatched[event.type] = true; - } - - var type:String; - for each (type in types) - { - dispatcher.addEventListener(type, handler); - } - - result = f.apply(null, arguments); - - for each (type in types) - { - dispatcher.removeEventListener(type, handler); - } - - for each (type in types) - { - if (dispatched[type] != true) - { - fail("Event of type " + type + " was not fired."); - } - } - - return result; - } - - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.flexunit +{ + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.utils.Dictionary; + + import flexunit.framework.TestCase; + + /** + * Defines an extended version of flex unit's TestCase class, providing + * a number of additional assert methods. + */ + public class TestCaseEx extends TestCase + { + /** + * @inheritDoc + */ + public function TestCaseEx(methodName:String=null) + { + super(methodName); + } + + // Utils + // + + /** + * Asserts that a function throws an exception on being invoked. + * + * @param f The function that's expected to throw an exception. + * @param arguments The arguments to pass to the function on its invocation. + * @return The result of the function invocation. + * + */ + protected function assertThrows(f:Function, ...arguments):* + { + var result:*; + + try + { + result = f.apply(null,arguments); + fail(); + } + catch(e:Error) + { + } + + return result; + } + + /** + * Asserts that one or more events get dispatched on a function being + * invoked. + * + * @param dispatcher The expected dispatcher of the events. + * @param types The types of the events that the dispatcher is expected to dispatch. + * @param f The function that's expected to trigger the event dispatching. + * @param arguments The arguments to pass to the function on its invocation. + * @return The result of the function invocation. + * + */ + protected function assertDispatches(dispatcher:EventDispatcher, types:Array, f:Function, ...arguments):* + { + var result:*; + var dispatched:Dictionary = new Dictionary(); + function handler(event:Event):void + { + dispatched[event.type] = true; + } + + var type:String; + for each (type in types) + { + dispatcher.addEventListener(type, handler); + } + + result = f.apply(null, arguments); + + for each (type in types) + { + dispatcher.removeEventListener(type, handler); + } + + for each (type in types) + { + if (dispatched[type] != true) + { + fail("Event of type " + type + " was not fired."); + } + } + + return result; + } + + } } \ No newline at end of file diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/media/TestMediaElement.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/media/TestMediaElement.as index 7e25f2e..ea9c02a 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/media/TestMediaElement.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/media/TestMediaElement.as @@ -1,649 +1,649 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.media -{ - import flash.events.Event; - import flash.events.EventDispatcher; - - import org.osmf.containers.MediaContainer; - import org.osmf.events.ContainerChangeEvent; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorCodes; - import org.osmf.events.MediaErrorEvent; - import org.osmf.flexunit.TestCaseEx; - import org.osmf.metadata.Metadata; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.utils.OSMFStrings; - - public class TestMediaElement extends TestCaseEx - { - override public function setUp():void - { - super.setUp(); - - _eventDispatcher = new EventDispatcher(); - } - - override public function tearDown():void - { - super.tearDown(); - - _eventDispatcher = null; - } - - public function testGetTraitTypes():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyGetTraitTypes(mediaElement, existentTraitTypesOnInitialization); - } - - public function testGetTraitTypesAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyGetTraitTypes); - } - } - - public function testGetTraitTypesAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyGetTraitTypes, mediaElement); - } - } - - public function testHasTrait():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyHasTrait(mediaElement, existentTraitTypesOnInitialization); - } - - public function testHasTraitWhenParamIsNull():void - { - var mediaElement:MediaElement = createMediaElement(); - - try - { - mediaElement.hasTrait(null); - - fail(); - } - catch (error:ArgumentError) - { - } - } - - public function testHasTraitAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyHasTrait); - } - } - - public function testHasTraitAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyHasTrait, mediaElement); - } - } - - public function testGetTrait():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyGetTrait(mediaElement, existentTraitTypesOnInitialization); - } - - public function testGetTraitWhenParamIsNull():void - { - var mediaElement:MediaElement = createMediaElement(); - - try - { - mediaElement.getTrait(null); - - fail(); - } - catch (error:ArgumentError) - { - } - } - - public function testGetTraitAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyGetTrait); - } - } - - public function testGetTraitAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyGetTrait, mediaElement); - } - } - - public function testGetResource():void - { - var mediaElement:MediaElement = createMediaElement(); - - assertTrue(mediaElement.resource == null); - } - - public function testSetResource():void - { - var mediaElement:MediaElement = createMediaElement(); - - mediaElement.resource = resourceForMediaElement; - assertTrue(mediaElement.resource != null); - - mediaElement.resource = null; - assertTrue(mediaElement.resource == null); - } - - public function testAddMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaElementEvent.METADATA_ADD, onAdd); - var addCalled:Boolean = false; - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - assertTrue(addCalled); - - mediaElement.addMetadata(nsurl2, meta2); - - assertEquals(mediaElement.getMetadata(nsurl1), meta1); - assertEquals(mediaElement.getMetadata(nsurl2), meta2); - - // Test addition through the undocumented API results in - // an event. (This is how we simulate metadata being added - // internally.) - addCalled = false; - mediaElement.metadata.addValue("foo", meta1); - assertEquals(mediaElement.getMetadata("foo"), meta1); - assertTrue(addCalled); - - // Test the Catching of Errors - try - { - mediaElement.addMetadata(null, meta1); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - try - { - mediaElement.addMetadata(nsurl1, null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - - function onAdd(event:MediaElementEvent):void - { - addCalled = true; - assertNotNull(event.metadata); - } - } - - public function testRemoveMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onRemove); - var removeCalled:Boolean = false; - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertFalse(removeCalled); - assertEquals(mediaElement.removeMetadata(nsurl2), meta2); - assertTrue(removeCalled); - assertEquals(mediaElement.removeMetadata(nsurl2), null); - assertEquals(mediaElement.removeMetadata(nsurl1), meta1); - - // Test removal through the undocumented API results in - // an event. (This is how we simulate metadata being removed - // internally.) - removeCalled = false; - mediaElement.addMetadata("foo", meta1); - assertEquals(mediaElement.metadata.removeValue("foo"), meta1); - assertTrue(removeCalled); - - // Test the Catching of Errors - try - { - mediaElement.removeMetadata(null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - - function onRemove(event:MediaElementEvent):void - { - removeCalled = true; - assertNotNull(event.metadata); - } - } - - public function testGetMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertEquals(mediaElement.getMetadata(nsurl2), meta2); - assertEquals(mediaElement.getMetadata(nsurl1), meta1); - assertEquals(mediaElement.getMetadata("foo"), null); - - // Test the Catching of Errors - try - { - mediaElement.getMetadata(null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - } - - public function testGetMetadataNamespaceURLs():void - { - var mediaElement:MediaElement = createMediaElement(); - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertTrue(mediaElement.metadataNamespaceURLs.length == 2); - assertTrue( ( mediaElement.metadataNamespaceURLs[0] == "nsurl1" - && mediaElement.metadataNamespaceURLs[1] == "nsurl2" - ) - || ( mediaElement.metadataNamespaceURLs[0] == "nsurl2" - && mediaElement.metadataNamespaceURLs[1] == "nsurl1" - ) - ); - } - - public function testMediaErrorEventDispatch():void - { - if (hasLoadTrait) - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, 1000)); - - var eventCtr:int = 0; - - // Make sure error events dispatched on the trait are redispatched - // on the MediaElement. - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(99))); - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID))); - - function onMediaError(event:MediaErrorEvent):void - { - eventCtr++; - - if (eventCtr == 1) - { - assertTrue(event.error.errorID == 99); - assertTrue(event.error.message == ""); - assertTrue(event.target == mediaElement); - } - else if (eventCtr == 2) - { - assertTrue(event.error.errorID == MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID); - assertTrue(event.error.message == "File has invalid structure"); - assertTrue(event.target == mediaElement); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - else fail(); - } - } - } - - public function testContainer():void - { - var mediaElement:MediaElement = createMediaElement(); - var containerA:MediaContainer = new MediaContainer(); - var containerB:MediaContainer = new MediaContainer(); - - assertNull(mediaElement.container); - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerA.addMediaElement(mediaElement);} - ); - - assertEquals(containerA, mediaElement.container); - - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerB.addMediaElement(mediaElement);} - ); - - assertEquals(containerB, mediaElement.container); - - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerB.removeMediaElement(mediaElement);} - ); - - assertNull(mediaElement.container); - } - - // Protected - // - - protected function createMediaElement():MediaElement - { - // Subclasses can override to specify the MediaElement subclass - // to test. - return new MediaElement(); - } - - protected function get hasLoadTrait():Boolean - { - // Subclasses can override to specify that they start with the - // LoadTrait. - return false; - } - - protected function get resourceForMediaElement():MediaResourceBase - { - // Subclasses can override to specify a resource that the - // MediaElement can work with. - return new URLResource("http://www.example.com"); - } - - protected function get existentTraitTypesOnInitialization():Array - { - // Subclasses can override to specify the trait types which are - // expected upon initialization. - return []; - } - - protected function get existentTraitTypesAfterLoad():Array - { - // Subclasses can override to specify the trait types which are - // expected after a load. Ignored if the MediaElement - // lacks the LoadTrait. - return []; - } - - final protected function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - final protected function mustNotReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is NOT received. - fail(); - } - - final protected function get eventDispatcher():EventDispatcher - { - return _eventDispatcher; - } - - // Internals - // - - private function verifyGetTraitTypes(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - assertTrue(mediaElement.traitTypes != null); - assertTrue(mediaElement.traitTypes.length == expectedTraitTypes.length); - - // Verify all expected traits are in traitTypes. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.traitTypes.indexOf(traitType) >= 0); - } - - // Verify all other traits are not in traitTypes. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.traitTypes.indexOf(traitType) == -1); - } - } - - private function verifyHasTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - // Verify hasTrait returns true for all expected traits. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.hasTrait(traitType) == true); - } - - // Verify hasTrait returns false for all unexpected traits. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.hasTrait(traitType) == false); - } - } - - private function verifyGetTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - // Verify getTrait returns a result for all expected traits. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.getTrait(traitType) != null); - } - - // Verify getTrait returns false for all unexpected traits. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.getTrait(traitType) == null); - } - } - - private function callAfterLoad(func:Function, triggerTestCompleteEvent:Boolean=true):MediaElement - { - assertTrue(hasLoadTrait); - - if (triggerTestCompleteEvent) - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); - } - - var mediaElement:MediaElement = createMediaElement(); - mediaElement.resource = resourceForMediaElement; - - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCallAfterLoad - ); - loadTrait.load(); - - function onTestCallAfterLoad(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterLoad); - - if (func != null) - { - func(mediaElement, existentTraitTypesAfterLoad); - } - - if (triggerTestCompleteEvent) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - return mediaElement; - } - - private function callAfterUnload(func:Function, mediaElement:MediaElement):void - { - assertTrue(hasLoadTrait); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); - - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - - // If the MediaElement is not yet loaded, wait until it is. - if (loadTrait.loadState == LoadState.READY) - { - completeCallAfterUnload(func, mediaElement); - } - else - { - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCallAfterUnload - ); - - function onTestCallAfterUnload(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterUnload); - - completeCallAfterUnload(func, mediaElement); - } - } - } - } - - private function completeCallAfterUnload(func:Function, mediaElement:MediaElement):void - { - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCompleteCallAfterUnload - ); - loadTrait.unload(); - - function onTestCompleteCallAfterUnload(event:LoadEvent):void - { - if (event.loadState == LoadState.UNINITIALIZED) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCompleteCallAfterUnload); - - func(mediaElement, existentTraitTypesOnInitialization); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - private function inverseOf(traitTypes:Array):Array - { - var inverseTraitTypes:Array = []; - - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.AUDIO); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.BUFFER); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DRM); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DYNAMIC_STREAM); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.LOAD); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.PLAY); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.SEEK); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.TIME); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DISPLAY_OBJECT); - - return inverseTraitTypes; - } - - private function addIfNotPresent(traitTypes:Array, results:Array, traitType:String):void - { - if (traitTypes.indexOf(traitType) == -1) - { - results.push(traitType); - } - } - - private static const ASYNC_DELAY:Number = 8000; - - private var _eventDispatcher:EventDispatcher; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.media +{ + import flash.events.Event; + import flash.events.EventDispatcher; + + import org.osmf.containers.MediaContainer; + import org.osmf.events.ContainerChangeEvent; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorCodes; + import org.osmf.events.MediaErrorEvent; + import org.osmf.flexunit.TestCaseEx; + import org.osmf.metadata.Metadata; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.utils.OSMFStrings; + + public class TestMediaElement extends TestCaseEx + { + override public function setUp():void + { + super.setUp(); + + _eventDispatcher = new EventDispatcher(); + } + + override public function tearDown():void + { + super.tearDown(); + + _eventDispatcher = null; + } + + public function testGetTraitTypes():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyGetTraitTypes(mediaElement, existentTraitTypesOnInitialization); + } + + public function testGetTraitTypesAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyGetTraitTypes); + } + } + + public function testGetTraitTypesAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyGetTraitTypes, mediaElement); + } + } + + public function testHasTrait():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyHasTrait(mediaElement, existentTraitTypesOnInitialization); + } + + public function testHasTraitWhenParamIsNull():void + { + var mediaElement:MediaElement = createMediaElement(); + + try + { + mediaElement.hasTrait(null); + + fail(); + } + catch (error:ArgumentError) + { + } + } + + public function testHasTraitAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyHasTrait); + } + } + + public function testHasTraitAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyHasTrait, mediaElement); + } + } + + public function testGetTrait():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyGetTrait(mediaElement, existentTraitTypesOnInitialization); + } + + public function testGetTraitWhenParamIsNull():void + { + var mediaElement:MediaElement = createMediaElement(); + + try + { + mediaElement.getTrait(null); + + fail(); + } + catch (error:ArgumentError) + { + } + } + + public function testGetTraitAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyGetTrait); + } + } + + public function testGetTraitAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyGetTrait, mediaElement); + } + } + + public function testGetResource():void + { + var mediaElement:MediaElement = createMediaElement(); + + assertTrue(mediaElement.resource == null); + } + + public function testSetResource():void + { + var mediaElement:MediaElement = createMediaElement(); + + mediaElement.resource = resourceForMediaElement; + assertTrue(mediaElement.resource != null); + + mediaElement.resource = null; + assertTrue(mediaElement.resource == null); + } + + public function testAddMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaElementEvent.METADATA_ADD, onAdd); + var addCalled:Boolean = false; + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + assertTrue(addCalled); + + mediaElement.addMetadata(nsurl2, meta2); + + assertEquals(mediaElement.getMetadata(nsurl1), meta1); + assertEquals(mediaElement.getMetadata(nsurl2), meta2); + + // Test addition through the undocumented API results in + // an event. (This is how we simulate metadata being added + // internally.) + addCalled = false; + mediaElement.metadata.addValue("foo", meta1); + assertEquals(mediaElement.getMetadata("foo"), meta1); + assertTrue(addCalled); + + // Test the Catching of Errors + try + { + mediaElement.addMetadata(null, meta1); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + try + { + mediaElement.addMetadata(nsurl1, null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + + function onAdd(event:MediaElementEvent):void + { + addCalled = true; + assertNotNull(event.metadata); + } + } + + public function testRemoveMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onRemove); + var removeCalled:Boolean = false; + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertFalse(removeCalled); + assertEquals(mediaElement.removeMetadata(nsurl2), meta2); + assertTrue(removeCalled); + assertEquals(mediaElement.removeMetadata(nsurl2), null); + assertEquals(mediaElement.removeMetadata(nsurl1), meta1); + + // Test removal through the undocumented API results in + // an event. (This is how we simulate metadata being removed + // internally.) + removeCalled = false; + mediaElement.addMetadata("foo", meta1); + assertEquals(mediaElement.metadata.removeValue("foo"), meta1); + assertTrue(removeCalled); + + // Test the Catching of Errors + try + { + mediaElement.removeMetadata(null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + + function onRemove(event:MediaElementEvent):void + { + removeCalled = true; + assertNotNull(event.metadata); + } + } + + public function testGetMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertEquals(mediaElement.getMetadata(nsurl2), meta2); + assertEquals(mediaElement.getMetadata(nsurl1), meta1); + assertEquals(mediaElement.getMetadata("foo"), null); + + // Test the Catching of Errors + try + { + mediaElement.getMetadata(null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + } + + public function testGetMetadataNamespaceURLs():void + { + var mediaElement:MediaElement = createMediaElement(); + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertTrue(mediaElement.metadataNamespaceURLs.length == 2); + assertTrue( ( mediaElement.metadataNamespaceURLs[0] == "nsurl1" + && mediaElement.metadataNamespaceURLs[1] == "nsurl2" + ) + || ( mediaElement.metadataNamespaceURLs[0] == "nsurl2" + && mediaElement.metadataNamespaceURLs[1] == "nsurl1" + ) + ); + } + + public function testMediaErrorEventDispatch():void + { + if (hasLoadTrait) + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, 1000)); + + var eventCtr:int = 0; + + // Make sure error events dispatched on the trait are redispatched + // on the MediaElement. + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(99))); + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID))); + + function onMediaError(event:MediaErrorEvent):void + { + eventCtr++; + + if (eventCtr == 1) + { + assertTrue(event.error.errorID == 99); + assertTrue(event.error.message == ""); + assertTrue(event.target == mediaElement); + } + else if (eventCtr == 2) + { + assertTrue(event.error.errorID == MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID); + assertTrue(event.error.message == "File has invalid structure"); + assertTrue(event.target == mediaElement); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + else fail(); + } + } + } + + public function testContainer():void + { + var mediaElement:MediaElement = createMediaElement(); + var containerA:MediaContainer = new MediaContainer(); + var containerB:MediaContainer = new MediaContainer(); + + assertNull(mediaElement.container); + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerA.addMediaElement(mediaElement);} + ); + + assertEquals(containerA, mediaElement.container); + + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerB.addMediaElement(mediaElement);} + ); + + assertEquals(containerB, mediaElement.container); + + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerB.removeMediaElement(mediaElement);} + ); + + assertNull(mediaElement.container); + } + + // Protected + // + + protected function createMediaElement():MediaElement + { + // Subclasses can override to specify the MediaElement subclass + // to test. + return new MediaElement(); + } + + protected function get hasLoadTrait():Boolean + { + // Subclasses can override to specify that they start with the + // LoadTrait. + return false; + } + + protected function get resourceForMediaElement():MediaResourceBase + { + // Subclasses can override to specify a resource that the + // MediaElement can work with. + return new URLResource("http://www.example.com"); + } + + protected function get existentTraitTypesOnInitialization():Array + { + // Subclasses can override to specify the trait types which are + // expected upon initialization. + return []; + } + + protected function get existentTraitTypesAfterLoad():Array + { + // Subclasses can override to specify the trait types which are + // expected after a load. Ignored if the MediaElement + // lacks the LoadTrait. + return []; + } + + final protected function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + final protected function mustNotReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is NOT received. + fail(); + } + + final protected function get eventDispatcher():EventDispatcher + { + return _eventDispatcher; + } + + // Internals + // + + private function verifyGetTraitTypes(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + assertTrue(mediaElement.traitTypes != null); + assertTrue(mediaElement.traitTypes.length == expectedTraitTypes.length); + + // Verify all expected traits are in traitTypes. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.traitTypes.indexOf(traitType) >= 0); + } + + // Verify all other traits are not in traitTypes. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.traitTypes.indexOf(traitType) == -1); + } + } + + private function verifyHasTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + // Verify hasTrait returns true for all expected traits. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.hasTrait(traitType) == true); + } + + // Verify hasTrait returns false for all unexpected traits. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.hasTrait(traitType) == false); + } + } + + private function verifyGetTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + // Verify getTrait returns a result for all expected traits. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.getTrait(traitType) != null); + } + + // Verify getTrait returns false for all unexpected traits. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.getTrait(traitType) == null); + } + } + + private function callAfterLoad(func:Function, triggerTestCompleteEvent:Boolean=true):MediaElement + { + assertTrue(hasLoadTrait); + + if (triggerTestCompleteEvent) + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); + } + + var mediaElement:MediaElement = createMediaElement(); + mediaElement.resource = resourceForMediaElement; + + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCallAfterLoad + ); + loadTrait.load(); + + function onTestCallAfterLoad(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterLoad); + + if (func != null) + { + func(mediaElement, existentTraitTypesAfterLoad); + } + + if (triggerTestCompleteEvent) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + return mediaElement; + } + + private function callAfterUnload(func:Function, mediaElement:MediaElement):void + { + assertTrue(hasLoadTrait); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); + + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + + // If the MediaElement is not yet loaded, wait until it is. + if (loadTrait.loadState == LoadState.READY) + { + completeCallAfterUnload(func, mediaElement); + } + else + { + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCallAfterUnload + ); + + function onTestCallAfterUnload(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterUnload); + + completeCallAfterUnload(func, mediaElement); + } + } + } + } + + private function completeCallAfterUnload(func:Function, mediaElement:MediaElement):void + { + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCompleteCallAfterUnload + ); + loadTrait.unload(); + + function onTestCompleteCallAfterUnload(event:LoadEvent):void + { + if (event.loadState == LoadState.UNINITIALIZED) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCompleteCallAfterUnload); + + func(mediaElement, existentTraitTypesOnInitialization); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + private function inverseOf(traitTypes:Array):Array + { + var inverseTraitTypes:Array = []; + + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.AUDIO); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.BUFFER); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DRM); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DYNAMIC_STREAM); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.LOAD); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.PLAY); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.SEEK); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.TIME); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DISPLAY_OBJECT); + + return inverseTraitTypes; + } + + private function addIfNotPresent(traitTypes:Array, results:Array, traitType:String):void + { + if (traitTypes.indexOf(traitType) == -1) + { + results.push(traitType); + } + } + + private static const ASYNC_DELAY:Number = 8000; + + private var _eventDispatcher:EventDispatcher; + } } \ No newline at end of file diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/TestCaptioningPluginInfo.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/TestCaptioningPluginInfo.as index 1024b75..522d3d6 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/TestCaptioningPluginInfo.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/TestCaptioningPluginInfo.as @@ -1,63 +1,63 @@ -package org.osmf.test.captioning -{ - import flexunit.framework.TestCase; - - import org.osmf.captioning.CaptioningPluginInfo; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.PluginInfo; - - public class TestCaptioningPluginInfo extends TestCase - { - public function testGetMediaInfoAt():void - { - var pluginInfo:PluginInfo = new CaptioningPluginInfo(); - - assertNotNull(pluginInfo); - - var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(0); - - assertNotNull(item); - } - - public function testGetMediaInfoAtWithBadIndex():void - { - var pluginInfo:PluginInfo = new CaptioningPluginInfo(); - - assertNotNull(pluginInfo); - - try - { - var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(10); - fail(); - } - catch(error:RangeError) - { - } - } - - public function testIsFrameworkVersionSupported():void - { - var pluginInfo:PluginInfo = new CaptioningPluginInfo(); - assertNotNull(pluginInfo); - - assertEquals(true, pluginInfo.isFrameworkVersionSupported("1.0.0")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.0.1")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.5.1")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.7.0")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.4.9")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported(null)); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("abc")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("foo.bar")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("foobar.")); - } - - public function testNumMediaInfos():void - { - var pluginInfo:PluginInfo = new CaptioningPluginInfo(); - assertNotNull(pluginInfo); - - assertTrue(pluginInfo.numMediaFactoryItems > 0); - } - } -} +package org.osmf.test.captioning +{ + import flexunit.framework.TestCase; + + import org.osmf.captioning.CaptioningPluginInfo; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.PluginInfo; + + public class TestCaptioningPluginInfo extends TestCase + { + public function testGetMediaInfoAt():void + { + var pluginInfo:PluginInfo = new CaptioningPluginInfo(); + + assertNotNull(pluginInfo); + + var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(0); + + assertNotNull(item); + } + + public function testGetMediaInfoAtWithBadIndex():void + { + var pluginInfo:PluginInfo = new CaptioningPluginInfo(); + + assertNotNull(pluginInfo); + + try + { + var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(10); + fail(); + } + catch(error:RangeError) + { + } + } + + public function testIsFrameworkVersionSupported():void + { + var pluginInfo:PluginInfo = new CaptioningPluginInfo(); + assertNotNull(pluginInfo); + + assertEquals(true, pluginInfo.isFrameworkVersionSupported("1.0.0")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.0.1")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.5.1")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.7.0")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.4.9")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported(null)); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("abc")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("foo.bar")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("foobar.")); + } + + public function testNumMediaInfos():void + { + var pluginInfo:PluginInfo = new CaptioningPluginInfo(); + assertNotNull(pluginInfo); + + assertTrue(pluginInfo.numMediaFactoryItems > 0); + } + } +} diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/loader/TestCaptioningLoader.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/loader/TestCaptioningLoader.as index e29462a..e437d81 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/loader/TestCaptioningLoader.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/loader/TestCaptioningLoader.as @@ -1,180 +1,180 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.test.captioning.loader -{ - import flash.events.*; - - import org.osmf.captioning.loader.*; - import org.osmf.captioning.model.*; - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaError; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.test.captioning.CaptioningTestConstants; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.traits.TestLoaderBase; - import org.osmf.utils.HTTPLoader; - import org.osmf.utils.MockHTTPLoader; - import org.osmf.utils.NullResource; - - public class TestCaptioningLoader extends TestLoaderBase - { - override public function setUp():void - { - eventDispatcher = new EventDispatcher(); - - // Change to HTTPLoader to run against the network. - httpLoader = new MockHTTPLoader(); - - super.setUp(); - } - - override public function tearDown():void - { - super.tearDown(); - - eventDispatcher = null; - httpLoader = null; - } - - public function testLoadWithValidCaptioningDocument():void - { - eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidCaptioningDocument); - loader.load(createLoadTrait(loader, SUCCESSFUL_RESOURCE)); - } - - private function onTestLoadWithValidCaptioningDocument(event:LoaderEvent):void - { - if (event.newState == LoadState.READY) - { - // Just check that we got a valid Captioning DOM back - var document:CaptioningDocument = CaptioningLoadTrait(event.loadTrait).document; - assertTrue(document != null); - assertTrue(document.numCaptions > 0); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - - //--------------------------------------------------------------------- - - override protected function createInterfaceObject(... args):Object - { - return new CaptioningLoader(httpLoader); - } - - override protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - var mockLoader:MockHTTPLoader = httpLoader as MockHTTPLoader; - if (mockLoader) - { - if (resource == successfulResource) - { - mockLoader.setExpectationForURL - ( URLResource(resource).url - , true - , CaptioningTestConstants.CAPTIONING_DOCUMENT_CONTENTS - ); - } - else if (resource == failedResource) - { - mockLoader.setExpectationForURL - ( URLResource(resource).url - , false - , null - ); - } - else if (resource == unhandledResource) - { - mockLoader.setExpectationForURL - ( URLResource(resource).url - , false - , null - ); - } - } - return new CaptioningLoadTrait(loader, resource); - } - - override protected function get successfulResource():MediaResourceBase - { - return SUCCESSFUL_RESOURCE; - } - - override protected function get failedResource():MediaResourceBase - { - return FAILED_RESOURCE; - } - - override protected function get unhandledResource():MediaResourceBase - { - return UNHANDLED_RESOURCE; - } - - override protected function verifyMediaErrorOnLoadFailure(error:MediaError):void - { - } - - override public function testCanHandleResource():void - { - super.testCanHandleResource(); - - // Verify some valid resources. - assertTrue(loader.canHandleResource(new URLResource("http://example.com"))); - assertTrue(loader.canHandleResource(new URLResource("http://example.com/video.flv"))); - assertTrue(loader.canHandleResource(new URLResource("http://example.com/script.php?param=value"))); - assertTrue(loader.canHandleResource(new URLResource("https://example.com"))); - assertTrue(loader.canHandleResource(new URLResource("https://example.com/video.flv"))); - assertTrue(loader.canHandleResource(new URLResource("https://example.com/script.php?param=value"))); - assertTrue(loader.canHandleResource(new URLResource("assets/audio.mp3"))); - assertTrue(loader.canHandleResource(new URLResource("audio.mp3"))); - assertTrue(loader.canHandleResource(new URLResource("foo"))); - - // And some invalid ones. - assertFalse(loader.canHandleResource(new URLResource("file:///audio.mp3"))); - assertFalse(loader.canHandleResource(new URLResource("httpt://example.com"))); - assertFalse(loader.canHandleResource(new URLResource(""))); - assertFalse(loader.canHandleResource(new URLResource(null))); - assertFalse(loader.canHandleResource(new NullResource())); - assertFalse(loader.canHandleResource(null)); - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder - } - - private static const TEST_TIME:int = 8000; - - private var httpLoader:HTTPLoader; - private var eventDispatcher:EventDispatcher; - - private static const SUCCESSFUL_RESOURCE:URLResource = new URLResource(CaptioningTestConstants.CAPTIONING_DOCUMENT_URL); - private static const FAILED_RESOURCE:URLResource = new URLResource(CaptioningTestConstants.MISSING_CAPTIONING_DOCUMENT_URL); - private static const UNHANDLED_RESOURCE:URLResource = new URLResource("ftp://example.com"); - - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.test.captioning.loader +{ + import flash.events.*; + + import org.osmf.captioning.loader.*; + import org.osmf.captioning.model.*; + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaError; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.test.captioning.CaptioningTestConstants; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.traits.TestLoaderBase; + import org.osmf.utils.HTTPLoader; + import org.osmf.utils.MockHTTPLoader; + import org.osmf.utils.NullResource; + + public class TestCaptioningLoader extends TestLoaderBase + { + override public function setUp():void + { + eventDispatcher = new EventDispatcher(); + + // Change to HTTPLoader to run against the network. + httpLoader = new MockHTTPLoader(); + + super.setUp(); + } + + override public function tearDown():void + { + super.tearDown(); + + eventDispatcher = null; + httpLoader = null; + } + + public function testLoadWithValidCaptioningDocument():void + { + eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidCaptioningDocument); + loader.load(createLoadTrait(loader, SUCCESSFUL_RESOURCE)); + } + + private function onTestLoadWithValidCaptioningDocument(event:LoaderEvent):void + { + if (event.newState == LoadState.READY) + { + // Just check that we got a valid Captioning DOM back + var document:CaptioningDocument = CaptioningLoadTrait(event.loadTrait).document; + assertTrue(document != null); + assertTrue(document.numCaptions > 0); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + + //--------------------------------------------------------------------- + + override protected function createInterfaceObject(... args):Object + { + return new CaptioningLoader(httpLoader); + } + + override protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait + { + var mockLoader:MockHTTPLoader = httpLoader as MockHTTPLoader; + if (mockLoader) + { + if (resource == successfulResource) + { + mockLoader.setExpectationForURL + ( URLResource(resource).url + , true + , CaptioningTestConstants.CAPTIONING_DOCUMENT_CONTENTS + ); + } + else if (resource == failedResource) + { + mockLoader.setExpectationForURL + ( URLResource(resource).url + , false + , null + ); + } + else if (resource == unhandledResource) + { + mockLoader.setExpectationForURL + ( URLResource(resource).url + , false + , null + ); + } + } + return new CaptioningLoadTrait(loader, resource); + } + + override protected function get successfulResource():MediaResourceBase + { + return SUCCESSFUL_RESOURCE; + } + + override protected function get failedResource():MediaResourceBase + { + return FAILED_RESOURCE; + } + + override protected function get unhandledResource():MediaResourceBase + { + return UNHANDLED_RESOURCE; + } + + override protected function verifyMediaErrorOnLoadFailure(error:MediaError):void + { + } + + override public function testCanHandleResource():void + { + super.testCanHandleResource(); + + // Verify some valid resources. + assertTrue(loader.canHandleResource(new URLResource("http://example.com"))); + assertTrue(loader.canHandleResource(new URLResource("http://example.com/video.flv"))); + assertTrue(loader.canHandleResource(new URLResource("http://example.com/script.php?param=value"))); + assertTrue(loader.canHandleResource(new URLResource("https://example.com"))); + assertTrue(loader.canHandleResource(new URLResource("https://example.com/video.flv"))); + assertTrue(loader.canHandleResource(new URLResource("https://example.com/script.php?param=value"))); + assertTrue(loader.canHandleResource(new URLResource("assets/audio.mp3"))); + assertTrue(loader.canHandleResource(new URLResource("audio.mp3"))); + assertTrue(loader.canHandleResource(new URLResource("foo"))); + + // And some invalid ones. + assertFalse(loader.canHandleResource(new URLResource("file:///audio.mp3"))); + assertFalse(loader.canHandleResource(new URLResource("httpt://example.com"))); + assertFalse(loader.canHandleResource(new URLResource(""))); + assertFalse(loader.canHandleResource(new URLResource(null))); + assertFalse(loader.canHandleResource(new NullResource())); + assertFalse(loader.canHandleResource(null)); + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder + } + + private static const TEST_TIME:int = 8000; + + private var httpLoader:HTTPLoader; + private var eventDispatcher:EventDispatcher; + + private static const SUCCESSFUL_RESOURCE:URLResource = new URLResource(CaptioningTestConstants.CAPTIONING_DOCUMENT_URL); + private static const FAILED_RESOURCE:URLResource = new URLResource(CaptioningTestConstants.MISSING_CAPTIONING_DOCUMENT_URL); + private static const UNHANDLED_RESOURCE:URLResource = new URLResource("ftp://example.com"); + + } +} diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/media/TestCaptioningProxyElement.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/media/TestCaptioningProxyElement.as index ab116ab..c518475 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/media/TestCaptioningProxyElement.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/media/TestCaptioningProxyElement.as @@ -1,205 +1,205 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.test.captioning.media -{ - import flash.events.Event; - - import org.osmf.captioning.CaptioningPluginInfo; - import org.osmf.captioning.media.CaptioningProxyElement; - import org.osmf.elements.VideoElement; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.MediaElement; - import org.osmf.media.TestMediaElement; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.test.captioning.CaptioningTestConstants; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - - - public class TestCaptioningProxyElement extends TestMediaElement - { - public function testConstructor():void - { - var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(new MediaElement()); - assertNotNull(proxyElement); - } - - - public function testSetProxiedElement():void - { - var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(); - - // Should not throw an exception - try - { - proxyElement.proxiedElement = null; - } - catch(error:Error) - { - fail(); - } - } - - /** - * Test loading with valid metadata and tell the CaptioningProxyElement class - * we DO NOT want to continue the load if the captioning document load and parse - * fails. - */ - public function testLoadWithValidMetadata():void - { - var mediaElement:MediaElement = new VideoElement(); - mediaElement.resource = createResource(CaptioningTestConstants.CAPTIONING_DOCUMENT_URL); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TIMEOUT)); - - var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(mediaElement, false); - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange) - - var proxyLoadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait - proxyLoadTrait.load(); - - function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - /** - * Test loading with invalid metadata and tell the CaptioningProxyElement class - * we DO NOT want to continue the media element load if the captioning document load fails. - */ - public function testLoadWithInvalidMetadataAndDoNotContinueLoadingMedia():void - { - // Test with a bad url - doLoadWithInvalidMetadataAndDoNotContinueLoadingMedia(CaptioningTestConstants.INVALID_CAPTIONING_DOCUMENT_URL); - // Test with null url - doLoadWithInvalidMetadataAndDoNotContinueLoadingMedia(null); - // Test with null facet - doLoadWithInvalidMetadataAndDoNotContinueLoadingMedia(null, true); - } - - /** - * Test loading with invalid metadata and tell the CaptioningProxyElement class - * we DO want to continue the media element load if the captioning document load fails. - */ - public function testLoadWithInvalidMetadataAndContinueLoadingMedia():void - { - // Test with a bad url - doLoadWithInvalidMetadataAndContinueLoadingMedia(CaptioningTestConstants.INVALID_CAPTIONING_DOCUMENT_URL); - // Test with null url - doLoadWithInvalidMetadataAndContinueLoadingMedia(null); - } - - ////////////////////////////////////////////////////////// - // - // Helper methods - // - ////////////////////////////////////////////////////////// - - private function doLoadWithInvalidMetadataAndDoNotContinueLoadingMedia(metadataURL:String, nullFacet:Boolean=false):void - { - var mediaElement:MediaElement = new VideoElement(); - - mediaElement.resource = nullFacet ? createResourceWithBadFacet() : createResource(metadataURL); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TIMEOUT)); - - var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(null, false); - proxyElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - proxyElement.proxiedElement = mediaElement; - - var loadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - loadTrait.load(); - - function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.LOAD_ERROR) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - - function onMediaError(event:MediaErrorEvent):void - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - - private function doLoadWithInvalidMetadataAndContinueLoadingMedia(metadataURL:String):void - { - var mediaElement:MediaElement = new VideoElement(); - mediaElement.resource = createResource(metadataURL); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TIMEOUT)); - - var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(mediaElement, true); - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange) - - var proxyLoadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait - proxyLoadTrait.load(); - - assertTrue(proxyElement.continueLoadOnFailure); - - function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - private function createResource(captioningDoc:String):URLResource - { - var resource:URLResource = new URLResource(REMOTE_STREAM); - - var metadata:Metadata = new Metadata(); - metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, captioningDoc); - resource.addMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE, metadata); - - return resource; - } - - private function createResourceWithBadFacet():URLResource - { - var resource:URLResource = new URLResource(REMOTE_STREAM); - - var metadata:Metadata = new Metadata(); - metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, null); - resource.addMetadataValue("http://www.osmf.bogus/captioning/1.0", metadata); - - return resource; - } - - private static const REMOTE_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - private static const TIMEOUT:int = 8000; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.test.captioning.media +{ + import flash.events.Event; + + import org.osmf.captioning.CaptioningPluginInfo; + import org.osmf.captioning.media.CaptioningProxyElement; + import org.osmf.elements.VideoElement; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.MediaElement; + import org.osmf.media.TestMediaElement; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.test.captioning.CaptioningTestConstants; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + + + public class TestCaptioningProxyElement extends TestMediaElement + { + public function testConstructor():void + { + var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(new MediaElement()); + assertNotNull(proxyElement); + } + + + public function testSetProxiedElement():void + { + var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(); + + // Should not throw an exception + try + { + proxyElement.proxiedElement = null; + } + catch(error:Error) + { + fail(); + } + } + + /** + * Test loading with valid metadata and tell the CaptioningProxyElement class + * we DO NOT want to continue the load if the captioning document load and parse + * fails. + */ + public function testLoadWithValidMetadata():void + { + var mediaElement:MediaElement = new VideoElement(); + mediaElement.resource = createResource(CaptioningTestConstants.CAPTIONING_DOCUMENT_URL); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TIMEOUT)); + + var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(mediaElement, false); + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange) + + var proxyLoadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait + proxyLoadTrait.load(); + + function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + /** + * Test loading with invalid metadata and tell the CaptioningProxyElement class + * we DO NOT want to continue the media element load if the captioning document load fails. + */ + public function testLoadWithInvalidMetadataAndDoNotContinueLoadingMedia():void + { + // Test with a bad url + doLoadWithInvalidMetadataAndDoNotContinueLoadingMedia(CaptioningTestConstants.INVALID_CAPTIONING_DOCUMENT_URL); + // Test with null url + doLoadWithInvalidMetadataAndDoNotContinueLoadingMedia(null); + // Test with null facet + doLoadWithInvalidMetadataAndDoNotContinueLoadingMedia(null, true); + } + + /** + * Test loading with invalid metadata and tell the CaptioningProxyElement class + * we DO want to continue the media element load if the captioning document load fails. + */ + public function testLoadWithInvalidMetadataAndContinueLoadingMedia():void + { + // Test with a bad url + doLoadWithInvalidMetadataAndContinueLoadingMedia(CaptioningTestConstants.INVALID_CAPTIONING_DOCUMENT_URL); + // Test with null url + doLoadWithInvalidMetadataAndContinueLoadingMedia(null); + } + + ////////////////////////////////////////////////////////// + // + // Helper methods + // + ////////////////////////////////////////////////////////// + + private function doLoadWithInvalidMetadataAndDoNotContinueLoadingMedia(metadataURL:String, nullFacet:Boolean=false):void + { + var mediaElement:MediaElement = new VideoElement(); + + mediaElement.resource = nullFacet ? createResourceWithBadFacet() : createResource(metadataURL); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TIMEOUT)); + + var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(null, false); + proxyElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + proxyElement.proxiedElement = mediaElement; + + var loadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + loadTrait.load(); + + function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.LOAD_ERROR) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + + function onMediaError(event:MediaErrorEvent):void + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + + private function doLoadWithInvalidMetadataAndContinueLoadingMedia(metadataURL:String):void + { + var mediaElement:MediaElement = new VideoElement(); + mediaElement.resource = createResource(metadataURL); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TIMEOUT)); + + var proxyElement:CaptioningProxyElement = new CaptioningProxyElement(mediaElement, true); + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange) + + var proxyLoadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait + proxyLoadTrait.load(); + + assertTrue(proxyElement.continueLoadOnFailure); + + function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + private function createResource(captioningDoc:String):URLResource + { + var resource:URLResource = new URLResource(REMOTE_STREAM); + + var metadata:Metadata = new Metadata(); + metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, captioningDoc); + resource.addMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE, metadata); + + return resource; + } + + private function createResourceWithBadFacet():URLResource + { + var resource:URLResource = new URLResource(REMOTE_STREAM); + + var metadata:Metadata = new Metadata(); + metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, null); + resource.addMetadataValue("http://www.osmf.bogus/captioning/1.0", metadata); + + return resource; + } + + private static const REMOTE_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + private static const TIMEOUT:int = 8000; + } +} diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/parsers/TestDFXPParser.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/parsers/TestDFXPParser.as index d819fde..a785fd7 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/parsers/TestDFXPParser.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/test/captioning/parsers/TestDFXPParser.as @@ -1,122 +1,122 @@ -package org.osmf.test.captioning.parsers -{ - import flash.errors.IllegalOperationError; - - import flexunit.framework.TestCase; - - import org.osmf.captioning.model.Caption; - import org.osmf.captioning.model.CaptionFormat; - import org.osmf.captioning.model.CaptionStyle; - import org.osmf.captioning.model.CaptioningDocument; - import org.osmf.captioning.parsers.DFXPParser; - import org.osmf.test.captioning.CaptioningTestConstants; - - public class TestDFXPParser extends TestCase - { - public function TestDFXPParser(methodName:String=null) - { - super(methodName); - } - public function testParser():void - { - var parser:DFXPParser = new DFXPParser(); - var document:CaptioningDocument = parser.parse(CaptioningTestConstants.CAPTIONING_DOCUMENT_CONTENTS_FULL.toXMLString()); - - assertTrue(document.copyright.length > 0); - assertTrue(document.description.length > 0); - assertTrue(document.title.length > 0); - - assertTrue(document.numCaptions > 0); - for (var i:int = 0; i < document.numCaptions; i++) - { - var caption:Caption = document.getCaptionAt(i); - assertTrue(caption.clearText.length > 0); - assertTrue(caption.text.length > 0); - - var maxIndex:int = caption.numCaptionFormats; - try - { - caption.getCaptionFormatAt(maxIndex + 1); - fail(); - } - catch(err:IllegalOperationError) - { - - } - - for (var j:int = 0; j < caption.numCaptionFormats; j++) - { - var format:CaptionFormat = caption.getCaptionFormatAt(j); - assertTrue(format.startIndex >= 0); - assertTrue(format.endIndex > format.startIndex); - var style:CaptionStyle = format.style; - - if (style.backgroundColor != null) - { - assertTrue((style.backgroundColor as int) > 0); - } - - if (style.backgroundColorAlpha != null) - { - assertTrue((style.backgroundColorAlpha as int) > 0); - } - - if (style.fontFamily != null && style.fontFamily != "") - { - assertTrue(style.fontFamily.length > 0); - } - - if (style.fontStyle != null && style.fontStyle != "") - { - assertTrue(style.fontStyle == "normal" || style.fontStyle == "italic"); - } - - if (style.fontWeight != null && style.fontWeight != "") - { - assertTrue(style.fontWeight == "normal" || style.fontWeight == "bold"); - } - - if (style.textAlign != null && style.textAlign != "") - { - assertTrue(style.textAlign == "left" || style.textAlign == "center" || style.textAlign == "right"); - } - - } - } - } - - public function testParserWithBadFile():void - { - var parser:DFXPParser = new DFXPParser(); - - try - { - var document:CaptioningDocument = parser.parse(CaptioningTestConstants.INVALID_XML_CAPTIONING_DOCUMENT_CONTENTS); - fail(); - } - catch (error:Error) - { - - } - } - - public function testParserWithNoBodyTag():void - { - var parser:DFXPParser = new DFXPParser(); - var document:CaptioningDocument = parser.parse(CaptioningTestConstants.CAPTIONING_DOCUMENT_CONTENTS_NO_BODY.toXMLString()); - - assertTrue(document.numCaptions == 0); - } - - public function testParserWithNoDivTag():void - { - var parser:DFXPParser = new DFXPParser(); - var document:CaptioningDocument = parser.parse(CaptioningTestConstants.CAPTIONING_DOCUMENT_CONTENTS_NO_DIV.toXMLString()); - - assertTrue(document.numCaptions > 0); - - } - - - } -} +package org.osmf.test.captioning.parsers +{ + import flash.errors.IllegalOperationError; + + import flexunit.framework.TestCase; + + import org.osmf.captioning.model.Caption; + import org.osmf.captioning.model.CaptionFormat; + import org.osmf.captioning.model.CaptionStyle; + import org.osmf.captioning.model.CaptioningDocument; + import org.osmf.captioning.parsers.DFXPParser; + import org.osmf.test.captioning.CaptioningTestConstants; + + public class TestDFXPParser extends TestCase + { + public function TestDFXPParser(methodName:String=null) + { + super(methodName); + } + public function testParser():void + { + var parser:DFXPParser = new DFXPParser(); + var document:CaptioningDocument = parser.parse(CaptioningTestConstants.CAPTIONING_DOCUMENT_CONTENTS_FULL.toXMLString()); + + assertTrue(document.copyright.length > 0); + assertTrue(document.description.length > 0); + assertTrue(document.title.length > 0); + + assertTrue(document.numCaptions > 0); + for (var i:int = 0; i < document.numCaptions; i++) + { + var caption:Caption = document.getCaptionAt(i); + assertTrue(caption.clearText.length > 0); + assertTrue(caption.text.length > 0); + + var maxIndex:int = caption.numCaptionFormats; + try + { + caption.getCaptionFormatAt(maxIndex + 1); + fail(); + } + catch(err:IllegalOperationError) + { + + } + + for (var j:int = 0; j < caption.numCaptionFormats; j++) + { + var format:CaptionFormat = caption.getCaptionFormatAt(j); + assertTrue(format.startIndex >= 0); + assertTrue(format.endIndex > format.startIndex); + var style:CaptionStyle = format.style; + + if (style.backgroundColor != null) + { + assertTrue((style.backgroundColor as int) > 0); + } + + if (style.backgroundColorAlpha != null) + { + assertTrue((style.backgroundColorAlpha as int) > 0); + } + + if (style.fontFamily != null && style.fontFamily != "") + { + assertTrue(style.fontFamily.length > 0); + } + + if (style.fontStyle != null && style.fontStyle != "") + { + assertTrue(style.fontStyle == "normal" || style.fontStyle == "italic"); + } + + if (style.fontWeight != null && style.fontWeight != "") + { + assertTrue(style.fontWeight == "normal" || style.fontWeight == "bold"); + } + + if (style.textAlign != null && style.textAlign != "") + { + assertTrue(style.textAlign == "left" || style.textAlign == "center" || style.textAlign == "right"); + } + + } + } + } + + public function testParserWithBadFile():void + { + var parser:DFXPParser = new DFXPParser(); + + try + { + var document:CaptioningDocument = parser.parse(CaptioningTestConstants.INVALID_XML_CAPTIONING_DOCUMENT_CONTENTS); + fail(); + } + catch (error:Error) + { + + } + } + + public function testParserWithNoBodyTag():void + { + var parser:DFXPParser = new DFXPParser(); + var document:CaptioningDocument = parser.parse(CaptioningTestConstants.CAPTIONING_DOCUMENT_CONTENTS_NO_BODY.toXMLString()); + + assertTrue(document.numCaptions == 0); + } + + public function testParserWithNoDivTag():void + { + var parser:DFXPParser = new DFXPParser(); + var document:CaptioningDocument = parser.parse(CaptioningTestConstants.CAPTIONING_DOCUMENT_CONTENTS_NO_DIV.toXMLString()); + + assertTrue(document.numCaptions > 0); + + } + + + } +} diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as index 5435969..7f2c694 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as @@ -1,415 +1,415 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.traits -{ - import flash.errors.IllegalOperationError; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.TimerEvent; - import flash.utils.Timer; - - import flexunit.framework.TestCase; - - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.utils.SimpleResource; - - public class TestLoaderBase extends TestCase - { - override public function setUp():void - { - super.setUp(); - - _loader = createLoader(); - - eventDispatcher = new EventDispatcher(); - eventCount = 0; - mediaErrors = []; - doTwice = false; - } - - override public function tearDown():void - { - super.tearDown(); - - _loader = null; - eventDispatcher = null; - } - - protected function createInterfaceObject(... args):Object - { - return new LoaderBase(); - } - - //--------------------------------------------------------------------- - - public function testCanHandleResource():void - { - assertTrue(loader.canHandleResource(successfulResource) == true); - assertTrue(loader.canHandleResource(failedResource) == true); - assertTrue(loader.canHandleResource(unhandledResource) == false); - } - - public function testLoad():void - { - doTestLoad(); - } - - public function testLoadTwice():void - { - doTwice = true; - doTestLoad(); - } - - private function doTestLoad():void - { - eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestLoad(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - if (doTwice) - { - reload = true; - } - else - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Calling load a second time should throw an exception. - try - { - event.loader.load(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - public function testLoadWithFailure():void - { - doTestLoadWithFailure(); - } - - public function testLoadWithFailureThenReload():void - { - doTwice = true; - doTestLoadWithFailure(); - } - - private function doTestLoadWithFailure():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); - var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); - loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - loader.load(loadTrait); - } - - private function onTestLoadWithFailure(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - if (eventCount == 1 && doTwice) - { - reload = true; - } - else - { - markCompleteOnMediaError(1); - } - break; - case 2: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOAD_ERROR); - assertTrue(event.newState == LoadState.LOADING); - break; - case 3: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - markCompleteOnMediaError(2); - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Reloading should repeat the failure. - event.loader.load(event.loadTrait); - } - } - - private function markCompleteOnMediaError(numExpected:int):void - { - if (numExpected == mediaErrors.length) - { - // Just verify one of them. - verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - else - { - // Wait a bit, then check again. - var timer:Timer = new Timer(400); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(event:TimerEvent):void - { - timer.stop(); - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - markCompleteOnMediaError(numExpected); - } - } - } - - public function testLoadWithInvalidResource():void - { - try - { - loader.load(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - public function testUnload():void - { - doTestUnload(); - } - - public function testUnloadTwice():void - { - doTwice = true; - doTestUnload(); - } - - private function doTestUnload():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestUnload(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var doUnload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - // Now unload. - doUnload = true; - - break; - case 2: - assertTrue(event.oldState == LoadState.READY); - assertTrue(event.newState == LoadState.UNLOADING); - break; - case 3: - assertTrue(event.oldState == LoadState.UNLOADING); - assertTrue(event.newState == LoadState.UNINITIALIZED); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - break; - - default: - fail(); - } - - eventCount++; - - if (doUnload) - { - event.loader.unload(event.loadTrait); - - if (doTwice) - { - // Unloading a second time should throw an exception - // (but the first unload will complete). - try - { - event.loader.unload(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - } - } - - public function testUnloadWithInvalidResource():void - { - try - { - loader.unload(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - //--------------------------------------------------------------------- - - protected final function createLoader():LoaderBase - { - return createInterfaceObject() as LoaderBase; - } - - protected function setOverriddenLoader(value:LoaderBase):void - { - _loader = value; - } - - protected final function get loader():LoaderBase - { - return _loader; - } - - protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - return new LoadTrait(loader, resource); - } - - - protected function get successfulResource():MediaResourceBase - { - throw new Error("Subclass must override get successfulResource!"); - } - - protected function get failedResource():MediaResourceBase - { - throw new Error("Subclass must override get failedResource!"); - } - - protected function get unhandledResource():MediaResourceBase - { - throw new Error("Subclass must override get unhandledResource!"); - } - - protected function verifyMediaErrorOnLoadFailure(error:MediaError):void - { - // Subclasses can override to check the error's properties. - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - private function mustNotReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is NOT received. - fail(); - } - - private function onMediaError(event:MediaErrorEvent):void - { - mediaErrors.push(event.error); - } - - private static const TEST_TIME:int = 8000; - - private var eventDispatcher:EventDispatcher; - private var eventCount:int = 0; - private var mediaErrors:Array; - private var _loader:LoaderBase; - private var doTwice:Boolean; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.traits +{ + import flash.errors.IllegalOperationError; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.TimerEvent; + import flash.utils.Timer; + + import flexunit.framework.TestCase; + + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.MediaResourceBase; + import org.osmf.utils.SimpleResource; + + public class TestLoaderBase extends TestCase + { + override public function setUp():void + { + super.setUp(); + + _loader = createLoader(); + + eventDispatcher = new EventDispatcher(); + eventCount = 0; + mediaErrors = []; + doTwice = false; + } + + override public function tearDown():void + { + super.tearDown(); + + _loader = null; + eventDispatcher = null; + } + + protected function createInterfaceObject(... args):Object + { + return new LoaderBase(); + } + + //--------------------------------------------------------------------- + + public function testCanHandleResource():void + { + assertTrue(loader.canHandleResource(successfulResource) == true); + assertTrue(loader.canHandleResource(failedResource) == true); + assertTrue(loader.canHandleResource(unhandledResource) == false); + } + + public function testLoad():void + { + doTestLoad(); + } + + public function testLoadTwice():void + { + doTwice = true; + doTestLoad(); + } + + private function doTestLoad():void + { + eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); + loader.load(createLoadTrait(loader, successfulResource)); + } + + private function onTestLoad(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var reload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.READY); + + if (doTwice) + { + reload = true; + } + else + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + break; + default: + fail(); + } + + eventCount++; + + if (reload) + { + // Calling load a second time should throw an exception. + try + { + event.loader.load(event.loadTrait); + + fail(); + } + catch (error:IllegalOperationError) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + public function testLoadWithFailure():void + { + doTestLoadWithFailure(); + } + + public function testLoadWithFailureThenReload():void + { + doTwice = true; + doTestLoadWithFailure(); + } + + private function doTestLoadWithFailure():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); + var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); + loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + loader.load(loadTrait); + } + + private function onTestLoadWithFailure(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var reload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.LOAD_ERROR); + + if (eventCount == 1 && doTwice) + { + reload = true; + } + else + { + markCompleteOnMediaError(1); + } + break; + case 2: + assertTrue(doTwice); + + assertTrue(event.oldState == LoadState.LOAD_ERROR); + assertTrue(event.newState == LoadState.LOADING); + break; + case 3: + assertTrue(doTwice); + + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.LOAD_ERROR); + + markCompleteOnMediaError(2); + break; + default: + fail(); + } + + eventCount++; + + if (reload) + { + // Reloading should repeat the failure. + event.loader.load(event.loadTrait); + } + } + + private function markCompleteOnMediaError(numExpected:int):void + { + if (numExpected == mediaErrors.length) + { + // Just verify one of them. + verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + else + { + // Wait a bit, then check again. + var timer:Timer = new Timer(400); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + + function onTimer(event:TimerEvent):void + { + timer.stop(); + timer.removeEventListener(TimerEvent.TIMER, onTimer); + + markCompleteOnMediaError(numExpected); + } + } + } + + public function testLoadWithInvalidResource():void + { + try + { + loader.load(createLoadTrait(loader, unhandledResource)); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + + public function testUnload():void + { + doTestUnload(); + } + + public function testUnloadTwice():void + { + doTwice = true; + doTestUnload(); + } + + private function doTestUnload():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); + loader.load(createLoadTrait(loader, successfulResource)); + } + + private function onTestUnload(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var doUnload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.READY); + + // Now unload. + doUnload = true; + + break; + case 2: + assertTrue(event.oldState == LoadState.READY); + assertTrue(event.newState == LoadState.UNLOADING); + break; + case 3: + assertTrue(event.oldState == LoadState.UNLOADING); + assertTrue(event.newState == LoadState.UNINITIALIZED); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + break; + + default: + fail(); + } + + eventCount++; + + if (doUnload) + { + event.loader.unload(event.loadTrait); + + if (doTwice) + { + // Unloading a second time should throw an exception + // (but the first unload will complete). + try + { + event.loader.unload(event.loadTrait); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + } + } + + public function testUnloadWithInvalidResource():void + { + try + { + loader.unload(createLoadTrait(loader, unhandledResource)); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + + //--------------------------------------------------------------------- + + protected final function createLoader():LoaderBase + { + return createInterfaceObject() as LoaderBase; + } + + protected function setOverriddenLoader(value:LoaderBase):void + { + _loader = value; + } + + protected final function get loader():LoaderBase + { + return _loader; + } + + protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait + { + return new LoadTrait(loader, resource); + } + + + protected function get successfulResource():MediaResourceBase + { + throw new Error("Subclass must override get successfulResource!"); + } + + protected function get failedResource():MediaResourceBase + { + throw new Error("Subclass must override get failedResource!"); + } + + protected function get unhandledResource():MediaResourceBase + { + throw new Error("Subclass must override get unhandledResource!"); + } + + protected function verifyMediaErrorOnLoadFailure(error:MediaError):void + { + // Subclasses can override to check the error's properties. + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + private function mustNotReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is NOT received. + fail(); + } + + private function onMediaError(event:MediaErrorEvent):void + { + mediaErrors.push(event.error); + } + + private static const TEST_TIME:int = 8000; + + private var eventDispatcher:EventDispatcher; + private var eventCount:int = 0; + private var mediaErrors:Array; + private var _loader:LoaderBase; + private var doTwice:Boolean; + } } \ No newline at end of file diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/DynamicMediaElement.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/DynamicMediaElement.as index 332aa27..b381eca 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/DynamicMediaElement.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/DynamicMediaElement.as @@ -1,119 +1,119 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.display.Sprite; - - import org.osmf.media.MediaElement; - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.AudioTrait; - import org.osmf.traits.BufferTrait; - import org.osmf.traits.DRMTrait; - import org.osmf.traits.DVRTrait; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.DynamicStreamTrait; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.traits.MediaTraitBase; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - - public class DynamicMediaElement extends MediaElement - { - public function DynamicMediaElement(traitTypes:Array=null, loader:LoaderBase=null, resource:MediaResourceBase=null, useDynamicTraits:Boolean=false) - { - this.resource = resource; - - var doCreateSeekTrait:Boolean = false; - - if (traitTypes != null) - { - for each (var traitType:String in traitTypes) - { - var trait:MediaTraitBase = null; - - switch (traitType) - { - case MediaTraitType.AUDIO: - trait = new AudioTrait(); - break; - case MediaTraitType.BUFFER: - trait = useDynamicTraits ? new DynamicBufferTrait() : new BufferTrait(); - break; - case MediaTraitType.LOAD: - trait = useDynamicTraits ? new DynamicLoadTrait(loader, resource) : new LoadTrait(loader, resource); - break; - case MediaTraitType.PLAY: - trait = useDynamicTraits ? new DynamicPlayTrait() : new PlayTrait(); - break; - case MediaTraitType.SEEK: - doCreateSeekTrait = true; - continue; - case MediaTraitType.DYNAMIC_STREAM: - trait = useDynamicTraits ? new DynamicDynamicStreamTrait() : new DynamicStreamTrait(true, 0, 5); - break; - case MediaTraitType.TIME: - trait = useDynamicTraits ? new DynamicTimeTrait() : new TimeTrait(); - timeTrait = trait as TimeTrait; - break; - case MediaTraitType.DISPLAY_OBJECT: - trait = useDynamicTraits ? new DynamicDisplayObjectTrait(new Sprite()) : new DisplayObjectTrait(new Sprite()); - break; - case MediaTraitType.DRM: - trait = useDynamicTraits ? new DynamicDRMTrait() : new DRMTrait(); - break; - case MediaTraitType.DVR: - trait = useDynamicTraits ? new DynamicDVRTrait() : new DVRTrait(); - break; - default: - break; - } - - if (trait != null) - { - doAddTrait(traitType, trait); - } - } - } - - if (doCreateSeekTrait) - { - var seekTrait:SeekTrait = useDynamicTraits ? new DynamicSeekTrait(DynamicTimeTrait(timeTrait)) : new SeekTrait(timeTrait); - doAddTrait(MediaTraitType.SEEK, seekTrait); - } - } - - public function doAddTrait(traitType:String, instance:MediaTraitBase):void - { - this.addTrait(traitType, instance); - } - - public function doRemoveTrait(traitType:String):MediaTraitBase - { - return this.removeTrait(traitType); - } - - private var timeTrait:TimeTrait; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.display.Sprite; + + import org.osmf.media.MediaElement; + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.AudioTrait; + import org.osmf.traits.BufferTrait; + import org.osmf.traits.DRMTrait; + import org.osmf.traits.DVRTrait; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.DynamicStreamTrait; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.traits.MediaTraitBase; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + + public class DynamicMediaElement extends MediaElement + { + public function DynamicMediaElement(traitTypes:Array=null, loader:LoaderBase=null, resource:MediaResourceBase=null, useDynamicTraits:Boolean=false) + { + this.resource = resource; + + var doCreateSeekTrait:Boolean = false; + + if (traitTypes != null) + { + for each (var traitType:String in traitTypes) + { + var trait:MediaTraitBase = null; + + switch (traitType) + { + case MediaTraitType.AUDIO: + trait = new AudioTrait(); + break; + case MediaTraitType.BUFFER: + trait = useDynamicTraits ? new DynamicBufferTrait() : new BufferTrait(); + break; + case MediaTraitType.LOAD: + trait = useDynamicTraits ? new DynamicLoadTrait(loader, resource) : new LoadTrait(loader, resource); + break; + case MediaTraitType.PLAY: + trait = useDynamicTraits ? new DynamicPlayTrait() : new PlayTrait(); + break; + case MediaTraitType.SEEK: + doCreateSeekTrait = true; + continue; + case MediaTraitType.DYNAMIC_STREAM: + trait = useDynamicTraits ? new DynamicDynamicStreamTrait() : new DynamicStreamTrait(true, 0, 5); + break; + case MediaTraitType.TIME: + trait = useDynamicTraits ? new DynamicTimeTrait() : new TimeTrait(); + timeTrait = trait as TimeTrait; + break; + case MediaTraitType.DISPLAY_OBJECT: + trait = useDynamicTraits ? new DynamicDisplayObjectTrait(new Sprite()) : new DisplayObjectTrait(new Sprite()); + break; + case MediaTraitType.DRM: + trait = useDynamicTraits ? new DynamicDRMTrait() : new DRMTrait(); + break; + case MediaTraitType.DVR: + trait = useDynamicTraits ? new DynamicDVRTrait() : new DVRTrait(); + break; + default: + break; + } + + if (trait != null) + { + doAddTrait(traitType, trait); + } + } + } + + if (doCreateSeekTrait) + { + var seekTrait:SeekTrait = useDynamicTraits ? new DynamicSeekTrait(DynamicTimeTrait(timeTrait)) : new SeekTrait(timeTrait); + doAddTrait(MediaTraitType.SEEK, seekTrait); + } + } + + public function doAddTrait(traitType:String, instance:MediaTraitBase):void + { + this.addTrait(traitType, instance); + } + + public function doRemoveTrait(traitType:String):MediaTraitBase + { + return this.removeTrait(traitType); + } + + private var timeTrait:TimeTrait; + } } \ No newline at end of file diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/MockHTTPLoader.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/MockHTTPLoader.as index 62bfd4a..37d7fc2 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/MockHTTPLoader.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/MockHTTPLoader.as @@ -1,47 +1,47 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.net.URLLoader; - - public class MockHTTPLoader extends HTTPLoader - { - public function MockHTTPLoader() - { - super(); - - urlLoader = new MockURLLoader(); - } - - public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void - { - urlLoader.setExpectationForURL(url, expectSuccess, expectedData); - } - - override protected function createURLLoader():URLLoader - { - return urlLoader; - } - - private var urlLoader:MockURLLoader; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.net.URLLoader; + + public class MockHTTPLoader extends HTTPLoader + { + public function MockHTTPLoader() + { + super(); + + urlLoader = new MockURLLoader(); + } + + public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void + { + urlLoader.setExpectationForURL(url, expectSuccess, expectedData); + } + + override protected function createURLLoader():URLLoader + { + return urlLoader; + } + + private var urlLoader:MockURLLoader; + } } \ No newline at end of file diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/MockURLLoader.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/MockURLLoader.as index c2d49a1..490bb25 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/MockURLLoader.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/MockURLLoader.as @@ -1,70 +1,70 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.events.Event; - import flash.events.IOErrorEvent; - import flash.net.URLLoader; - import flash.net.URLRequest; - import flash.utils.Dictionary; - - public class MockURLLoader extends URLLoader - { - public function MockURLLoader() - { - super(); - - expectations = new Dictionary(); - } - - public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void - { - expectations[url] = {"success":expectSuccess, "data":expectedData}; - } - - override public function load(request:URLRequest):void - { - var expectation:Object = expectations[request.url]; - if (expectation != null) - { - data = expectation["data"]; - - // Prevent the network request from happening. - if (expectation["success"] == true) - { - dispatchEvent(new Event(Event.COMPLETE)); - } - else - { - data = null; - dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR)); - } - } - else - { - throw new Error("Expectation needs to be set on MockURLLoader!"); - } - } - - private var expectations:Dictionary; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + import flash.utils.Dictionary; + + public class MockURLLoader extends URLLoader + { + public function MockURLLoader() + { + super(); + + expectations = new Dictionary(); + } + + public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void + { + expectations[url] = {"success":expectSuccess, "data":expectedData}; + } + + override public function load(request:URLRequest):void + { + var expectation:Object = expectations[request.url]; + if (expectation != null) + { + data = expectation["data"]; + + // Prevent the network request from happening. + if (expectation["success"] == true) + { + dispatchEvent(new Event(Event.COMPLETE)); + } + else + { + data = null; + dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR)); + } + } + else + { + throw new Error("Expectation needs to be set on MockURLLoader!"); + } + } + + private var expectations:Dictionary; + } } \ No newline at end of file diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/NullResource.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/NullResource.as index b8b27cc..775b8e1 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/NullResource.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/NullResource.as @@ -1,29 +1,29 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.media.MediaResourceBase; - - public class NullResource extends MediaResourceBase - { - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.media.MediaResourceBase; + + public class NullResource extends MediaResourceBase + { + } } \ No newline at end of file diff --git a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as index 2e0ea2f..038567c 100644 --- a/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as +++ b/lib/osmf/samples/CaptioningPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as @@ -1,44 +1,44 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.media.MediaResourceBase; - - public class SimpleResource extends MediaResourceBase - { - public static const SUCCESSFUL:String = "successful"; - public static const FAILED:String = "failed"; - public static const UNHANDLED:String = "unhandled"; - - public function SimpleResource(type:String) - { - _type = type; - } - - public function get type():String - { - return _type; - } - - private var _type:String; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.media.MediaResourceBase; + + public class SimpleResource extends MediaResourceBase + { + public static const SUCCESSFUL:String = "successful"; + public static const FAILED:String = "failed"; + public static const UNHANDLED:String = "unhandled"; + + public function SimpleResource(type:String) + { + _type = type; + } + + public function get type():String + { + return _type; + } + + private var _type:String; + } } \ No newline at end of file diff --git a/lib/osmf/samples/CaptioningPluginTest/.actionScriptProperties b/lib/osmf/samples/CaptioningPluginTest/.actionScriptProperties index fe1146d..2117d22 100644 --- a/lib/osmf/samples/CaptioningPluginTest/.actionScriptProperties +++ b/lib/osmf/samples/CaptioningPluginTest/.actionScriptProperties @@ -1,43 +1,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/CaptioningPluginTest/.flexProperties b/lib/osmf/samples/CaptioningPluginTest/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/CaptioningPluginTest/.flexProperties +++ b/lib/osmf/samples/CaptioningPluginTest/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/CaptioningPluginTest/src/CaptioningPluginTest.css b/lib/osmf/samples/CaptioningPluginTest/src/CaptioningPluginTest.css index 9a38389..a2a5aaa 100644 --- a/lib/osmf/samples/CaptioningPluginTest/src/CaptioningPluginTest.css +++ b/lib/osmf/samples/CaptioningPluginTest/src/CaptioningPluginTest.css @@ -1,98 +1,98 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ - -@namespace mx "library://ns.adobe.com/flex/mx"; - -global { - color: #ffffff; - fontFamily: "Verdana"; - fontSize: 11px; - fontWeight: normal; - disabledColor: #3d3d3d; -} - -.title { - fontSize: 20px; -} - -.timeCode { - fontSize: 10px; - color: #999999; -} - -.error { - fontSize: 10px; - color: #FF1111; -} - -mx|Label { - fontSize: 10px; - color: #aaaaaa; -} - -mx|Button { - themeColor: "haloSilver"; -} - -mx|ComboBox { - color: #333333; - themeColor: "haloSilver"; -} - -mx|TextArea { - color: #000000; - disabledColor: #000000; - backgroundColor: #ffffff; - backgroundDisabledColor: #ffffff; - borderColor: #ffffff; -} - -mx|TextInput { - color: #000000; -} - -mx|HSlider { - themeColor: "haloSilver"; - dataTipStyleName: "dataTip"; - dataTipOffset: 6; -} - -mx|ToolTip { - color: #ffffff; - backgroundColor: #333333; -} - -.dataTip { - backgroundColor: black; -} - -.captionStyle { - paddingLeft: 5; - paddingRight: 5; - paddingTop: 5; - alpha: 0; - color: #ffffff; - background-color: #000000; - background-alpha: 0.33; - textAlign: "center"; - fontSize: 11px; -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ + +@namespace mx "library://ns.adobe.com/flex/mx"; + +global { + color: #ffffff; + fontFamily: "Verdana"; + fontSize: 11px; + fontWeight: normal; + disabledColor: #3d3d3d; +} + +.title { + fontSize: 20px; +} + +.timeCode { + fontSize: 10px; + color: #999999; +} + +.error { + fontSize: 10px; + color: #FF1111; +} + +mx|Label { + fontSize: 10px; + color: #aaaaaa; +} + +mx|Button { + themeColor: "haloSilver"; +} + +mx|ComboBox { + color: #333333; + themeColor: "haloSilver"; +} + +mx|TextArea { + color: #000000; + disabledColor: #000000; + backgroundColor: #ffffff; + backgroundDisabledColor: #ffffff; + borderColor: #ffffff; +} + +mx|TextInput { + color: #000000; +} + +mx|HSlider { + themeColor: "haloSilver"; + dataTipStyleName: "dataTip"; + dataTipOffset: 6; +} + +mx|ToolTip { + color: #ffffff; + backgroundColor: #333333; +} + +.dataTip { + backgroundColor: black; +} + +.captionStyle { + paddingLeft: 5; + paddingRight: 5; + paddingTop: 5; + alpha: 0; + color: #ffffff; + background-color: #000000; + background-alpha: 0.33; + textAlign: "center"; + fontSize: 11px; +} diff --git a/lib/osmf/samples/CaptioningPluginTest/src/CaptioningPluginTest.mxml b/lib/osmf/samples/CaptioningPluginTest/src/CaptioningPluginTest.mxml index abedaf7..c617ab2 100644 --- a/lib/osmf/samples/CaptioningPluginTest/src/CaptioningPluginTest.mxml +++ b/lib/osmf/samples/CaptioningPluginTest/src/CaptioningPluginTest.mxml @@ -1,583 +1,583 @@ - - - - - - MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) - { - if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) - { - mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; - mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); - } - else - { - mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); - mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; - } - } - else if (width > 0 && height > 0) - { - mediaContainerUIComponent.width = width; - mediaContainerUIComponent.height = height; - } - } - - private function onDurationChange(event:TimeEvent):void - { - seekBar.maximum = event.time; - lblDuration.text = timeCode(event.time); - } - - private function onCurrentTimeChange(event:TimeEvent):void - { - if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) - { - seekBar.value = event.time; - lblPlayhead.text = timeCode(event.time); - } - } - - private function onSeekingChange(event:SeekEvent):void - { - if (event.seeking) - { - clearCaptionText(); - } - else - { - waitForSeek = false; - } - } - - private function toggleDragging(state:Boolean):void - { - sliderDragging = state; - if (!state) - { - waitForSeek = true; - if (mediaPlayer.canSeek) - { - mediaPlayer.seek(seekBar.value); - } - } - } - - private function onTraitAdd(event:MediaElementEvent):void - { - switch (event.traitType) - { - case MediaTraitType.SEEK: - seekBar.enabled = seekBar.visible = true; - break; - } - } - - private function onMetadataAdd(event:MediaElementEvent):void - { - var metadata:TimelineMetadata = event.metadata as TimelineMetadata; - - if (metadata) - { - debug(">>> Timeline metadata added, namespace="+event.namespaceURL); - namespaces[metadata] = event.namespaceURL; - timelineMetadata = metadata; - timelineMetadata.addEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); - timelineMetadata.addEventListener(TimelineMetadataEvent.MARKER_DURATION_REACHED, onHideCaption); - } - } - - private function onMetadataRemove(event:MediaElementEvent):void - { - var metadata:TimelineMetadata = event.metadata as TimelineMetadata; - - if (metadata && timelineMetadata) - { - debug(">>> Timeline metadata removed, namespace="+event.namespaceURL); - delete namespaces[metadata]; - timelineMetadata.removeEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); - timelineMetadata.removeEventListener(TimelineMetadataEvent.MARKER_DURATION_REACHED, onHideCaption); - timelineMetadata = null; - } - } - - private function onShowCaption(event:TimelineMetadataEvent):void - { - var caption:Caption = event.marker as Caption; - var ns:String = namespaces[event.currentTarget]; - - // Make sure this is a caption object, and just for good measure, we'll - // also check the namespace - if (captioningEnabled && (caption != null) && (ns == CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE)) - { - this.currentCaption = caption; - this.captionLabel.htmlText = caption.text; - this.captionLabel.validateNow(); - formatCaption(caption); - } - } - - /** - * Handles formatting within the caption string. - */ - private function formatCaption(caption:Caption):void - { - debug(">>> in formatCaption() - caption.numCaptionFormats="+caption.numCaptionFormats); - - for (var i:uint = 0; i < caption.numCaptionFormats; i++) - { - var captionFormat:CaptionFormat = caption.getCaptionFormatAt(i); - var txtFormat:TextFormat = new TextFormat(); - var style:CaptionStyle = captionFormat.style; - - if (style.textColor != null) - { - txtFormat.color = style.textColor; - } - - if (style.fontFamily != "") - { - txtFormat.font = style.fontFamily; - } - - if (style.fontSize > 0) - { - txtFormat.size = style.fontSize; - } - else - { - txtFormat.size = DEFAULT_CAPTION_FONT_SIZE; - } - - if (style.fontStyle != "") - { - txtFormat.italic = (style.fontStyle == "italic") ? true : false; - } - - if (style.fontWeight != "") - { - txtFormat.bold = (style.fontWeight == "bold") ? true : false; - } - - if (style.textAlign != "") - { - txtFormat.align = style.textAlign; - } - - if (style.backgroundColor != null) - { - captionBackgroundColor = uint(style.backgroundColor); - } - - if (captionLabel.wordWrap != style.wrapOption) - { - captionLabel.wordWrap = style.wrapOption; - } - - debug(">>> style.textColor="+style.textColor); - debug(">>> style.backgroundColor="+style.backgroundColor); - debug(">>> style.fontStyle="+style.fontStyle); - debug(">>> txtFormat.italic="+txtFormat.italic); - debug(">>> captionLabel.text.length="+captionLabel.text.length+" captionFormat.startIndex="+captionFormat.startIndex+", captionFormat.endIndex="+captionFormat.endIndex); - - - callLater(updateCaptionLabel, [txtFormat, captionFormat.startIndex, captionFormat.endIndex]); - - function updateCaptionLabel(txtFormat:TextFormat, start:int, end:int):void - { - captionLabel.mx_internal::getTextField().setTextFormat(txtFormat, start, end); - } - } - } - - private function onHideCaption(event:TimelineMetadataEvent):void - { - var caption:Caption = event.marker as Caption; - - if (this.currentCaption.time == caption.time) - { - clearCaptionText(); - } - } - - private function clearCaptionText():void - { - trace(">>> CLEARING CAPTION TEXT!"); - captionLabel.htmlText = ""; - captionBackgroundColor = CaptioningPluginTest.DEFAULT_CAPTION_BG_COLOR; - } - - private function onClickPlayBtn(event:Event):void - { - if (mediaPlayer.playing && mediaPlayer.canPause) - { - playBtn.label = "Play"; - mediaPlayer.pause(); - } - else if (mediaPlayer.paused && mediaPlayer.canPlay) - { - playBtn.label = "Pause"; - mediaPlayer.play(); - } - } - - private function loadMedia(url:String, timedTextFile:String):void - { - var resource:URLResource = new URLResource(url); - var dfxpFile:String = timedTextFile; - - // Assign to the resource the metadata that indicates that it should have a Timed Text - // document applied (and include the URL of that document). - var metadata:Metadata = new Metadata(); - - metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, dfxpFile); - resource.addMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE, metadata); - - var netLoader:NetLoader = new NetLoader(); - - mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, createVideoElement)); - var mediaElement:MediaElement = mediaFactory.createMediaElement(resource); - - // Listen for traits to be added, so we can adjust the UI. For example, enable the seek bar - // when the SeekTrait is added - mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - - // Listen for metadata to be added so we can add any desired event listeners on any - // metadata facets we care about. - mediaElement.addEventListener(MediaElementEvent.METADATA_ADD, onMetadataAdd); - - // Listen for metadata to be removed so we remove an event listeners - mediaElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onMetadataRemove); - - mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true); - - setMediaElement(mediaElement); - enablePlayerControls(true); - - // Now load the DFXP file separately so we can show it in the UI (note this has - // nothing to do with the functionality of the app, this is only for the - // convenience of the user) - var fileRenderer:FileRenderer = new FileRenderer(this.dxfpFileContents, dfxpFile); - } - - private function setMediaElement(value:MediaElement):void - { - if (mediaPlayer.media != null) - { - mediaContainerUIComponent.container.removeMediaElement(mediaPlayer.media); - } - - if (value != null) - { - mediaContainerUIComponent.container.addMediaElement(value); - } - - mediaPlayer.media = value; - } - - private function unloadMedia():void - { - setMediaElement(null); - enablePlayerControls(false); - clearCaptionText(); - } - - private function enablePlayerControls(enable:Boolean=true):void - { - playBtn.enabled = seekBar.enabled = enable; - } - - private function showScrubTime(val:String):String - { - return timeCode(Number(val)); - } - - private function timeCode(sec:Number):String - { - var h:Number = Math.floor(sec/3600); - h = isNaN(h) ? 0 : h; - - var m:Number = Math.floor((sec%3600)/60); - m = isNaN(m) ? 0 : m; - - var s:Number = Math.floor((sec%3600)%60); - s = isNaN(s) ? 0 : s; - - return (h == 0 ? "":(h<10 ? "0"+h.toString()+":" : h.toString()+":"))+(m<10 ? "0"+m.toString() : m.toString())+":"+(s<10 ? "0"+s.toString() : s.toString()); - } - - private function debug(msg:String):void - { - if (DEBUG) - { - trace(msg); - } - } - - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) + { + if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) + { + mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; + mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); + } + else + { + mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); + mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; + } + } + else if (width > 0 && height > 0) + { + mediaContainerUIComponent.width = width; + mediaContainerUIComponent.height = height; + } + } + + private function onDurationChange(event:TimeEvent):void + { + seekBar.maximum = event.time; + lblDuration.text = timeCode(event.time); + } + + private function onCurrentTimeChange(event:TimeEvent):void + { + if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) + { + seekBar.value = event.time; + lblPlayhead.text = timeCode(event.time); + } + } + + private function onSeekingChange(event:SeekEvent):void + { + if (event.seeking) + { + clearCaptionText(); + } + else + { + waitForSeek = false; + } + } + + private function toggleDragging(state:Boolean):void + { + sliderDragging = state; + if (!state) + { + waitForSeek = true; + if (mediaPlayer.canSeek) + { + mediaPlayer.seek(seekBar.value); + } + } + } + + private function onTraitAdd(event:MediaElementEvent):void + { + switch (event.traitType) + { + case MediaTraitType.SEEK: + seekBar.enabled = seekBar.visible = true; + break; + } + } + + private function onMetadataAdd(event:MediaElementEvent):void + { + var metadata:TimelineMetadata = event.metadata as TimelineMetadata; + + if (metadata) + { + debug(">>> Timeline metadata added, namespace="+event.namespaceURL); + namespaces[metadata] = event.namespaceURL; + timelineMetadata = metadata; + timelineMetadata.addEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); + timelineMetadata.addEventListener(TimelineMetadataEvent.MARKER_DURATION_REACHED, onHideCaption); + } + } + + private function onMetadataRemove(event:MediaElementEvent):void + { + var metadata:TimelineMetadata = event.metadata as TimelineMetadata; + + if (metadata && timelineMetadata) + { + debug(">>> Timeline metadata removed, namespace="+event.namespaceURL); + delete namespaces[metadata]; + timelineMetadata.removeEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); + timelineMetadata.removeEventListener(TimelineMetadataEvent.MARKER_DURATION_REACHED, onHideCaption); + timelineMetadata = null; + } + } + + private function onShowCaption(event:TimelineMetadataEvent):void + { + var caption:Caption = event.marker as Caption; + var ns:String = namespaces[event.currentTarget]; + + // Make sure this is a caption object, and just for good measure, we'll + // also check the namespace + if (captioningEnabled && (caption != null) && (ns == CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE)) + { + this.currentCaption = caption; + this.captionLabel.htmlText = caption.text; + this.captionLabel.validateNow(); + formatCaption(caption); + } + } + + /** + * Handles formatting within the caption string. + */ + private function formatCaption(caption:Caption):void + { + debug(">>> in formatCaption() - caption.numCaptionFormats="+caption.numCaptionFormats); + + for (var i:uint = 0; i < caption.numCaptionFormats; i++) + { + var captionFormat:CaptionFormat = caption.getCaptionFormatAt(i); + var txtFormat:TextFormat = new TextFormat(); + var style:CaptionStyle = captionFormat.style; + + if (style.textColor != null) + { + txtFormat.color = style.textColor; + } + + if (style.fontFamily != "") + { + txtFormat.font = style.fontFamily; + } + + if (style.fontSize > 0) + { + txtFormat.size = style.fontSize; + } + else + { + txtFormat.size = DEFAULT_CAPTION_FONT_SIZE; + } + + if (style.fontStyle != "") + { + txtFormat.italic = (style.fontStyle == "italic") ? true : false; + } + + if (style.fontWeight != "") + { + txtFormat.bold = (style.fontWeight == "bold") ? true : false; + } + + if (style.textAlign != "") + { + txtFormat.align = style.textAlign; + } + + if (style.backgroundColor != null) + { + captionBackgroundColor = uint(style.backgroundColor); + } + + if (captionLabel.wordWrap != style.wrapOption) + { + captionLabel.wordWrap = style.wrapOption; + } + + debug(">>> style.textColor="+style.textColor); + debug(">>> style.backgroundColor="+style.backgroundColor); + debug(">>> style.fontStyle="+style.fontStyle); + debug(">>> txtFormat.italic="+txtFormat.italic); + debug(">>> captionLabel.text.length="+captionLabel.text.length+" captionFormat.startIndex="+captionFormat.startIndex+", captionFormat.endIndex="+captionFormat.endIndex); + + + callLater(updateCaptionLabel, [txtFormat, captionFormat.startIndex, captionFormat.endIndex]); + + function updateCaptionLabel(txtFormat:TextFormat, start:int, end:int):void + { + captionLabel.mx_internal::getTextField().setTextFormat(txtFormat, start, end); + } + } + } + + private function onHideCaption(event:TimelineMetadataEvent):void + { + var caption:Caption = event.marker as Caption; + + if (this.currentCaption.time == caption.time) + { + clearCaptionText(); + } + } + + private function clearCaptionText():void + { + trace(">>> CLEARING CAPTION TEXT!"); + captionLabel.htmlText = ""; + captionBackgroundColor = CaptioningPluginTest.DEFAULT_CAPTION_BG_COLOR; + } + + private function onClickPlayBtn(event:Event):void + { + if (mediaPlayer.playing && mediaPlayer.canPause) + { + playBtn.label = "Play"; + mediaPlayer.pause(); + } + else if (mediaPlayer.paused && mediaPlayer.canPlay) + { + playBtn.label = "Pause"; + mediaPlayer.play(); + } + } + + private function loadMedia(url:String, timedTextFile:String):void + { + var resource:URLResource = new URLResource(url); + var dfxpFile:String = timedTextFile; + + // Assign to the resource the metadata that indicates that it should have a Timed Text + // document applied (and include the URL of that document). + var metadata:Metadata = new Metadata(); + + metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, dfxpFile); + resource.addMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE, metadata); + + var netLoader:NetLoader = new NetLoader(); + + mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, createVideoElement)); + var mediaElement:MediaElement = mediaFactory.createMediaElement(resource); + + // Listen for traits to be added, so we can adjust the UI. For example, enable the seek bar + // when the SeekTrait is added + mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + + // Listen for metadata to be added so we can add any desired event listeners on any + // metadata facets we care about. + mediaElement.addEventListener(MediaElementEvent.METADATA_ADD, onMetadataAdd); + + // Listen for metadata to be removed so we remove an event listeners + mediaElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onMetadataRemove); + + mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true); + + setMediaElement(mediaElement); + enablePlayerControls(true); + + // Now load the DFXP file separately so we can show it in the UI (note this has + // nothing to do with the functionality of the app, this is only for the + // convenience of the user) + var fileRenderer:FileRenderer = new FileRenderer(this.dxfpFileContents, dfxpFile); + } + + private function setMediaElement(value:MediaElement):void + { + if (mediaPlayer.media != null) + { + mediaContainerUIComponent.container.removeMediaElement(mediaPlayer.media); + } + + if (value != null) + { + mediaContainerUIComponent.container.addMediaElement(value); + } + + mediaPlayer.media = value; + } + + private function unloadMedia():void + { + setMediaElement(null); + enablePlayerControls(false); + clearCaptionText(); + } + + private function enablePlayerControls(enable:Boolean=true):void + { + playBtn.enabled = seekBar.enabled = enable; + } + + private function showScrubTime(val:String):String + { + return timeCode(Number(val)); + } + + private function timeCode(sec:Number):String + { + var h:Number = Math.floor(sec/3600); + h = isNaN(h) ? 0 : h; + + var m:Number = Math.floor((sec%3600)/60); + m = isNaN(m) ? 0 : m; + + var s:Number = Math.floor((sec%3600)%60); + s = isNaN(s) ? 0 : s; + + return (h == 0 ? "":(h<10 ? "0"+h.toString()+":" : h.toString()+":"))+(m<10 ? "0"+m.toString() : m.toString())+":"+(s<10 ? "0"+s.toString() : s.toString()); + } + + private function debug(msg:String):void + { + if (DEBUG) + { + trace(msg); + } + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/CaptioningPluginTest/src/org/osmf/captioningPluginTest/utils/FileRenderer.as b/lib/osmf/samples/CaptioningPluginTest/src/org/osmf/captioningPluginTest/utils/FileRenderer.as index 1014dbc..d608220 100644 --- a/lib/osmf/samples/CaptioningPluginTest/src/org/osmf/captioningPluginTest/utils/FileRenderer.as +++ b/lib/osmf/samples/CaptioningPluginTest/src/org/osmf/captioningPluginTest/utils/FileRenderer.as @@ -1,98 +1,98 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.captioningPluginTest.utils -{ - import flash.events.Event; - import flash.events.HTTPStatusEvent; - import flash.events.IOErrorEvent; - import flash.events.ProgressEvent; - import flash.events.SecurityErrorEvent; - import flash.net.URLLoader; - import flash.net.URLRequest; - - import mx.controls.TextArea; - - public class FileRenderer - { - public function FileRenderer(target:TextArea, url:String) - { - _target = target; - _loader = new URLLoader(); - setupListeners(); - - _loader.load(new URLRequest(url)); - } - - private function setupListeners(setup:Boolean=true):void - { - if (setup) - { - _loader.addEventListener(Event.COMPLETE, completeHandler); - _loader.addEventListener(Event.OPEN, openHandler); - _loader.addEventListener(ProgressEvent.PROGRESS, progressHandler); - _loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); - _loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); - _loader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); - } - else - { - _loader.removeEventListener(Event.COMPLETE, completeHandler); - _loader.removeEventListener(Event.OPEN, openHandler); - _loader.removeEventListener(ProgressEvent.PROGRESS, progressHandler); - _loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); - _loader.removeEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); - _loader.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); - } - } - - private function completeHandler(event:Event):void - { - setupListeners(false); - var loader:URLLoader = URLLoader(event.target); - //trace("completeHandler: " + loader.data); - _target.text = loader.data; - } - - private function openHandler(event:Event):void { - trace("openHandler: " + event); - } - - private function progressHandler(event:ProgressEvent):void { - trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal); - } - - private function securityErrorHandler(event:SecurityErrorEvent):void { - trace("securityErrorHandler: " + event); - } - - private function httpStatusHandler(event:HTTPStatusEvent):void { - trace("httpStatusHandler: " + event); - } - - private function ioErrorHandler(event:IOErrorEvent):void { - trace("ioErrorHandler: " + event); - } - - private var _target:TextArea; - private var _loader:URLLoader; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.captioningPluginTest.utils +{ + import flash.events.Event; + import flash.events.HTTPStatusEvent; + import flash.events.IOErrorEvent; + import flash.events.ProgressEvent; + import flash.events.SecurityErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + + import mx.controls.TextArea; + + public class FileRenderer + { + public function FileRenderer(target:TextArea, url:String) + { + _target = target; + _loader = new URLLoader(); + setupListeners(); + + _loader.load(new URLRequest(url)); + } + + private function setupListeners(setup:Boolean=true):void + { + if (setup) + { + _loader.addEventListener(Event.COMPLETE, completeHandler); + _loader.addEventListener(Event.OPEN, openHandler); + _loader.addEventListener(ProgressEvent.PROGRESS, progressHandler); + _loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); + _loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); + _loader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); + } + else + { + _loader.removeEventListener(Event.COMPLETE, completeHandler); + _loader.removeEventListener(Event.OPEN, openHandler); + _loader.removeEventListener(ProgressEvent.PROGRESS, progressHandler); + _loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); + _loader.removeEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); + _loader.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); + } + } + + private function completeHandler(event:Event):void + { + setupListeners(false); + var loader:URLLoader = URLLoader(event.target); + //trace("completeHandler: " + loader.data); + _target.text = loader.data; + } + + private function openHandler(event:Event):void { + trace("openHandler: " + event); + } + + private function progressHandler(event:ProgressEvent):void { + trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal); + } + + private function securityErrorHandler(event:SecurityErrorEvent):void { + trace("securityErrorHandler: " + event); + } + + private function httpStatusHandler(event:HTTPStatusEvent):void { + trace("httpStatusHandler: " + event); + } + + private function ioErrorHandler(event:IOErrorEvent):void { + trace("ioErrorHandler: " + event); + } + + private var _target:TextArea; + private var _loader:URLLoader; + } +} diff --git a/lib/osmf/samples/CaptioningSample/.actionScriptProperties b/lib/osmf/samples/CaptioningSample/.actionScriptProperties index 501b9a0..d6064f9 100644 --- a/lib/osmf/samples/CaptioningSample/.actionScriptProperties +++ b/lib/osmf/samples/CaptioningSample/.actionScriptProperties @@ -1,43 +1,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/CaptioningSample/.flexProperties b/lib/osmf/samples/CaptioningSample/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/CaptioningSample/.flexProperties +++ b/lib/osmf/samples/CaptioningSample/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/CaptioningSample/readme.txt b/lib/osmf/samples/CaptioningSample/readme.txt index 77235d1..a634a94 100644 --- a/lib/osmf/samples/CaptioningSample/readme.txt +++ b/lib/osmf/samples/CaptioningSample/readme.txt @@ -1,13 +1,13 @@ Sample Application: CaptioningSample A. Overview -This sample application demonstrates loading the OSMF captioning plugin and using an external captioning -document to show captions over a video. Specifically, the sample app loads the OSMF captioning plugin, -places the URL location of a WC3 Timed Text DFXP file on the metadata of the video resource, and listens -for the metadata TemporalFacet to be added to the VideoElement. - -When the TemporalFacet is added to the VideoElement, an event listener is added for events of type TemporalFacetEvent. -In that event handler, the caption data is included in the event and the sample app renders the caption using the style information +This sample application demonstrates loading the OSMF captioning plugin and using an external captioning +document to show captions over a video. Specifically, the sample app loads the OSMF captioning plugin, +places the URL location of a WC3 Timed Text DFXP file on the metadata of the video resource, and listens +for the metadata TemporalFacet to be added to the VideoElement. + +When the TemporalFacet is added to the VideoElement, an event listener is added for events of type TemporalFacetEvent. +In that event handler, the caption data is included in the event and the sample app renders the caption using the style information found in the caption object that was passed to the event listener. B. Installation Instructions (Flex Builder) @@ -20,10 +20,10 @@ B. Installation Instructions (Flex Builder) 6. Launch the application from the Run menu. C. Usage Instructions - -Run the app, you should see the captions appear. Seeking should always show the correct caption at the correct time. -* IMPORTANT NOTE: The sample app loads the captioning plugin statically. Due to Flash Player security, you will not be able to load -the plugin dynamically unless you run the sample app from a Web server or localhost, i.e., "http://localhost/CaptioningSample.html". -Both the plugin and the player loading the plugin must be run from a Web server or localhost. +Run the app, you should see the captions appear. Seeking should always show the correct caption at the correct time. + +* IMPORTANT NOTE: The sample app loads the captioning plugin statically. Due to Flash Player security, you will not be able to load +the plugin dynamically unless you run the sample app from a Web server or localhost, i.e., "http://localhost/CaptioningSample.html". +Both the plugin and the player loading the plugin must be run from a Web server or localhost. diff --git a/lib/osmf/samples/CaptioningSample/src/CaptioningSample.css b/lib/osmf/samples/CaptioningSample/src/CaptioningSample.css index 43e7f85..30feea4 100644 --- a/lib/osmf/samples/CaptioningSample/src/CaptioningSample.css +++ b/lib/osmf/samples/CaptioningSample/src/CaptioningSample.css @@ -1,88 +1,88 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ - -@namespace mx "library://ns.adobe.com/flex/mx"; - -global { - color: #ffffff; - fontFamily: "Verdana"; - fontSize: 11px; - fontWeight: normal; - disabledColor: #3d3d3d; -} - -.title { - fontSize: 20px; -} - -.timeCode { - fontSize: 10px; - color: #999999; -} - -.error { - fontSize: 10px; - color: #FF1111; -} - -mx|Label { - fontSize: 10px; - color: #aaaaaa; -} - -mx|Button { - themeColor: "haloSilver"; -} - -mx|TextArea { - color: #ffffff; - disabledColor: #ffffff; - backgroundColor: #000000; - backgroundDisabledColor: #000000; - borderColor: #000000; -} - -mx|HSlider { - themeColor: "haloSilver"; - dataTipStyleName: "dataTip"; - dataTipOffset: 6; -} - -mx|ToolTip { - color: #ffffff; - backgroundColor: #333333; -} - -.dataTip { - backgroundColor: black; -} - -.captionStyle { - paddingLeft: 5; - paddingRight: 5; - paddingTop: 5; - alpha: 0; - background-color: #000000; - background-alpha: 0.33; - textAlign: "center"; - fontSize: 14px; -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ + +@namespace mx "library://ns.adobe.com/flex/mx"; + +global { + color: #ffffff; + fontFamily: "Verdana"; + fontSize: 11px; + fontWeight: normal; + disabledColor: #3d3d3d; +} + +.title { + fontSize: 20px; +} + +.timeCode { + fontSize: 10px; + color: #999999; +} + +.error { + fontSize: 10px; + color: #FF1111; +} + +mx|Label { + fontSize: 10px; + color: #aaaaaa; +} + +mx|Button { + themeColor: "haloSilver"; +} + +mx|TextArea { + color: #ffffff; + disabledColor: #ffffff; + backgroundColor: #000000; + backgroundDisabledColor: #000000; + borderColor: #000000; +} + +mx|HSlider { + themeColor: "haloSilver"; + dataTipStyleName: "dataTip"; + dataTipOffset: 6; +} + +mx|ToolTip { + color: #ffffff; + backgroundColor: #333333; +} + +.dataTip { + backgroundColor: black; +} + +.captionStyle { + paddingLeft: 5; + paddingRight: 5; + paddingTop: 5; + alpha: 0; + background-color: #000000; + background-alpha: 0.33; + textAlign: "center"; + fontSize: 14px; +} diff --git a/lib/osmf/samples/CaptioningSample/src/CaptioningSample.mxml b/lib/osmf/samples/CaptioningSample/src/CaptioningSample.mxml index ee651fc..68e0c66 100644 --- a/lib/osmf/samples/CaptioningSample/src/CaptioningSample.mxml +++ b/lib/osmf/samples/CaptioningSample/src/CaptioningSample.mxml @@ -1,446 +1,446 @@ - - - - - - This sample application loads the OSMF captioning plugin,"+ - " places the URL location of a WC3 Timed Text DFXP file on"+ - " the metadata of the video resource, and listens for the"+ - " metadata TemporalFacet to be added to the VideoElement.

      "+ - "

      When the TemporalFacet is added to the VideoElement,"+ - " an event listener is added for events of type TemporalFacetEvent.

      "+ - "

      In that event handler, the caption data is included in the event"+ - " and the sample app renders the caption using the style information"+ - " found in the caption object that was passed to the event listener.

      "; - - private function init():void - { - mediaContainerUIComponent.container = new MediaContainer(); - mediaFactory = new MediaFactory(); - - loadPlugin("org.osmf.captioning.CaptioningPluginInfo"); - - mediaPlayer = new MediaPlayer(); - mediaPlayer.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange); - mediaPlayer.addEventListener(TimeEvent.DURATION_CHANGE, onDurationChange); - mediaPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, onCurrentTimeChange); - mediaPlayer.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); - - mediaPlayer.currentTimeUpdateInterval = DEFAULT_PROGRESS_DELAY; - - sliderDragging = false; - waitForSeek = false; - captioningEnabled = true; - - loadMedia(STREAM_URL); - } - - private function loadMedia(url:String):void - { - var resource:URLResource = new URLResource(url); - - // Assign to the resource the metadata that indicates that it should have a Timed Text - // document applied (and include the URL of that document). - var metadata:Metadata = new Metadata(); - - metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, CAPTION_URL); - resource.addMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE, metadata); - - var netLoader:NetLoader = new NetLoader(); - - mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, createVideoElement)); - var mediaElement:MediaElement = mediaFactory.createMediaElement(resource); - - // Listen for traits to be added, so we can adjust the UI. For example, enable the seek bar - // when the SeekTrait is added - mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - - // Listen for captions being added. - captionMetadata = mediaElement.getMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE) as TimelineMetadata; - if (captionMetadata == null) - { - captionMetadata = new TimelineMetadata(mediaElement); - mediaElement.addMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE, captionMetadata); - } - captionMetadata.addEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); - captionMetadata.addEventListener(TimelineMetadataEvent.MARKER_ADD, onHideCaption); - - mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true); - - setMediaElement(mediaElement); - enablePlayerControls(true); - } - - private function setMediaElement(value:MediaElement):void - { - if (mediaPlayer.media != null) - { - mediaContainerUIComponent.container.removeMediaElement(mediaPlayer.media); - } - - if (value != null) - { - mediaContainerUIComponent.container.addMediaElement(value); - } - - mediaPlayer.media = value; - } - - private function createVideoElement():MediaElement - { - return new VideoElement(); - } - - private function loadPlugin(source:String):void - { - var pluginResource:MediaResourceBase; - if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file") - { - // This is a URL, create a URLResource - pluginResource = new URLResource(source); - } - else - { - // Assume this is a class - var pluginInfoRef:Class = flash.utils.getDefinitionByName(source) as Class; - pluginResource = new PluginInfoResource(new pluginInfoRef); - } - - loadPluginFromResource(pluginResource); - } - - private function loadPluginFromResource(pluginResource:MediaResourceBase):void - { - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); - mediaFactory.loadPlugin(pluginResource); - } - - private function onPluginLoaded(event:MediaFactoryEvent):void - { - trace("Plugin LOADED!"); - } - - private function onPluginLoadFailed(event:MediaFactoryEvent):void - { - trace("Plugin LOAD FAILED!"); - } - - private function onMediaError(event:MediaErrorEvent):void - { - Alert.show("Media Load Error : "+event.error.errorID+" - "+event.error.message); - } - - private function onMediaSizeChange(event:DisplayObjectEvent):void - { - var width:int = event.newWidth; - var height:int = event.newHeight; - - // Scale to native or smaller - if (width > MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) - { - if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) - { - mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; - mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); - } - else - { - mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); - mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; - } - } - else if (width > 0 && height > 0) - { - mediaContainerUIComponent.width = event.newWidth; - mediaContainerUIComponent.height = event.newHeight; - } - } - - private function onDurationChange(event:TimeEvent):void - { - seekBar.maximum = event.time; - lblDuration.text = timeCode(event.time); - } - - private function onCurrentTimeChange(event:TimeEvent):void - { - if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) - { - seekBar.value = event.time; - lblPlayhead.text = timeCode(event.time); - } - } - - private function onSeekingChange(event:SeekEvent):void - { - if (event.seeking) - { - this.onHideCaption(null); - } - else - { - waitForSeek = false; - } - } - - private function toggleDragging(state:Boolean):void - { - sliderDragging = state; - if (!state) - { - waitForSeek = true; - if (mediaPlayer.canSeek) - { - mediaPlayer.seek(seekBar.value); - } - } - } - - private function onTraitAdd(event:MediaElementEvent):void - { - switch (event.traitType) - { - case MediaTraitType.SEEK: - seekBar.enabled = seekBar.visible = true; - break; - } - } - - private function onShowCaption(event:TimelineMetadataEvent):void - { - var caption:Caption = event.marker as Caption; - - // Make sure this is a caption object, and just for good measure, we'll - // also check the namespace - if (captioningEnabled && caption != null) - { - this.captionLabel.htmlText = caption.text; - this.captionLabel.validateNow(); - formatCaption(caption); - } - } - - /** - * Handles formatting within the caption string. - */ - private function formatCaption(caption:Caption):void - { - for (var i:uint = 0; i < caption.numCaptionFormats; i++) - { - var captionFormat:CaptionFormat = caption.getCaptionFormatAt(i); - var txtFormat:TextFormat = new TextFormat(); - var style:CaptionStyle = captionFormat.style; - - if (style.textColor != null) - { - txtFormat.color = style.textColor; - } - - if (style.fontFamily != "") - { - txtFormat.font = style.fontFamily; - } - - if (style.fontSize > 0) - { - txtFormat.size = style.fontSize; - } - - if (style.fontStyle != "") - { - txtFormat.italic = (style.fontStyle == "italic") ? true : false; - } - - if (style.fontWeight != "") - { - txtFormat.bold = (style.fontWeight == "bold") ? true : false; - } - - if (style.textAlign != "") - { - txtFormat.align = style.textAlign; - } - - - this.captionLabel.mx_internal::getTextField().setTextFormat(txtFormat, captionFormat.startIndex, - captionFormat.endIndex); - if (this.captionLabel.wordWrap != style.wrapOption) - { - this.captionLabel.wordWrap = style.wrapOption; - } - } - } - - private function onHideCaption(event:TimelineMetadataEvent):void - { - // Save the current caption text so we can easily re-display - // if user is toggling the captioning button - savedCaptionText = captionLabel.htmlText; - captionLabel.htmlText = ""; - } - - private function onClickPlayBtn(event:Event):void - { - if (mediaPlayer.playing && mediaPlayer.canPause) - { - playBtn.label = "Play"; - mediaPlayer.pause(); - } - else if (mediaPlayer.paused && mediaPlayer.canPlay) - { - playBtn.label = "Pause"; - mediaPlayer.play(); - } - } - - private function enablePlayerControls(enable:Boolean=true):void - { - playBtn.enabled = seekBar.enabled = enable; - } - - private function onClickCC(e:Event):void - { - captioningEnabled = !captioningEnabled; - captionLabel.visible = captioningEnabled; - - var color:String = captioningEnabled ? "#00cc00" : "#cc0000"; - ccBox.setStyle("borderColor", color); - - if (!captioningEnabled) - { - onHideCaption(null); - } - else if (savedCaptionText && savedCaptionText.length > 0) - { - captionLabel.htmlText = savedCaptionText; - } - } - - private function showScrubTime(val:String):String - { - return timeCode(Number(val)); - } - - private function timeCode(sec:Number):String - { - var h:Number = Math.floor(sec/3600); - h = isNaN(h) ? 0 : h; - - var m:Number = Math.floor((sec%3600)/60); - m = isNaN(m) ? 0 : m; - - var s:Number = Math.floor((sec%3600)%60); - s = isNaN(s) ? 0 : s; - - return (h == 0 ? "":(h<10 ? "0"+h.toString()+":" : h.toString()+":"))+(m<10 ? "0"+m.toString() : m.toString())+":"+(s<10 ? "0"+s.toString() : s.toString()); - } - - ]]> -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      + + + + + + This sample application loads the OSMF captioning plugin,"+ + " places the URL location of a WC3 Timed Text DFXP file on"+ + " the metadata of the video resource, and listens for the"+ + " metadata TemporalFacet to be added to the VideoElement.

      "+ + "

      When the TemporalFacet is added to the VideoElement,"+ + " an event listener is added for events of type TemporalFacetEvent.

      "+ + "

      In that event handler, the caption data is included in the event"+ + " and the sample app renders the caption using the style information"+ + " found in the caption object that was passed to the event listener.

      "; + + private function init():void + { + mediaContainerUIComponent.container = new MediaContainer(); + mediaFactory = new MediaFactory(); + + loadPlugin("org.osmf.captioning.CaptioningPluginInfo"); + + mediaPlayer = new MediaPlayer(); + mediaPlayer.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange); + mediaPlayer.addEventListener(TimeEvent.DURATION_CHANGE, onDurationChange); + mediaPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, onCurrentTimeChange); + mediaPlayer.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); + + mediaPlayer.currentTimeUpdateInterval = DEFAULT_PROGRESS_DELAY; + + sliderDragging = false; + waitForSeek = false; + captioningEnabled = true; + + loadMedia(STREAM_URL); + } + + private function loadMedia(url:String):void + { + var resource:URLResource = new URLResource(url); + + // Assign to the resource the metadata that indicates that it should have a Timed Text + // document applied (and include the URL of that document). + var metadata:Metadata = new Metadata(); + + metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, CAPTION_URL); + resource.addMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE, metadata); + + var netLoader:NetLoader = new NetLoader(); + + mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, createVideoElement)); + var mediaElement:MediaElement = mediaFactory.createMediaElement(resource); + + // Listen for traits to be added, so we can adjust the UI. For example, enable the seek bar + // when the SeekTrait is added + mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + + // Listen for captions being added. + captionMetadata = mediaElement.getMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE) as TimelineMetadata; + if (captionMetadata == null) + { + captionMetadata = new TimelineMetadata(mediaElement); + mediaElement.addMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE, captionMetadata); + } + captionMetadata.addEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); + captionMetadata.addEventListener(TimelineMetadataEvent.MARKER_ADD, onHideCaption); + + mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true); + + setMediaElement(mediaElement); + enablePlayerControls(true); + } + + private function setMediaElement(value:MediaElement):void + { + if (mediaPlayer.media != null) + { + mediaContainerUIComponent.container.removeMediaElement(mediaPlayer.media); + } + + if (value != null) + { + mediaContainerUIComponent.container.addMediaElement(value); + } + + mediaPlayer.media = value; + } + + private function createVideoElement():MediaElement + { + return new VideoElement(); + } + + private function loadPlugin(source:String):void + { + var pluginResource:MediaResourceBase; + if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file") + { + // This is a URL, create a URLResource + pluginResource = new URLResource(source); + } + else + { + // Assume this is a class + var pluginInfoRef:Class = flash.utils.getDefinitionByName(source) as Class; + pluginResource = new PluginInfoResource(new pluginInfoRef); + } + + loadPluginFromResource(pluginResource); + } + + private function loadPluginFromResource(pluginResource:MediaResourceBase):void + { + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); + mediaFactory.loadPlugin(pluginResource); + } + + private function onPluginLoaded(event:MediaFactoryEvent):void + { + trace("Plugin LOADED!"); + } + + private function onPluginLoadFailed(event:MediaFactoryEvent):void + { + trace("Plugin LOAD FAILED!"); + } + + private function onMediaError(event:MediaErrorEvent):void + { + Alert.show("Media Load Error : "+event.error.errorID+" - "+event.error.message); + } + + private function onMediaSizeChange(event:DisplayObjectEvent):void + { + var width:int = event.newWidth; + var height:int = event.newHeight; + + // Scale to native or smaller + if (width > MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) + { + if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) + { + mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; + mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); + } + else + { + mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); + mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; + } + } + else if (width > 0 && height > 0) + { + mediaContainerUIComponent.width = event.newWidth; + mediaContainerUIComponent.height = event.newHeight; + } + } + + private function onDurationChange(event:TimeEvent):void + { + seekBar.maximum = event.time; + lblDuration.text = timeCode(event.time); + } + + private function onCurrentTimeChange(event:TimeEvent):void + { + if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) + { + seekBar.value = event.time; + lblPlayhead.text = timeCode(event.time); + } + } + + private function onSeekingChange(event:SeekEvent):void + { + if (event.seeking) + { + this.onHideCaption(null); + } + else + { + waitForSeek = false; + } + } + + private function toggleDragging(state:Boolean):void + { + sliderDragging = state; + if (!state) + { + waitForSeek = true; + if (mediaPlayer.canSeek) + { + mediaPlayer.seek(seekBar.value); + } + } + } + + private function onTraitAdd(event:MediaElementEvent):void + { + switch (event.traitType) + { + case MediaTraitType.SEEK: + seekBar.enabled = seekBar.visible = true; + break; + } + } + + private function onShowCaption(event:TimelineMetadataEvent):void + { + var caption:Caption = event.marker as Caption; + + // Make sure this is a caption object, and just for good measure, we'll + // also check the namespace + if (captioningEnabled && caption != null) + { + this.captionLabel.htmlText = caption.text; + this.captionLabel.validateNow(); + formatCaption(caption); + } + } + + /** + * Handles formatting within the caption string. + */ + private function formatCaption(caption:Caption):void + { + for (var i:uint = 0; i < caption.numCaptionFormats; i++) + { + var captionFormat:CaptionFormat = caption.getCaptionFormatAt(i); + var txtFormat:TextFormat = new TextFormat(); + var style:CaptionStyle = captionFormat.style; + + if (style.textColor != null) + { + txtFormat.color = style.textColor; + } + + if (style.fontFamily != "") + { + txtFormat.font = style.fontFamily; + } + + if (style.fontSize > 0) + { + txtFormat.size = style.fontSize; + } + + if (style.fontStyle != "") + { + txtFormat.italic = (style.fontStyle == "italic") ? true : false; + } + + if (style.fontWeight != "") + { + txtFormat.bold = (style.fontWeight == "bold") ? true : false; + } + + if (style.textAlign != "") + { + txtFormat.align = style.textAlign; + } + + + this.captionLabel.mx_internal::getTextField().setTextFormat(txtFormat, captionFormat.startIndex, + captionFormat.endIndex); + if (this.captionLabel.wordWrap != style.wrapOption) + { + this.captionLabel.wordWrap = style.wrapOption; + } + } + } + + private function onHideCaption(event:TimelineMetadataEvent):void + { + // Save the current caption text so we can easily re-display + // if user is toggling the captioning button + savedCaptionText = captionLabel.htmlText; + captionLabel.htmlText = ""; + } + + private function onClickPlayBtn(event:Event):void + { + if (mediaPlayer.playing && mediaPlayer.canPause) + { + playBtn.label = "Play"; + mediaPlayer.pause(); + } + else if (mediaPlayer.paused && mediaPlayer.canPlay) + { + playBtn.label = "Pause"; + mediaPlayer.play(); + } + } + + private function enablePlayerControls(enable:Boolean=true):void + { + playBtn.enabled = seekBar.enabled = enable; + } + + private function onClickCC(e:Event):void + { + captioningEnabled = !captioningEnabled; + captionLabel.visible = captioningEnabled; + + var color:String = captioningEnabled ? "#00cc00" : "#cc0000"; + ccBox.setStyle("borderColor", color); + + if (!captioningEnabled) + { + onHideCaption(null); + } + else if (savedCaptionText && savedCaptionText.length > 0) + { + captionLabel.htmlText = savedCaptionText; + } + } + + private function showScrubTime(val:String):String + { + return timeCode(Number(val)); + } + + private function timeCode(sec:Number):String + { + var h:Number = Math.floor(sec/3600); + h = isNaN(h) ? 0 : h; + + var m:Number = Math.floor((sec%3600)/60); + m = isNaN(m) ? 0 : m; + + var s:Number = Math.floor((sec%3600)%60); + s = isNaN(s) ? 0 : s; + + return (h == 0 ? "":(h<10 ? "0"+h.toString()+":" : h.toString()+":"))+(m<10 ? "0"+m.toString() : m.toString())+":"+(s<10 ? "0"+s.toString() : s.toString()); + } + + ]]> +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      diff --git a/lib/osmf/samples/ChromeLibrary/.actionScriptProperties b/lib/osmf/samples/ChromeLibrary/.actionScriptProperties index e6e806f..46f0119 100644 --- a/lib/osmf/samples/ChromeLibrary/.actionScriptProperties +++ b/lib/osmf/samples/ChromeLibrary/.actionScriptProperties @@ -1,51 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/ChromeLibrary/.flexLibProperties b/lib/osmf/samples/ChromeLibrary/.flexLibProperties index ebf5a83..87cfbce 100644 --- a/lib/osmf/samples/ChromeLibrary/.flexLibProperties +++ b/lib/osmf/samples/ChromeLibrary/.flexLibProperties @@ -1,59 +1,59 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/application/ChromeApplication.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/application/ChromeApplication.as index 6017b8d..75068e2 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/application/ChromeApplication.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/application/ChromeApplication.as @@ -1,233 +1,233 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.application -{ - import flash.display.Sprite; - import flash.events.Event; - - import org.osmf.chrome.configuration.Configuration; - import org.osmf.chrome.configuration.PluginsParser; - import org.osmf.chrome.configuration.WidgetsParser; - import org.osmf.chrome.widgets.Widget; - import org.osmf.containers.MediaContainer; - import org.osmf.layout.LayoutRenderer; - import org.osmf.layout.LayoutRendererBase; - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - public class ChromeApplication extends Sprite - { - // Public Interface - // - - public function ChromeApplication() - { - super(); - - _factory = constructMediaFactory(); - _player = constructMediaPlayer(); - _renderer = constructLayoutRenderer(); - _container = constructMediaContainer(renderer); - _widgets = constructWidgetsParser(); - - pluginsParser = constructPluginsParser(); - - addChild(_container); - } - - public function get factory():MediaFactory - { - return _factory; - } - - public function get player():MediaPlayer - { - return _player; - } - - public function get renderer():LayoutRendererBase - { - return _renderer; - } - - public function get container():MediaContainer - { - return _container; - } - - public function get widgets():WidgetsParser - { - return _widgets; - } - - public function setup(configuration:Configuration):void - { - if (configuration.configuration != null) - { - _widgets.parse - ( configuration.configuration.widgets.* - , configuration.assetsManager - ); - - // Add widgets on top of the media: - var index:Number = 10000; - for each (var widget:Widget in _widgets.widgets) - { - widget.layoutMetadata.index = index++; - _renderer.addTarget(widget); - } - - pluginsParser.addEventListener(Event.COMPLETE, onPluginsParserComplete); - pluginsParser.parse(configuration.configuration.plugins.plugin, _factory); - - function onPluginsParserComplete(event:Event):void - { - processSetupComplete(); - } - } - else - { - processSetupComplete(); - } - } - - public function set media(value:MediaElement):void - { - if (value != _media) - { - // Remove the current media from the container: - if (_media) - { - container.removeMediaElement(_media); - } - - // Remove the current media reference from all widgets: - for each (var widget:Widget in _widgets.widgets) - { - widget.media = null; - } - - // See if subclasses wish to process the new value: - var processedNewValue:MediaElement = processNewMedia(value); - if (processedNewValue) - { - value = processedNewValue; - } - - // Set the new main media element: - _media = player.media = value; - - if (_media) - { - // Forward a reference to all chrome widgets: - for each (widget in _widgets.widgets) - { - widget.media = _media; - } - - // Add the media to the media container: - container.addMediaElement(_media); - } - } - } - - public function get media():MediaElement - { - return _media; - } - - public function set url(value:String):void - { - media = factory.createMediaElement(new URLResource(value)); - } - - // Protected - // - - protected function constructLayoutRenderer():LayoutRendererBase - { - return new LayoutRenderer(); - } - - protected function constructMediaContainer(renderer:LayoutRendererBase):MediaContainer - { - return new MediaContainer(renderer); - } - - protected function constructMediaFactory():MediaFactory - { - return new DefaultMediaFactory(); - } - - protected function constructMediaPlayer():MediaPlayer - { - return new MediaPlayer(); - } - - protected function constructWidgetsParser():WidgetsParser - { - return new WidgetsParser(); - } - - protected function constructPluginsParser():PluginsParser - { - return new PluginsParser(); - } - - protected function processSetupComplete():void - { - } - - protected function processNewMedia(value:MediaElement):MediaElement - { - return null; - } - - // Overrides - // - - override public function set width(value:Number):void - { - container.width = value; - } - - override public function set height(value:Number):void - { - container.height = value; - } - - // Internals - // - - private var _renderer:LayoutRendererBase; - private var _container:MediaContainer; - private var _factory:MediaFactory; - private var _player:MediaPlayer; - private var _media:MediaElement; - private var _widgets:WidgetsParser; - private var pluginsParser:PluginsParser; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.application +{ + import flash.display.Sprite; + import flash.events.Event; + + import org.osmf.chrome.configuration.Configuration; + import org.osmf.chrome.configuration.PluginsParser; + import org.osmf.chrome.configuration.WidgetsParser; + import org.osmf.chrome.widgets.Widget; + import org.osmf.containers.MediaContainer; + import org.osmf.layout.LayoutRenderer; + import org.osmf.layout.LayoutRendererBase; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + public class ChromeApplication extends Sprite + { + // Public Interface + // + + public function ChromeApplication() + { + super(); + + _factory = constructMediaFactory(); + _player = constructMediaPlayer(); + _renderer = constructLayoutRenderer(); + _container = constructMediaContainer(renderer); + _widgets = constructWidgetsParser(); + + pluginsParser = constructPluginsParser(); + + addChild(_container); + } + + public function get factory():MediaFactory + { + return _factory; + } + + public function get player():MediaPlayer + { + return _player; + } + + public function get renderer():LayoutRendererBase + { + return _renderer; + } + + public function get container():MediaContainer + { + return _container; + } + + public function get widgets():WidgetsParser + { + return _widgets; + } + + public function setup(configuration:Configuration):void + { + if (configuration.configuration != null) + { + _widgets.parse + ( configuration.configuration.widgets.* + , configuration.assetsManager + ); + + // Add widgets on top of the media: + var index:Number = 10000; + for each (var widget:Widget in _widgets.widgets) + { + widget.layoutMetadata.index = index++; + _renderer.addTarget(widget); + } + + pluginsParser.addEventListener(Event.COMPLETE, onPluginsParserComplete); + pluginsParser.parse(configuration.configuration.plugins.plugin, _factory); + + function onPluginsParserComplete(event:Event):void + { + processSetupComplete(); + } + } + else + { + processSetupComplete(); + } + } + + public function set media(value:MediaElement):void + { + if (value != _media) + { + // Remove the current media from the container: + if (_media) + { + container.removeMediaElement(_media); + } + + // Remove the current media reference from all widgets: + for each (var widget:Widget in _widgets.widgets) + { + widget.media = null; + } + + // See if subclasses wish to process the new value: + var processedNewValue:MediaElement = processNewMedia(value); + if (processedNewValue) + { + value = processedNewValue; + } + + // Set the new main media element: + _media = player.media = value; + + if (_media) + { + // Forward a reference to all chrome widgets: + for each (widget in _widgets.widgets) + { + widget.media = _media; + } + + // Add the media to the media container: + container.addMediaElement(_media); + } + } + } + + public function get media():MediaElement + { + return _media; + } + + public function set url(value:String):void + { + media = factory.createMediaElement(new URLResource(value)); + } + + // Protected + // + + protected function constructLayoutRenderer():LayoutRendererBase + { + return new LayoutRenderer(); + } + + protected function constructMediaContainer(renderer:LayoutRendererBase):MediaContainer + { + return new MediaContainer(renderer); + } + + protected function constructMediaFactory():MediaFactory + { + return new DefaultMediaFactory(); + } + + protected function constructMediaPlayer():MediaPlayer + { + return new MediaPlayer(); + } + + protected function constructWidgetsParser():WidgetsParser + { + return new WidgetsParser(); + } + + protected function constructPluginsParser():PluginsParser + { + return new PluginsParser(); + } + + protected function processSetupComplete():void + { + } + + protected function processNewMedia(value:MediaElement):MediaElement + { + return null; + } + + // Overrides + // + + override public function set width(value:Number):void + { + container.width = value; + } + + override public function set height(value:Number):void + { + container.height = value; + } + + // Internals + // + + private var _renderer:LayoutRendererBase; + private var _container:MediaContainer; + private var _factory:MediaFactory; + private var _player:MediaPlayer; + private var _media:MediaElement; + private var _widgets:WidgetsParser; + private var pluginsParser:PluginsParser; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/Asset.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/Asset.as index c93b47e..e1beb20 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/Asset.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/Asset.as @@ -1,28 +1,28 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - public class Asset - { - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + public class Asset + { + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetLoader.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetLoader.as index afc2c8f..fbcc184 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetLoader.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetLoader.as @@ -1,155 +1,155 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - import flash.display.Bitmap; - import flash.display.Loader; - import flash.display.LoaderInfo; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.IOErrorEvent; - import flash.net.URLRequest; - import flash.utils.getDefinitionByName; - - [Event(name="complete", type="flash.events.Event")] - public class AssetLoader extends EventDispatcher - { - public function load(resource:AssetResource):void - { - this.resource = resource; - - if (resource.local == false) - { - if ( resource is BitmapResource - || resource is FontResource - || resource is SymbolResource - ) - { - var loader:Loader = new Loader(); - loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoaderError); - loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete); - - loader.load(new URLRequest(resource.url)); - } - } - else - { - _asset = constructLocalAsset(); - - dispatchEvent(new Event(Event.COMPLETE)); - } - } - - public function get asset():Asset - { - return _asset; - } - - protected var resource:AssetResource; - private var _asset:Asset; - - protected function onLoaderError(event:IOErrorEvent):void - { - dispatchEvent(new Event(Event.COMPLETE)); - } - - protected function onLoaderComplete(event:Event):void - { - var loaderInfo:LoaderInfo = event.target as LoaderInfo; - - _asset = constructLoadedAsset(loaderInfo); - - dispatchEvent(new Event(Event.COMPLETE)); - } - - protected function constructLoadedAsset(loaderInfo:LoaderInfo):Asset - { - var asset:Asset; - var type:Class; - - if (resource is FontResource) - { - type = loaderInfo.applicationDomain.getDefinition(FontResource(resource).symbol) as Class; - asset = new FontAsset(type, resource as FontResource); - } - else if (resource is BitmapResource) - { - asset - = new BitmapAsset - ( loaderInfo.content as Bitmap - , resource is BitmapResource - ? BitmapResource(resource).scale9 - : null - ); - } - else if (resource is SymbolResource) - { - type = loaderInfo.applicationDomain.getDefinition(SymbolResource(resource).symbol) as Class; - asset = new SymbolAsset(type); - } - - return asset; - } - - protected function constructLocalAsset():Asset - { - var asset:Asset; - var type:Class; - - try - { - type = getDefinitionByName(resource.url) as Class; - } - catch(error:Error) - { - trace("WARNING: failure instantiating local asset:",error.message); - } - - if (type != null) - { - if (resource is BitmapResource) - { - asset = new BitmapAsset(new type(), BitmapResource(resource).scale9); - } - else if (resource is FontResource) - { - asset = new FontAsset(type, resource as FontResource); - } - else if (resource is SymbolResource) - { - asset = new SymbolAsset(type); - } - else - { - trace("WARNING: no suitable asset type found for "+resource.id); - } - } - else - { - trace("WARNING: failed loading "+resource.id); - } - - return asset; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + import flash.display.Bitmap; + import flash.display.Loader; + import flash.display.LoaderInfo; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.IOErrorEvent; + import flash.net.URLRequest; + import flash.utils.getDefinitionByName; + + [Event(name="complete", type="flash.events.Event")] + public class AssetLoader extends EventDispatcher + { + public function load(resource:AssetResource):void + { + this.resource = resource; + + if (resource.local == false) + { + if ( resource is BitmapResource + || resource is FontResource + || resource is SymbolResource + ) + { + var loader:Loader = new Loader(); + loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoaderError); + loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete); + + loader.load(new URLRequest(resource.url)); + } + } + else + { + _asset = constructLocalAsset(); + + dispatchEvent(new Event(Event.COMPLETE)); + } + } + + public function get asset():Asset + { + return _asset; + } + + protected var resource:AssetResource; + private var _asset:Asset; + + protected function onLoaderError(event:IOErrorEvent):void + { + dispatchEvent(new Event(Event.COMPLETE)); + } + + protected function onLoaderComplete(event:Event):void + { + var loaderInfo:LoaderInfo = event.target as LoaderInfo; + + _asset = constructLoadedAsset(loaderInfo); + + dispatchEvent(new Event(Event.COMPLETE)); + } + + protected function constructLoadedAsset(loaderInfo:LoaderInfo):Asset + { + var asset:Asset; + var type:Class; + + if (resource is FontResource) + { + type = loaderInfo.applicationDomain.getDefinition(FontResource(resource).symbol) as Class; + asset = new FontAsset(type, resource as FontResource); + } + else if (resource is BitmapResource) + { + asset + = new BitmapAsset + ( loaderInfo.content as Bitmap + , resource is BitmapResource + ? BitmapResource(resource).scale9 + : null + ); + } + else if (resource is SymbolResource) + { + type = loaderInfo.applicationDomain.getDefinition(SymbolResource(resource).symbol) as Class; + asset = new SymbolAsset(type); + } + + return asset; + } + + protected function constructLocalAsset():Asset + { + var asset:Asset; + var type:Class; + + try + { + type = getDefinitionByName(resource.url) as Class; + } + catch(error:Error) + { + trace("WARNING: failure instantiating local asset:",error.message); + } + + if (type != null) + { + if (resource is BitmapResource) + { + asset = new BitmapAsset(new type(), BitmapResource(resource).scale9); + } + else if (resource is FontResource) + { + asset = new FontAsset(type, resource as FontResource); + } + else if (resource is SymbolResource) + { + asset = new SymbolAsset(type); + } + else + { + trace("WARNING: no suitable asset type found for "+resource.id); + } + } + else + { + trace("WARNING: failed loading "+resource.id); + } + + return asset; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetResource.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetResource.as index 9939246..9cbf147 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetResource.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetResource.as @@ -1,53 +1,53 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - public class AssetResource - { - public function AssetResource(id:String, url:String, local:Boolean) - { - _id = id; - _url = url; - _local = local; - } - - public function get id():String - { - return _id; - } - - public function get url():String - { - return _url; - } - - public function get local():Boolean - { - return _local; - } - - private var _id:String; - private var _url:String; - private var _local:Boolean; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + public class AssetResource + { + public function AssetResource(id:String, url:String, local:Boolean) + { + _id = id; + _url = url; + _local = local; + } + + public function get id():String + { + return _id; + } + + public function get url():String + { + return _url; + } + + public function get local():Boolean + { + return _local; + } + + private var _id:String; + private var _url:String; + private var _local:Boolean; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetsManager.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetsManager.as index 56b7cde..93198fc 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetsManager.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/AssetsManager.as @@ -1,140 +1,140 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - import flash.display.DisplayObject; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.IOErrorEvent; - import flash.utils.Dictionary; - - import org.osmf.chrome.configuration.AssetsParser; - - [Event(name="complete", type="flash.events.Event")] - - public class AssetsManager extends EventDispatcher - { - // Public API - // - - public function AssetsManager() - { - loaders = new Dictionary(); - resourceByLoader = new Dictionary(); - } - - public function addConfigurationAssets(xml:XML):void - { - var parser:AssetsParser = new AssetsParser(); - parser.parse(xml.assets, this); - } - - public function addAsset(resource:AssetResource, loader:AssetLoader):void - { - if (loaders[resource] == undefined) - { - assetCount++; - } - - loaders[resource] = loader; - resourceByLoader[loader] = resource; - } - - public function getAsset(id:String):Asset - { - var result:Asset; - - for each (var resource:AssetResource in resourceByLoader) - { - if (resource.id == id) - { - result = loaders[resource].asset; - break; - } - } - - return result; - } - - public function getDisplayObject(id:String):DisplayObject - { - var result:DisplayObject; - var asset:DisplayObjectAsset = getAsset(id) as DisplayObjectAsset; - if (asset) - { - result = asset.displayObject; - } - return result; - } - - public function load():void - { - completionCount = assetCount; - for each (var loader:AssetLoader in loaders) - { - loader.addEventListener(Event.COMPLETE, onAssetLoaderComplete); - loader.load(resourceByLoader[loader]); - } - } - - // Internals - // - - private var loaders:Dictionary; - private var resourceByLoader:Dictionary; - - private var assetCount:int = 0; - private var _completionCount:int = -1; - - private function set completionCount(value:int):void - { - if (_completionCount != value) - { - _completionCount = value; - if (_completionCount == 0) - { - dispatchEvent(new Event(Event.COMPLETE)); - } - } - } - private function get completionCount():int - { - return _completionCount; - } - - private function onAssetLoaderComplete(event:Event):void - { - var loader:AssetLoader = event.target as AssetLoader; - var resource:AssetResource = resourceByLoader[event.target]; - - completionCount--; - } - - private function onAssetLoaderError(event:IOErrorEvent):void - { - var resource:AssetResource = resourceByLoader[event.target]; - - completionCount--; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + import flash.display.DisplayObject; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.IOErrorEvent; + import flash.utils.Dictionary; + + import org.osmf.chrome.configuration.AssetsParser; + + [Event(name="complete", type="flash.events.Event")] + + public class AssetsManager extends EventDispatcher + { + // Public API + // + + public function AssetsManager() + { + loaders = new Dictionary(); + resourceByLoader = new Dictionary(); + } + + public function addConfigurationAssets(xml:XML):void + { + var parser:AssetsParser = new AssetsParser(); + parser.parse(xml.assets, this); + } + + public function addAsset(resource:AssetResource, loader:AssetLoader):void + { + if (loaders[resource] == undefined) + { + assetCount++; + } + + loaders[resource] = loader; + resourceByLoader[loader] = resource; + } + + public function getAsset(id:String):Asset + { + var result:Asset; + + for each (var resource:AssetResource in resourceByLoader) + { + if (resource.id == id) + { + result = loaders[resource].asset; + break; + } + } + + return result; + } + + public function getDisplayObject(id:String):DisplayObject + { + var result:DisplayObject; + var asset:DisplayObjectAsset = getAsset(id) as DisplayObjectAsset; + if (asset) + { + result = asset.displayObject; + } + return result; + } + + public function load():void + { + completionCount = assetCount; + for each (var loader:AssetLoader in loaders) + { + loader.addEventListener(Event.COMPLETE, onAssetLoaderComplete); + loader.load(resourceByLoader[loader]); + } + } + + // Internals + // + + private var loaders:Dictionary; + private var resourceByLoader:Dictionary; + + private var assetCount:int = 0; + private var _completionCount:int = -1; + + private function set completionCount(value:int):void + { + if (_completionCount != value) + { + _completionCount = value; + if (_completionCount == 0) + { + dispatchEvent(new Event(Event.COMPLETE)); + } + } + } + private function get completionCount():int + { + return _completionCount; + } + + private function onAssetLoaderComplete(event:Event):void + { + var loader:AssetLoader = event.target as AssetLoader; + var resource:AssetResource = resourceByLoader[event.target]; + + completionCount--; + } + + private function onAssetLoaderError(event:IOErrorEvent):void + { + var resource:AssetResource = resourceByLoader[event.target]; + + completionCount--; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/BitmapAsset.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/BitmapAsset.as index 84e7db3..921cda7 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/BitmapAsset.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/BitmapAsset.as @@ -1,49 +1,49 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - import flash.display.Bitmap; - import flash.display.DisplayObject; - import flash.geom.Rectangle; - - public class BitmapAsset extends DisplayObjectAsset - { - public function BitmapAsset(bitmap:Bitmap, scale9:Rectangle = null) - { - _bitmap = bitmap; - _scale9 = scale9; - super(); - } - - override public function get displayObject():DisplayObject - { - return _scale9 - ? new Scale9Bitmap(_bitmap, _scale9) - : new Bitmap(_bitmap.bitmapData.clone(), _bitmap.pixelSnapping, _bitmap.smoothing); - } - - private var _bitmap:Bitmap; - private var _scale9:Rectangle; - - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + import flash.display.Bitmap; + import flash.display.DisplayObject; + import flash.geom.Rectangle; + + public class BitmapAsset extends DisplayObjectAsset + { + public function BitmapAsset(bitmap:Bitmap, scale9:Rectangle = null) + { + _bitmap = bitmap; + _scale9 = scale9; + super(); + } + + override public function get displayObject():DisplayObject + { + return _scale9 + ? new Scale9Bitmap(_bitmap, _scale9) + : new Bitmap(_bitmap.bitmapData.clone(), _bitmap.pixelSnapping, _bitmap.smoothing); + } + + private var _bitmap:Bitmap; + private var _scale9:Rectangle; + + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/BitmapResource.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/BitmapResource.as index be30a0c..da32d6e 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/BitmapResource.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/BitmapResource.as @@ -1,43 +1,43 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - import flash.geom.Rectangle; - - public class BitmapResource extends AssetResource - { - public function BitmapResource(id:String, url:String, local:Boolean, scale9:Rectangle) - { - _scale9 = scale9; - - super(id, url, local); - } - - public function get scale9():Rectangle - { - return _scale9; - } - - private var _scale9:Rectangle; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + import flash.geom.Rectangle; + + public class BitmapResource extends AssetResource + { + public function BitmapResource(id:String, url:String, local:Boolean, scale9:Rectangle) + { + _scale9 = scale9; + + super(id, url, local); + } + + public function get scale9():Rectangle + { + return _scale9; + } + + private var _scale9:Rectangle; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/DisplayObjectAsset.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/DisplayObjectAsset.as index eafbff8..ba63a3d 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/DisplayObjectAsset.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/DisplayObjectAsset.as @@ -1,34 +1,34 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - import flash.display.DisplayObject; - - public class DisplayObjectAsset extends Asset - { - public function get displayObject():DisplayObject - { - return null; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + import flash.display.DisplayObject; + + public class DisplayObjectAsset extends Asset + { + public function get displayObject():DisplayObject + { + return null; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/FontAsset.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/FontAsset.as index bd1a0a2..cc8104d 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/FontAsset.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/FontAsset.as @@ -1,63 +1,63 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - import flash.text.Font; - import flash.text.TextFormat; - import flash.text.TextFormatAlign; - - public class FontAsset extends SymbolAsset - { - public function FontAsset(font:Class, resource:FontResource) - { - super(font); - - _font = new font(); - Font.registerFont(font); - - this.resource = resource; - } - - public function get font():Font - { - return _font; - } - - public function get format():TextFormat - { - var result:TextFormat - = new TextFormat - ( _font.fontName - , resource.size - , resource.color - ); - - result.align = TextFormatAlign.LEFT; - - return result; - } - - private var _font:Font; - private var resource:FontResource; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + import flash.text.Font; + import flash.text.TextFormat; + import flash.text.TextFormatAlign; + + public class FontAsset extends SymbolAsset + { + public function FontAsset(font:Class, resource:FontResource) + { + super(font); + + _font = new font(); + Font.registerFont(font); + + this.resource = resource; + } + + public function get font():Font + { + return _font; + } + + public function get format():TextFormat + { + var result:TextFormat + = new TextFormat + ( _font.fontName + , resource.size + , resource.color + ); + + result.align = TextFormatAlign.LEFT; + + return result; + } + + private var _font:Font; + private var resource:FontResource; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/FontResource.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/FontResource.as index 7e09fe7..1b2bfa5 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/FontResource.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/FontResource.as @@ -1,58 +1,58 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - public class FontResource extends SymbolResource - { - public function FontResource - ( id:String - , url:String - , local:Boolean - , symbol:String - , size:Number - , color:uint - ) - { - super(id, url, local, symbol); - - _size = size; - _color = color; - } - - public function get size():Number - { - return _size; - } - - public function get color():uint - { - return _color; - } - - // Internals - // - - private var _size:Number; - private var _color:uint; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + public class FontResource extends SymbolResource + { + public function FontResource + ( id:String + , url:String + , local:Boolean + , symbol:String + , size:Number + , color:uint + ) + { + super(id, url, local, symbol); + + _size = size; + _color = color; + } + + public function get size():Number + { + return _size; + } + + public function get color():uint + { + return _color; + } + + // Internals + // + + private var _size:Number; + private var _color:uint; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/Scale9Bitmap.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/Scale9Bitmap.as index 0fed81a..d581cf7 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/Scale9Bitmap.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/Scale9Bitmap.as @@ -1,152 +1,152 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - import flash.display.Bitmap; - import flash.display.BitmapData; - import flash.geom.Matrix; - import flash.geom.Rectangle; - - public class Scale9Bitmap extends Bitmap - { - public function Scale9Bitmap(source:Bitmap, scale9:Rectangle) - { - this.scale9 = scale9; - this.sourceData = source.bitmapData.clone(); - super(source.bitmapData.clone(), source.pixelSnapping, source.smoothing); - } - - // Overrides - // - - override public function set width(value:Number):void - { - apply9Scale(value, height); - } - - override public function set height(value:Number):void - { - apply9Scale(width, value); - } - - // Internals - // - - private var sourceData:BitmapData; - private var scale9:Rectangle; - - private function apply9Scale(width:Number, height:Number):void - { - if (bitmapData) - { - bitmapData.dispose(); - } - - if ( width - && height - && ( width != sourceData.width - || height != sourceData.height - ) - ) - { - try - { - bitmapData = new BitmapData(width, height, true, 0); - - var sourceWidth:Number = sourceData.width; - var sourceHeight:Number = sourceData.height; - - var rightWidth:Number = sourceHeight - scale9.y - scale9.height; - var bottomHeight:Number = sourceWidth - scale9.x - scale9.width; - - var matrix:Matrix = new Matrix(); - var clipRect:Rectangle = new Rectangle(); - - - // [1] | [5] | [2] - // --------------- - // [8] | [7] | [9] - // --------------- - // [4] | [6] | [3] - - // [1] - clipRect = new Rectangle(0, 0, scale9.x, scale9.y); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - - // [2] - matrix.tx = width - sourceWidth; - clipRect = new Rectangle(width - bottomHeight, 0, scale9.x, scale9.y); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - - // [3] - matrix.ty = height - sourceHeight; - clipRect = new Rectangle(width - bottomHeight, height - rightWidth, scale9.x, bottomHeight); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - - // [4] - matrix.tx = 0; - clipRect = new Rectangle(0, height - rightWidth, scale9.x, rightWidth); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - - // [5] - matrix.identity(); - matrix.a = (width - scale9.x - rightWidth) / scale9.width; - matrix.tx = scale9.x - scale9.x * matrix.a; - clipRect = new Rectangle(scale9.x, 0, scale9.width * matrix.a, scale9.y); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - - // [6] - matrix.ty = height - sourceHeight; - clipRect = new Rectangle(scale9.x, height - rightWidth, scale9.width * matrix.a, bottomHeight); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - - // [7] - matrix.d = (height - scale9.y - bottomHeight) / scale9.height; - matrix.ty = scale9.y - scale9.y * matrix.d; - clipRect = new Rectangle(scale9.x, scale9.y, scale9.width * matrix.a, scale9.height * matrix.d); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - - // [8] - matrix.identity(); - matrix.d = (height - scale9.y - bottomHeight) / scale9.height; - matrix.ty = scale9.y - scale9.y * matrix.d; - clipRect = new Rectangle(0, scale9.y, scale9.x, scale9.height * matrix.d); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - - // [9] - matrix.tx = width - sourceWidth; - clipRect = new Rectangle(width - rightWidth, scale9.y, rightWidth, scale9.height * matrix.d); - bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); - } - catch(e:ArgumentError) - { - trace("Warning: argument error on 9-slicing bitmap!"); - } - } - else - { - bitmapData = sourceData.clone(); - } - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + import flash.display.Bitmap; + import flash.display.BitmapData; + import flash.geom.Matrix; + import flash.geom.Rectangle; + + public class Scale9Bitmap extends Bitmap + { + public function Scale9Bitmap(source:Bitmap, scale9:Rectangle) + { + this.scale9 = scale9; + this.sourceData = source.bitmapData.clone(); + super(source.bitmapData.clone(), source.pixelSnapping, source.smoothing); + } + + // Overrides + // + + override public function set width(value:Number):void + { + apply9Scale(value, height); + } + + override public function set height(value:Number):void + { + apply9Scale(width, value); + } + + // Internals + // + + private var sourceData:BitmapData; + private var scale9:Rectangle; + + private function apply9Scale(width:Number, height:Number):void + { + if (bitmapData) + { + bitmapData.dispose(); + } + + if ( width + && height + && ( width != sourceData.width + || height != sourceData.height + ) + ) + { + try + { + bitmapData = new BitmapData(width, height, true, 0); + + var sourceWidth:Number = sourceData.width; + var sourceHeight:Number = sourceData.height; + + var rightWidth:Number = sourceHeight - scale9.y - scale9.height; + var bottomHeight:Number = sourceWidth - scale9.x - scale9.width; + + var matrix:Matrix = new Matrix(); + var clipRect:Rectangle = new Rectangle(); + + + // [1] | [5] | [2] + // --------------- + // [8] | [7] | [9] + // --------------- + // [4] | [6] | [3] + + // [1] + clipRect = new Rectangle(0, 0, scale9.x, scale9.y); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + + // [2] + matrix.tx = width - sourceWidth; + clipRect = new Rectangle(width - bottomHeight, 0, scale9.x, scale9.y); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + + // [3] + matrix.ty = height - sourceHeight; + clipRect = new Rectangle(width - bottomHeight, height - rightWidth, scale9.x, bottomHeight); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + + // [4] + matrix.tx = 0; + clipRect = new Rectangle(0, height - rightWidth, scale9.x, rightWidth); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + + // [5] + matrix.identity(); + matrix.a = (width - scale9.x - rightWidth) / scale9.width; + matrix.tx = scale9.x - scale9.x * matrix.a; + clipRect = new Rectangle(scale9.x, 0, scale9.width * matrix.a, scale9.y); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + + // [6] + matrix.ty = height - sourceHeight; + clipRect = new Rectangle(scale9.x, height - rightWidth, scale9.width * matrix.a, bottomHeight); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + + // [7] + matrix.d = (height - scale9.y - bottomHeight) / scale9.height; + matrix.ty = scale9.y - scale9.y * matrix.d; + clipRect = new Rectangle(scale9.x, scale9.y, scale9.width * matrix.a, scale9.height * matrix.d); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + + // [8] + matrix.identity(); + matrix.d = (height - scale9.y - bottomHeight) / scale9.height; + matrix.ty = scale9.y - scale9.y * matrix.d; + clipRect = new Rectangle(0, scale9.y, scale9.x, scale9.height * matrix.d); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + + // [9] + matrix.tx = width - sourceWidth; + clipRect = new Rectangle(width - rightWidth, scale9.y, rightWidth, scale9.height * matrix.d); + bitmapData.draw(sourceData, matrix, null, null, clipRect, smoothing); + } + catch(e:ArgumentError) + { + trace("Warning: argument error on 9-slicing bitmap!"); + } + } + else + { + bitmapData = sourceData.clone(); + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/SymbolAsset.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/SymbolAsset.as index 4f93f8d..c31c5d5 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/SymbolAsset.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/SymbolAsset.as @@ -1,40 +1,40 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - public class SymbolAsset extends Asset - { - public function SymbolAsset(type:Class) - { - _type = type; - super(); - } - - public function get type():Class - { - return _type; - } - - private var _type:Class; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + public class SymbolAsset extends Asset + { + public function SymbolAsset(type:Class) + { + _type = type; + super(); + } + + public function get type():Class + { + return _type; + } + + private var _type:Class; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/SymbolResource.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/SymbolResource.as index 14f9921..a0fa1e2 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/SymbolResource.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/assets/SymbolResource.as @@ -1,42 +1,42 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.assets -{ - public class SymbolResource extends AssetResource - { - public function SymbolResource(id:String, url:String, local:Boolean, symbol:String) - { - _symbol = symbol; - - super(id, url, local); - } - - public function get symbol():String - { - return _symbol; - } - - private var _symbol:String; - - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.assets +{ + public class SymbolResource extends AssetResource + { + public function SymbolResource(id:String, url:String, local:Boolean, symbol:String) + { + _symbol = symbol; + + super(id, url, local); + } + + public function get symbol():String + { + return _symbol; + } + + private var _symbol:String; + + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/AssetsParser.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/AssetsParser.as index 2b2a77e..b2bac82 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/AssetsParser.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/AssetsParser.as @@ -1,114 +1,114 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.configuration -{ - import flash.errors.IllegalOperationError; - import flash.geom.Rectangle; - - import org.osmf.chrome.assets.AssetLoader; - import org.osmf.chrome.assets.AssetResource; - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.assets.BitmapResource; - import org.osmf.chrome.assets.FontResource; - - public class AssetsParser - { - public function parse(assetsList:XMLList, assetsManager:AssetsManager):void - { - for each (var assets:XML in assetsList) - { - var baseURL:String = assets.@baseURL || ""; - var loader:AssetLoader; - var resource:AssetResource; - for each (var asset:XML in assets.asset) - { - loader = new AssetLoader(); - resource = assetToResource(asset, baseURL); - if (loader && resource) - { - assetsManager.addAsset(resource, loader); - } - else - { - throw new IllegalOperationError("Unknown resource type", asset.@type); - } - } - } - } - - // Internals - // - - private function assetToResource(asset:XML, baseURL:String = ""):AssetResource - { - var type:String = String(asset.@type || "").toLowerCase(); - var resource:AssetResource; - - switch (type) - { - case "bitmapfile": - case "embeddedbitmap": - resource = new BitmapResource - ( asset.@id - , baseURL + asset.@url - , type == "embeddedbitmap" - , parseRect(asset.@scale9) - ); - break; - - case "fontsymbol": - case "embeddedfont": - resource = new FontResource - ( asset.@id - , baseURL + asset.@url - , type == "embeddedfont" - , asset.@symbol - , parseInt(asset.@fontSize || "11") - , parseInt(asset.@color || "0xFFFFFF") - ); - break; - } - - return resource; - } - - private function parseRect(value:String):Rectangle - { - var result:Rectangle; - - var values:Array = value.split(","); - if (values.length == 4) - { - result - = new Rectangle - ( parseInt(values[0]) - , parseInt(values[1]) - , parseInt(values[2]) - , parseInt(values[3]) - ); - } - - return result; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.configuration +{ + import flash.errors.IllegalOperationError; + import flash.geom.Rectangle; + + import org.osmf.chrome.assets.AssetLoader; + import org.osmf.chrome.assets.AssetResource; + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.assets.BitmapResource; + import org.osmf.chrome.assets.FontResource; + + public class AssetsParser + { + public function parse(assetsList:XMLList, assetsManager:AssetsManager):void + { + for each (var assets:XML in assetsList) + { + var baseURL:String = assets.@baseURL || ""; + var loader:AssetLoader; + var resource:AssetResource; + for each (var asset:XML in assets.asset) + { + loader = new AssetLoader(); + resource = assetToResource(asset, baseURL); + if (loader && resource) + { + assetsManager.addAsset(resource, loader); + } + else + { + throw new IllegalOperationError("Unknown resource type", asset.@type); + } + } + } + } + + // Internals + // + + private function assetToResource(asset:XML, baseURL:String = ""):AssetResource + { + var type:String = String(asset.@type || "").toLowerCase(); + var resource:AssetResource; + + switch (type) + { + case "bitmapfile": + case "embeddedbitmap": + resource = new BitmapResource + ( asset.@id + , baseURL + asset.@url + , type == "embeddedbitmap" + , parseRect(asset.@scale9) + ); + break; + + case "fontsymbol": + case "embeddedfont": + resource = new FontResource + ( asset.@id + , baseURL + asset.@url + , type == "embeddedfont" + , asset.@symbol + , parseInt(asset.@fontSize || "11") + , parseInt(asset.@color || "0xFFFFFF") + ); + break; + } + + return resource; + } + + private function parseRect(value:String):Rectangle + { + var result:Rectangle; + + var values:Array = value.split(","); + if (values.length == 4) + { + result + = new Rectangle + ( parseInt(values[0]) + , parseInt(values[1]) + , parseInt(values[2]) + , parseInt(values[3]) + ); + } + + return result; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/Configuration.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/Configuration.as index b1e7322..9b1b386 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/Configuration.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/Configuration.as @@ -1,102 +1,102 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.configuration -{ - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.IOErrorEvent; - import flash.net.URLLoader; - import flash.net.URLRequest; - - import org.osmf.chrome.assets.AssetsManager; - - [Event(name="complete", type="flash.events.Event")] - - public class Configuration extends EventDispatcher - { - public function Configuration() - { - super(); - } - - public function loadFromFile(url:String, loadAssets:Boolean):void - { - _configuration = null; - - var loader:URLLoader = new URLLoader(); - loader.addEventListener - ( IOErrorEvent.IO_ERROR - , function(event:IOErrorEvent):void - { - trace("WARNING: configuration loading error:", event.text); - dispatchEvent(new Event(Event.COMPLETE)); - } - ); - loader.addEventListener - ( Event.COMPLETE - , function(event:Event):void - { - loadFromXML(new XML(loader.data), loadAssets); - } - ); - loader.load(new URLRequest(url)); - } - - public function loadFromXML(value:XML, loadAssets:Boolean):void - { - _configuration = value; - if (loadAssets) - { - _assetsManager = new AssetsManager(); - _assetsManager.addEventListener - ( Event.COMPLETE - , function (event:Event):void - { - var assetsManager:AssetsManager - dispatchEvent(new Event(Event.COMPLETE)); - } - ); - - _assetsManager.addConfigurationAssets(_configuration); - _assetsManager.load(); - } - else - { - dispatchEvent(new Event(Event.COMPLETE)); - } - } - - public function get configuration():XML - { - return _configuration; - } - - public function get assetsManager():AssetsManager - { - return _assetsManager; - } - - private var _configuration:XML; - private var _assetsManager:AssetsManager; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.configuration +{ + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.IOErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + + import org.osmf.chrome.assets.AssetsManager; + + [Event(name="complete", type="flash.events.Event")] + + public class Configuration extends EventDispatcher + { + public function Configuration() + { + super(); + } + + public function loadFromFile(url:String, loadAssets:Boolean):void + { + _configuration = null; + + var loader:URLLoader = new URLLoader(); + loader.addEventListener + ( IOErrorEvent.IO_ERROR + , function(event:IOErrorEvent):void + { + trace("WARNING: configuration loading error:", event.text); + dispatchEvent(new Event(Event.COMPLETE)); + } + ); + loader.addEventListener + ( Event.COMPLETE + , function(event:Event):void + { + loadFromXML(new XML(loader.data), loadAssets); + } + ); + loader.load(new URLRequest(url)); + } + + public function loadFromXML(value:XML, loadAssets:Boolean):void + { + _configuration = value; + if (loadAssets) + { + _assetsManager = new AssetsManager(); + _assetsManager.addEventListener + ( Event.COMPLETE + , function (event:Event):void + { + var assetsManager:AssetsManager + dispatchEvent(new Event(Event.COMPLETE)); + } + ); + + _assetsManager.addConfigurationAssets(_configuration); + _assetsManager.load(); + } + else + { + dispatchEvent(new Event(Event.COMPLETE)); + } + } + + public function get configuration():XML + { + return _configuration; + } + + public function get assetsManager():AssetsManager + { + return _assetsManager; + } + + private var _configuration:XML; + private var _assetsManager:AssetsManager; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/LayoutAttributesParser.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/LayoutAttributesParser.as index f1cddfb..b89503b 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/LayoutAttributesParser.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/LayoutAttributesParser.as @@ -1,190 +1,190 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.configuration -{ - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - - public class LayoutAttributesParser - { - public static function parse(xml:XML, layoutMetadata:LayoutMetadata):void - { - // Absolute: - // - - var x:Number = Number(xml.@x); - if (!isNaN(x) && xml.@x != undefined) - { - layoutMetadata.x = x; - } - - var y:Number = Number(xml.@y); - if (!isNaN(y) && xml.@y != undefined) - { - layoutMetadata.y = y; - } - - var width:Number = Number(xml.@width); - if (!isNaN(width) && xml.@width != undefined) - { - layoutMetadata.width = width; - } - - var height:Number = Number(xml.@height); - if (!isNaN(height) && xml.@height != undefined) - { - layoutMetadata.height = height; - } - - // Relative: - // - - var percentX:Number = Number(xml.@percentX); - if (!isNaN(percentX) && xml.@percentX != undefined) - { - layoutMetadata.percentX = percentX; - } - - var percentY:Number = Number(xml.@percentY); - if (!isNaN(percentY) && xml.@percentY != undefined) - { - layoutMetadata.percentY = percentY; - } - - var percentWidth:Number = Number(xml.@percentWidth); - if (!isNaN(percentWidth) && xml.@percentWidth != undefined) - { - layoutMetadata.percentWidth = percentWidth; - } - - var percentHeight:Number = Number(xml.@percentHeight); - if (!isNaN(percentHeight) && xml.@percentHeight != undefined) - { - layoutMetadata.percentHeight = percentHeight; - } - - // Anchor: - // - - var left:Number = Number(xml.@left); - if (!isNaN(left) && xml.@left != undefined) - { - layoutMetadata.left = left; - } - - var top:Number = Number(xml.@top); - if (!isNaN(top) && xml.@top != undefined) - { - layoutMetadata.top = top; - } - - var right:Number = Number(xml.@right); - if (!isNaN(right) && xml.@right != undefined) - { - layoutMetadata.right = right; - } - - var bottom:Number = Number(xml.@bottom); - if (!isNaN(bottom) && xml.@bottom != undefined) - { - layoutMetadata.bottom = bottom; - } - - // Padding: - // - - var paddingLeft:Number = Number(xml.@paddingLeft); - if (!isNaN(paddingLeft) && xml.@paddingLeft != undefined) - { - layoutMetadata.paddingLeft = paddingLeft; - } - - var paddingTop:Number = Number(xml.@paddingTop); - if (!isNaN(paddingTop) && xml.@paddingTop != undefined) - { - layoutMetadata.paddingTop = paddingTop; - } - - var paddingRight:Number = Number(xml.@paddingRight); - if (!isNaN(paddingRight) && xml.@paddingRight != undefined) - { - layoutMetadata.paddingRight = paddingRight; - } - - var paddingBottom:Number = Number(xml.@paddingBottom); - if (!isNaN(paddingBottom) && xml.@paddingBottom != undefined) - { - layoutMetadata.paddingBottom = paddingBottom; - } - - // Attributes: - // - - var index:Number = Number(xml.@index); - if (!isNaN(index) && xml.@index != undefined) - { - layoutMetadata.index = index; - } - - var scaleMode:String = String(xml.@scaleMode || "").toLocaleLowerCase(); - switch(scaleMode) - { - case "none": layoutMetadata.scaleMode = ScaleMode.NONE; break; - case "stretch": layoutMetadata.scaleMode = ScaleMode.STRETCH; break; - case "letterbox": layoutMetadata.scaleMode = ScaleMode.LETTERBOX; break; - case "zoom": layoutMetadata.scaleMode = ScaleMode.ZOOM; break; - } - - var verticalAlign:String = String(xml.@verticalAlign || "").toLocaleLowerCase(); - switch(verticalAlign) - { - case "top": layoutMetadata.verticalAlign = VerticalAlign.TOP; break; - case "middle": layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; break; - case "bottom": layoutMetadata.verticalAlign = VerticalAlign.BOTTOM; break; - } - - var horizontalAlign:String = String(xml.@horizontalAlign || "").toLocaleLowerCase(); - switch(horizontalAlign) - { - case "left": layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; break; - case "center": layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; break; - case "right": layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; break; - } - - layoutMetadata.snapToPixel = !(String(xml.@snapToPixel || "").toLocaleLowerCase() == "false"); - - var layoutMode:String = String(xml.@layoutMode || "").toLocaleLowerCase(); - switch(layoutMode) - { - case "none": layoutMetadata.layoutMode = LayoutMode.NONE; break; - case "horizontal": layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; break; - case "vertical": layoutMetadata.layoutMode = LayoutMode.VERTICAL; break; - } - - layoutMetadata.includeInLayout = !(String(xml.@includeInLayout || "").toLocaleLowerCase() == "false"); - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.configuration +{ + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + + public class LayoutAttributesParser + { + public static function parse(xml:XML, layoutMetadata:LayoutMetadata):void + { + // Absolute: + // + + var x:Number = Number(xml.@x); + if (!isNaN(x) && xml.@x != undefined) + { + layoutMetadata.x = x; + } + + var y:Number = Number(xml.@y); + if (!isNaN(y) && xml.@y != undefined) + { + layoutMetadata.y = y; + } + + var width:Number = Number(xml.@width); + if (!isNaN(width) && xml.@width != undefined) + { + layoutMetadata.width = width; + } + + var height:Number = Number(xml.@height); + if (!isNaN(height) && xml.@height != undefined) + { + layoutMetadata.height = height; + } + + // Relative: + // + + var percentX:Number = Number(xml.@percentX); + if (!isNaN(percentX) && xml.@percentX != undefined) + { + layoutMetadata.percentX = percentX; + } + + var percentY:Number = Number(xml.@percentY); + if (!isNaN(percentY) && xml.@percentY != undefined) + { + layoutMetadata.percentY = percentY; + } + + var percentWidth:Number = Number(xml.@percentWidth); + if (!isNaN(percentWidth) && xml.@percentWidth != undefined) + { + layoutMetadata.percentWidth = percentWidth; + } + + var percentHeight:Number = Number(xml.@percentHeight); + if (!isNaN(percentHeight) && xml.@percentHeight != undefined) + { + layoutMetadata.percentHeight = percentHeight; + } + + // Anchor: + // + + var left:Number = Number(xml.@left); + if (!isNaN(left) && xml.@left != undefined) + { + layoutMetadata.left = left; + } + + var top:Number = Number(xml.@top); + if (!isNaN(top) && xml.@top != undefined) + { + layoutMetadata.top = top; + } + + var right:Number = Number(xml.@right); + if (!isNaN(right) && xml.@right != undefined) + { + layoutMetadata.right = right; + } + + var bottom:Number = Number(xml.@bottom); + if (!isNaN(bottom) && xml.@bottom != undefined) + { + layoutMetadata.bottom = bottom; + } + + // Padding: + // + + var paddingLeft:Number = Number(xml.@paddingLeft); + if (!isNaN(paddingLeft) && xml.@paddingLeft != undefined) + { + layoutMetadata.paddingLeft = paddingLeft; + } + + var paddingTop:Number = Number(xml.@paddingTop); + if (!isNaN(paddingTop) && xml.@paddingTop != undefined) + { + layoutMetadata.paddingTop = paddingTop; + } + + var paddingRight:Number = Number(xml.@paddingRight); + if (!isNaN(paddingRight) && xml.@paddingRight != undefined) + { + layoutMetadata.paddingRight = paddingRight; + } + + var paddingBottom:Number = Number(xml.@paddingBottom); + if (!isNaN(paddingBottom) && xml.@paddingBottom != undefined) + { + layoutMetadata.paddingBottom = paddingBottom; + } + + // Attributes: + // + + var index:Number = Number(xml.@index); + if (!isNaN(index) && xml.@index != undefined) + { + layoutMetadata.index = index; + } + + var scaleMode:String = String(xml.@scaleMode || "").toLocaleLowerCase(); + switch(scaleMode) + { + case "none": layoutMetadata.scaleMode = ScaleMode.NONE; break; + case "stretch": layoutMetadata.scaleMode = ScaleMode.STRETCH; break; + case "letterbox": layoutMetadata.scaleMode = ScaleMode.LETTERBOX; break; + case "zoom": layoutMetadata.scaleMode = ScaleMode.ZOOM; break; + } + + var verticalAlign:String = String(xml.@verticalAlign || "").toLocaleLowerCase(); + switch(verticalAlign) + { + case "top": layoutMetadata.verticalAlign = VerticalAlign.TOP; break; + case "middle": layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; break; + case "bottom": layoutMetadata.verticalAlign = VerticalAlign.BOTTOM; break; + } + + var horizontalAlign:String = String(xml.@horizontalAlign || "").toLocaleLowerCase(); + switch(horizontalAlign) + { + case "left": layoutMetadata.horizontalAlign = HorizontalAlign.LEFT; break; + case "center": layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; break; + case "right": layoutMetadata.horizontalAlign = HorizontalAlign.RIGHT; break; + } + + layoutMetadata.snapToPixel = !(String(xml.@snapToPixel || "").toLocaleLowerCase() == "false"); + + var layoutMode:String = String(xml.@layoutMode || "").toLocaleLowerCase(); + switch(layoutMode) + { + case "none": layoutMetadata.layoutMode = LayoutMode.NONE; break; + case "horizontal": layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; break; + case "vertical": layoutMetadata.layoutMode = LayoutMode.VERTICAL; break; + } + + layoutMetadata.includeInLayout = !(String(xml.@includeInLayout || "").toLocaleLowerCase() == "false"); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/PluginsParser.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/PluginsParser.as index aa7159d..2989a4e 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/PluginsParser.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/PluginsParser.as @@ -1,70 +1,70 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.configuration -{ - import flash.events.Event; - import flash.events.EventDispatcher; - - import org.osmf.events.MediaFactoryEvent; - import org.osmf.media.MediaFactory; - import org.osmf.media.URLResource; - - [Event(name="complete", type="flash.events.Event")] - - public class PluginsParser extends EventDispatcher - { - public function parse(pluginsList:XMLList, mediaFactory:MediaFactory):void - { - var pluginsToLoad:int = 0; - - if (mediaFactory == null) - { - onPluginResult(); - return; - } - else - { - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginResult); - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginResult); - } - - function onPluginResult(event:MediaFactoryEvent = null):void - { - pluginsToLoad--; - if (pluginsToLoad <= 0) - { - mediaFactory.removeEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginResult); - mediaFactory.removeEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginResult); - dispatchEvent(new Event(Event.COMPLETE)); - } - } - - for each (var plugin:XML in pluginsList) - { - mediaFactory.loadPlugin(new URLResource(plugin.@url)); - } - - onPluginResult(); - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.configuration +{ + import flash.events.Event; + import flash.events.EventDispatcher; + + import org.osmf.events.MediaFactoryEvent; + import org.osmf.media.MediaFactory; + import org.osmf.media.URLResource; + + [Event(name="complete", type="flash.events.Event")] + + public class PluginsParser extends EventDispatcher + { + public function parse(pluginsList:XMLList, mediaFactory:MediaFactory):void + { + var pluginsToLoad:int = 0; + + if (mediaFactory == null) + { + onPluginResult(); + return; + } + else + { + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginResult); + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginResult); + } + + function onPluginResult(event:MediaFactoryEvent = null):void + { + pluginsToLoad--; + if (pluginsToLoad <= 0) + { + mediaFactory.removeEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginResult); + mediaFactory.removeEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginResult); + dispatchEvent(new Event(Event.COMPLETE)); + } + } + + for each (var plugin:XML in pluginsList) + { + mediaFactory.loadPlugin(new URLResource(plugin.@url)); + } + + onPluginResult(); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/WidgetsParser.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/WidgetsParser.as index 113fcaa..2450435 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/WidgetsParser.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/configuration/WidgetsParser.as @@ -1,173 +1,173 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.configuration -{ - import __AS3__.vec.Vector; - - import flash.utils.getDefinitionByName; - - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.widgets.*; - - public class WidgetsParser - { - public function addType(id:String, type:Class):void - { - widgetTypes[id.toLowerCase()] = type; - } - - public function get widgets():Vector. - { - return _widgets; - } - - public function registerWidgetType(type:String, definition:Class):void - { - widgetTypes[type] = definition; - } - - public function parse(widgetsList:XMLList, assetsManager:AssetsManager, parentWidget:Widget = null):void - { - if (parentWidget == null) - { - _siblings = new Vector.(); - _widgets = new Vector.(); - } - - for each (var widgetXML:XML in widgetsList) - { - var widget:Widget = constructWidget(widgetXML, assetsManager); - if (parentWidget != null) - { - _siblings.push(widget); - parentWidget.addChildWidget(widget); - } - else - { - _widgets.push(widget); - } - } - } - - public function getWidget(id:String):Widget - { - var result:Widget; - - if (id != null) - { - var lowerCaseId:String = id.toLocaleLowerCase(); - var widget:Widget; - - if (_widgets != null) - { - for each (widget in _widgets) - { - if (widget.id && widget.id.toLocaleLowerCase() == lowerCaseId) - { - result = widget; - break; - } - } - } - - if (result == null && _siblings != null) - { - for each (widget in _siblings) - { - if (widget.id && widget.id.toLocaleLowerCase() == lowerCaseId) - { - result = widget; - break; - } - } - } - } - - return result; - } - - // Internals - // - - private static const widgetTypes:Object - = { alert: AlertDialog - , button: ButtonWidget - , pinupbutton: PinUpButton - , pindownbutton: PinDownButton - , qualitymodetoggle: QualityModeToggle - , qualitydecreasebutton: QualityDecreaseButton - , qualityincreasebutton: QualityIncreaseButton - , qualitylabel: QualityLabel - , recordbutton: RecordButton - , livebutton: LiveButton - , ejectbutton: EjectButton - , playbutton: PlayButton - , pausebutton: PauseButton - , stopbutton: StopButton - , soundmorebutton: SoundMoreButton - , soundlessbutton: SoundLessButton - , scrubbar: ScrubBar - , fullscreenenterbutton: FullScreenEnterButton - , fullscreenleavebutton: FullScreenLeaveButton - , contextmenuoverlay: ContextMenuOverlay - , autohidewidget: AutoHideWidget - , urlinput: URLInput - , authenticationdialog: AuthenticationDialog - , label: LabelWidget - , metadatalabel: MetadataLabel - }; - - private var _widgets:Vector.; - private var _siblings:Vector.; - - private function constructWidget(xml:XML, assetsManager:AssetsManager):Widget - { - var typeString:String = String(xml.@type == undefined ? "" : xml.@type).toLowerCase(); - var type:Class = widgetTypes[typeString] - if (type == null) - { - try - { - type = flash.utils.getDefinitionByName(xml.@type || "") as Class; - } - catch(error:Error) - { - if (xml.@type != undefined) - { - trace("WARNING: type not found", xml.@type); - } - type = Widget; - } - } - var widget:Widget = new type(); - - // Parse child widgets: - parse(xml.widget, assetsManager, widget); - - // Configure widget: - widget.configure(xml, assetsManager); - - return widget; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.configuration +{ + import __AS3__.vec.Vector; + + import flash.utils.getDefinitionByName; + + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.widgets.*; + + public class WidgetsParser + { + public function addType(id:String, type:Class):void + { + widgetTypes[id.toLowerCase()] = type; + } + + public function get widgets():Vector. + { + return _widgets; + } + + public function registerWidgetType(type:String, definition:Class):void + { + widgetTypes[type] = definition; + } + + public function parse(widgetsList:XMLList, assetsManager:AssetsManager, parentWidget:Widget = null):void + { + if (parentWidget == null) + { + _siblings = new Vector.(); + _widgets = new Vector.(); + } + + for each (var widgetXML:XML in widgetsList) + { + var widget:Widget = constructWidget(widgetXML, assetsManager); + if (parentWidget != null) + { + _siblings.push(widget); + parentWidget.addChildWidget(widget); + } + else + { + _widgets.push(widget); + } + } + } + + public function getWidget(id:String):Widget + { + var result:Widget; + + if (id != null) + { + var lowerCaseId:String = id.toLocaleLowerCase(); + var widget:Widget; + + if (_widgets != null) + { + for each (widget in _widgets) + { + if (widget.id && widget.id.toLocaleLowerCase() == lowerCaseId) + { + result = widget; + break; + } + } + } + + if (result == null && _siblings != null) + { + for each (widget in _siblings) + { + if (widget.id && widget.id.toLocaleLowerCase() == lowerCaseId) + { + result = widget; + break; + } + } + } + } + + return result; + } + + // Internals + // + + private static const widgetTypes:Object + = { alert: AlertDialog + , button: ButtonWidget + , pinupbutton: PinUpButton + , pindownbutton: PinDownButton + , qualitymodetoggle: QualityModeToggle + , qualitydecreasebutton: QualityDecreaseButton + , qualityincreasebutton: QualityIncreaseButton + , qualitylabel: QualityLabel + , recordbutton: RecordButton + , livebutton: LiveButton + , ejectbutton: EjectButton + , playbutton: PlayButton + , pausebutton: PauseButton + , stopbutton: StopButton + , soundmorebutton: SoundMoreButton + , soundlessbutton: SoundLessButton + , scrubbar: ScrubBar + , fullscreenenterbutton: FullScreenEnterButton + , fullscreenleavebutton: FullScreenLeaveButton + , contextmenuoverlay: ContextMenuOverlay + , autohidewidget: AutoHideWidget + , urlinput: URLInput + , authenticationdialog: AuthenticationDialog + , label: LabelWidget + , metadatalabel: MetadataLabel + }; + + private var _widgets:Vector.; + private var _siblings:Vector.; + + private function constructWidget(xml:XML, assetsManager:AssetsManager):Widget + { + var typeString:String = String(xml.@type == undefined ? "" : xml.@type).toLowerCase(); + var type:Class = widgetTypes[typeString] + if (type == null) + { + try + { + type = flash.utils.getDefinitionByName(xml.@type || "") as Class; + } + catch(error:Error) + { + if (xml.@type != undefined) + { + trace("WARNING: type not found", xml.@type); + } + type = Widget; + } + } + var widget:Widget = new type(); + + // Parse child widgets: + parse(xml.widget, assetsManager, widget); + + // Configure widget: + widget.configure(xml, assetsManager); + + return widget; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/debug/FPSMeter.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/debug/FPSMeter.as index 5977f36..3dfaef1 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/debug/FPSMeter.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/debug/FPSMeter.as @@ -1,57 +1,57 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.debug -{ - import flash.events.Event; - import flash.utils.getTimer; - - import org.osmf.chrome.widgets.LabelWidget; - - public class FPSMeter extends LabelWidget - { - public function FPSMeter() - { - super(); - - ticks = getTimer(); - frames = 0; - addEventListener(Event.ENTER_FRAME, onEnterFrame); - } - - private function onEnterFrame(event:Event):void - { - frames++; - var currentTicks:uint = getTimer(); - if (currentTicks - ticks > 1000) - { - text = (frames / ((currentTicks - ticks) / 1000)).toFixed(3) + " Flash frames/sec."; - frames = 0; - ticks = currentTicks; - } - } - - private var frames:uint; - private var ticks:uint; - private var timer:uint; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.debug +{ + import flash.events.Event; + import flash.utils.getTimer; + + import org.osmf.chrome.widgets.LabelWidget; + + public class FPSMeter extends LabelWidget + { + public function FPSMeter() + { + super(); + + ticks = getTimer(); + frames = 0; + addEventListener(Event.ENTER_FRAME, onEnterFrame); + } + + private function onEnterFrame(event:Event):void + { + frames++; + var currentTicks:uint = getTimer(); + if (currentTicks - ticks > 1000) + { + text = (frames / ((currentTicks - ticks) / 1000)).toFixed(3) + " Flash frames/sec."; + frames = 0; + ticks = currentTicks; + } + } + + private var frames:uint; + private var ticks:uint; + private var timer:uint; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/debug/MemoryMeter.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/debug/MemoryMeter.as index 0ac4f5d..24c1d40 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/debug/MemoryMeter.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/debug/MemoryMeter.as @@ -1,44 +1,44 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.debug -{ - import flash.events.Event; - import flash.system.System; - - import org.osmf.chrome.widgets.LabelWidget; - - public class MemoryMeter extends LabelWidget - { - public function MemoryMeter() - { - super(); - - this.addEventListener(Event.ENTER_FRAME, onEnterFrame); - } - - private function onEnterFrame(event:Event):void - { - text = (System.totalMemory / (1024 * 1024)).toFixed(3) + " mb."; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.debug +{ + import flash.events.Event; + import flash.system.System; + + import org.osmf.chrome.widgets.LabelWidget; + + public class MemoryMeter extends LabelWidget + { + public function MemoryMeter() + { + super(); + + this.addEventListener(Event.ENTER_FRAME, onEnterFrame); + } + + private function onEnterFrame(event:Event):void + { + text = (System.totalMemory / (1024 * 1024)).toFixed(3) + " mb."; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/events/ScrubberEvent.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/events/ScrubberEvent.as index 2fb07ac..952f1fb 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/events/ScrubberEvent.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/events/ScrubberEvent.as @@ -1,39 +1,39 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.events -{ - import flash.events.Event; - - public class ScrubberEvent extends Event - { - public static const SCRUB_START:String = "scrubStart"; - public static const SCRUB_UPDATE:String = "scrubUpdate"; - public static const SCRUB_END:String = "scrubEnd"; - - public function ScrubberEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) - { - super(type, bubbles, cancelable); - } - - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.events +{ + import flash.events.Event; + + public class ScrubberEvent extends Event + { + public static const SCRUB_START:String = "scrubStart"; + public static const SCRUB_UPDATE:String = "scrubUpdate"; + public static const SCRUB_END:String = "scrubEnd"; + + public function ScrubberEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) + { + super(type, bubbles, cancelable); + } + + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/hint/Hint.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/hint/Hint.as index 06761c9..4a463ef 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/hint/Hint.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/hint/Hint.as @@ -1,169 +1,169 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.hint -{ - import flash.display.Stage; - import flash.errors.IllegalOperationError; - import flash.events.MouseEvent; - import flash.events.TimerEvent; - import flash.text.TextField; - import flash.text.TextFieldAutoSize; - import flash.utils.Timer; - - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.assets.FontAsset; - import org.osmf.chrome.widgets.FadingLayoutTargetSprite; - - public class Hint - { - public function Hint(lock:Class, assetManager:AssetsManager) - { - if (lock != ConstructorLock) - { - throw new IllegalOperationError("Hint is a singleton. Please use the getInstance method"); - } - - view = new FadingLayoutTargetSprite(); - view.fadeSteps = 10; - view.mouseChildren = false; - view.mouseEnabled = false; - - var fontAsset:FontAsset - = ( assetManager.getAsset("hintFont") - || assetManager.getAsset("defaultFont") - ) as FontAsset; - - label = new TextField(); - label.embedFonts = true; - label.defaultTextFormat = fontAsset.format; - label.height = 12; - label.multiline = true; - label.wordWrap = true; - label.width = 100; - label.alpha = 0.8; - label.autoSize = TextFieldAutoSize.LEFT; - label.background = true; - label.backgroundColor = 0; - - view.addChild(label); - } - - public static function getInstance(stage:Stage, assetManager:AssetsManager):Hint - { - if (stage == null) - { - throw new ArgumentError("Stage cannot be null"); - } - - if (_instance == null) - { - _instance = new Hint(ConstructorLock, assetManager); - _instance.stage = stage; - stage.addEventListener(MouseEvent.MOUSE_MOVE, _instance.onStageMouseMove); - } - - return _instance; - } - - - public function set text(value:String):void - { - if (value != _text) - { - if (openingTimer != null) - { - openingTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onOpeningTimerComplete); - openingTimer.stop(); - openingTimer = null; - } - - if (stage.contains(view)) - { - stage.removeChild(view); - } - - _text = value; - label.text = _text || ""; - - if (value != null && value != "") - { - openingTimer = new Timer(OPENING_DELAY, 1); - openingTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onOpeningTimerComplete); - openingTimer.start(); - } - - view.measure(); - } - } - - public function get text():String - { - return _text; - } - - // Internals - // - - private static var _instance:Hint; - private static const OPENING_DELAY:Number = 1200; - - private var stage:Stage; - private var view:FadingLayoutTargetSprite; - private var _text:String; - private var label:TextField; - - private var openingTimer:Timer; - - private function onStageMouseMove(event:MouseEvent):void - { - if (_text != null && _text != "") - { - if (openingTimer && openingTimer.running) - { - openingTimer.reset(); - openingTimer.start(); - } - else - { - text = null; - } - } - } - - private function onOpeningTimerComplete(event:TimerEvent):void - { - openingTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onOpeningTimerComplete); - openingTimer.stop(); - openingTimer = null; - - stage.addChild(view); - view.x = stage.mouseX - 13; - view.y = stage.mouseY - view.height - 2; - } - - } -} - -class ConstructorLock -{ +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.hint +{ + import flash.display.Stage; + import flash.errors.IllegalOperationError; + import flash.events.MouseEvent; + import flash.events.TimerEvent; + import flash.text.TextField; + import flash.text.TextFieldAutoSize; + import flash.utils.Timer; + + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.assets.FontAsset; + import org.osmf.chrome.widgets.FadingLayoutTargetSprite; + + public class Hint + { + public function Hint(lock:Class, assetManager:AssetsManager) + { + if (lock != ConstructorLock) + { + throw new IllegalOperationError("Hint is a singleton. Please use the getInstance method"); + } + + view = new FadingLayoutTargetSprite(); + view.fadeSteps = 10; + view.mouseChildren = false; + view.mouseEnabled = false; + + var fontAsset:FontAsset + = ( assetManager.getAsset("hintFont") + || assetManager.getAsset("defaultFont") + ) as FontAsset; + + label = new TextField(); + label.embedFonts = true; + label.defaultTextFormat = fontAsset.format; + label.height = 12; + label.multiline = true; + label.wordWrap = true; + label.width = 100; + label.alpha = 0.8; + label.autoSize = TextFieldAutoSize.LEFT; + label.background = true; + label.backgroundColor = 0; + + view.addChild(label); + } + + public static function getInstance(stage:Stage, assetManager:AssetsManager):Hint + { + if (stage == null) + { + throw new ArgumentError("Stage cannot be null"); + } + + if (_instance == null) + { + _instance = new Hint(ConstructorLock, assetManager); + _instance.stage = stage; + stage.addEventListener(MouseEvent.MOUSE_MOVE, _instance.onStageMouseMove); + } + + return _instance; + } + + + public function set text(value:String):void + { + if (value != _text) + { + if (openingTimer != null) + { + openingTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onOpeningTimerComplete); + openingTimer.stop(); + openingTimer = null; + } + + if (stage.contains(view)) + { + stage.removeChild(view); + } + + _text = value; + label.text = _text || ""; + + if (value != null && value != "") + { + openingTimer = new Timer(OPENING_DELAY, 1); + openingTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onOpeningTimerComplete); + openingTimer.start(); + } + + view.measure(); + } + } + + public function get text():String + { + return _text; + } + + // Internals + // + + private static var _instance:Hint; + private static const OPENING_DELAY:Number = 1200; + + private var stage:Stage; + private var view:FadingLayoutTargetSprite; + private var _text:String; + private var label:TextField; + + private var openingTimer:Timer; + + private function onStageMouseMove(event:MouseEvent):void + { + if (_text != null && _text != "") + { + if (openingTimer && openingTimer.running) + { + openingTimer.reset(); + openingTimer.start(); + } + else + { + text = null; + } + } + } + + private function onOpeningTimerComplete(event:TimerEvent):void + { + openingTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onOpeningTimerComplete); + openingTimer.stop(); + openingTimer = null; + + stage.addChild(view); + view.x = stage.mouseX - 13; + view.y = stage.mouseY - view.height - 2; + } + + } +} + +class ConstructorLock +{ } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/metadata/ChromeMetadata.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/metadata/ChromeMetadata.as index 2088809..1d6f3b8 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/metadata/ChromeMetadata.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/metadata/ChromeMetadata.as @@ -1,12 +1,12 @@ -package org.osmf.chrome.metadata -{ - import org.osmf.metadata.Metadata; - - public class ChromeMetadata - { - public static const CHROME_METADATA_KEY:String = "http://www.osmf.org.chrome/1.0" - - public static const AUTO_HIDE:String = "autoHide"; - public static const FULLSCREEN_BUTTON_STATE:String = "fullScreen"; - } +package org.osmf.chrome.metadata +{ + import org.osmf.metadata.Metadata; + + public class ChromeMetadata + { + public static const CHROME_METADATA_KEY:String = "http://www.osmf.org.chrome/1.0" + + public static const AUTO_HIDE:String = "autoHide"; + public static const FULLSCREEN_BUTTON_STATE:String = "fullScreen"; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AlertDialog.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AlertDialog.as index 5c90057..e4084a2 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AlertDialog.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AlertDialog.as @@ -1,110 +1,110 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.events.MouseEvent; - - import org.osmf.chrome.assets.AssetsManager; - - public class AlertDialog extends Widget - { - // Overrides - // - - public function AlertDialog() - { - super(); - } - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - queue = new Vector.; - update(); - - super.configure(xml, assetManager); - - closeButton = getChildWidget("closeButton") as ButtonWidget; - closeButton.addEventListener(MouseEvent.CLICK,onCloseButtonClick); - - captionLabel = getChildWidget("captionLabel") as LabelWidget; - messageLabel = getChildWidget("messageLabel") as LabelWidget; - } - - public function alert(caption:String, message:String):void - { - var alert:Object = {caption: caption, message:message}; - if (currentAlert != null) - { - queue.unshift(alert); - } - else - { - currentAlert = alert; - } - - update(); - } - - public function close(all:Boolean=true):void - { - if (all) - { - queue = new Vector.; - } - onCloseButtonClick(); - } - - // Internals - // - - private var closeButton:ButtonWidget; - private var captionLabel:LabelWidget; - private var messageLabel:LabelWidget; - - private var queue:Vector.; - private var currentAlert:Object; - - private function onCloseButtonClick(event:MouseEvent=null):void - { - currentAlert = queue.length ? queue.pop() : null; - - update(); - } - - private function update():void - { - if (currentAlert == null) - { - visible = false; - } - else - { - captionLabel.text = currentAlert.caption; - messageLabel.text = currentAlert.message; - - visible = true; - } - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.events.MouseEvent; + + import org.osmf.chrome.assets.AssetsManager; + + public class AlertDialog extends Widget + { + // Overrides + // + + public function AlertDialog() + { + super(); + } + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + queue = new Vector.; + update(); + + super.configure(xml, assetManager); + + closeButton = getChildWidget("closeButton") as ButtonWidget; + closeButton.addEventListener(MouseEvent.CLICK,onCloseButtonClick); + + captionLabel = getChildWidget("captionLabel") as LabelWidget; + messageLabel = getChildWidget("messageLabel") as LabelWidget; + } + + public function alert(caption:String, message:String):void + { + var alert:Object = {caption: caption, message:message}; + if (currentAlert != null) + { + queue.unshift(alert); + } + else + { + currentAlert = alert; + } + + update(); + } + + public function close(all:Boolean=true):void + { + if (all) + { + queue = new Vector.; + } + onCloseButtonClick(); + } + + // Internals + // + + private var closeButton:ButtonWidget; + private var captionLabel:LabelWidget; + private var messageLabel:LabelWidget; + + private var queue:Vector.; + private var currentAlert:Object; + + private function onCloseButtonClick(event:MouseEvent=null):void + { + currentAlert = queue.length ? queue.pop() : null; + + update(); + } + + private function update():void + { + if (currentAlert == null) + { + visible = false; + } + else + { + captionLabel.text = currentAlert.caption; + messageLabel.text = currentAlert.message; + + visible = true; + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AuthenticationDialog.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AuthenticationDialog.as index b41175a..07a4914 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AuthenticationDialog.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AuthenticationDialog.as @@ -1,150 +1,150 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.MouseEvent; - - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.events.DRMEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.DRMState; - import org.osmf.traits.DRMTrait; - import org.osmf.traits.MediaTraitType; - - public class AuthenticationDialog extends Widget - { - // Overrides - // - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - super.configure(xml, assetManager); - - submit = getChildWidget("submitButton") as ButtonWidget; - submit.addEventListener(MouseEvent.CLICK, onSubmitClick); - - cancel = getChildWidget("cancelButton") as ButtonWidget; - cancel.addEventListener(MouseEvent.CLICK, onCancelClick); - - userName = getChildWidget("username") as LabelWidget; - password = getChildWidget("password") as LabelWidget; - - _open = false; - updateVisibility(); - } - - // Internals - // - - private static const OFFSET_X:Number = 10; - - private var userName:LabelWidget; - private var password:LabelWidget; - private var submit:ButtonWidget; - private var cancel:ButtonWidget; - - private var _open:Boolean; - - private function onSubmitClick(event:MouseEvent):void - { - _open = false; - updateVisibility(); - - authenticating = true; - drm.authenticate(userName.text, password.text); - } - - private function onCancelClick(event:MouseEvent):void - { - _open = false; - updateVisibility(); - } - - private function updateVisibility():void - { - visible = _open; - } - - // Overrides - // - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - drm = element.getTrait(MediaTraitType.DRM) as DRMTrait; - drm.addEventListener(DRMEvent.DRM_STATE_CHANGE, onDRMStateChange); - - onDRMStateChange(); - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - if (drm) - { - drm.removeEventListener(DRMEvent.DRM_STATE_CHANGE, onDRMStateChange); - drm = null; - authenticating = false; - } - - updateVisibility(); - } - - // Internals - // - - private var drm:DRMTrait; - private var authenticating:Boolean; - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.DRM; - - private function onDRMStateChange(event:DRMEvent=null):void - { - if (drm) - { - _open = drm.drmState == DRMState.AUTHENTICATION_NEEDED; - if (_open == false && authenticating == true) - { - if (drm.drmState == DRMState.AUTHENTICATION_COMPLETE) - { - authenticating = false; - } - else if (drm.drmState == DRMState.AUTHENTICATION_ERROR) - { - authenticating = false; - _open = true; - } - } - } - else - { - _open = false; - } - updateVisibility(); - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.MouseEvent; + + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.events.DRMEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.DRMState; + import org.osmf.traits.DRMTrait; + import org.osmf.traits.MediaTraitType; + + public class AuthenticationDialog extends Widget + { + // Overrides + // + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + super.configure(xml, assetManager); + + submit = getChildWidget("submitButton") as ButtonWidget; + submit.addEventListener(MouseEvent.CLICK, onSubmitClick); + + cancel = getChildWidget("cancelButton") as ButtonWidget; + cancel.addEventListener(MouseEvent.CLICK, onCancelClick); + + userName = getChildWidget("username") as LabelWidget; + password = getChildWidget("password") as LabelWidget; + + _open = false; + updateVisibility(); + } + + // Internals + // + + private static const OFFSET_X:Number = 10; + + private var userName:LabelWidget; + private var password:LabelWidget; + private var submit:ButtonWidget; + private var cancel:ButtonWidget; + + private var _open:Boolean; + + private function onSubmitClick(event:MouseEvent):void + { + _open = false; + updateVisibility(); + + authenticating = true; + drm.authenticate(userName.text, password.text); + } + + private function onCancelClick(event:MouseEvent):void + { + _open = false; + updateVisibility(); + } + + private function updateVisibility():void + { + visible = _open; + } + + // Overrides + // + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + drm = element.getTrait(MediaTraitType.DRM) as DRMTrait; + drm.addEventListener(DRMEvent.DRM_STATE_CHANGE, onDRMStateChange); + + onDRMStateChange(); + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + if (drm) + { + drm.removeEventListener(DRMEvent.DRM_STATE_CHANGE, onDRMStateChange); + drm = null; + authenticating = false; + } + + updateVisibility(); + } + + // Internals + // + + private var drm:DRMTrait; + private var authenticating:Boolean; + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.DRM; + + private function onDRMStateChange(event:DRMEvent=null):void + { + if (drm) + { + _open = drm.drmState == DRMState.AUTHENTICATION_NEEDED; + if (_open == false && authenticating == true) + { + if (drm.drmState == DRMState.AUTHENTICATION_COMPLETE) + { + authenticating = false; + } + else if (drm.drmState == DRMState.AUTHENTICATION_ERROR) + { + authenticating = false; + _open = true; + } + } + } + else + { + _open = false; + } + updateVisibility(); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AutoHideWidget.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AutoHideWidget.as index 56a0781..d556612 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AutoHideWidget.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/AutoHideWidget.as @@ -1,99 +1,99 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.Event; - import flash.events.MouseEvent; - - import org.osmf.chrome.metadata.ChromeMetadata; - import org.osmf.media.MediaElement; - import org.osmf.metadata.MetadataWatcher; - - public class AutoHideWidget extends Widget - { - public function AutoHideWidget() - { - super(); - - addEventListener(Event.ADDED_TO_STAGE, onFirstAddedToStage); - } - - // Overrides - // - - override protected function processMediaElementChange(oldElement:MediaElement):void - { - if (autoHideWatcher) - { - autoHideWatcher.unwatch(); - autoHideWatcher = null; - } - - if (media != null) - { - autoHideWatcher - = new MetadataWatcher - ( media.metadata - , ChromeMetadata.CHROME_METADATA_KEY - , ChromeMetadata.AUTO_HIDE - , autoHideChangeCallback - ); - autoHideWatcher.watch(); - } - else - { - visible = true; - } - } - - private function onFirstAddedToStage(event:Event):void - { - removeEventListener(Event.ADDED_TO_STAGE, onFirstAddedToStage); - - stage.addEventListener(MouseEvent.MOUSE_OVER, onStageMouseOver); - stage.addEventListener(MouseEvent.MOUSE_OUT, onStageMouseOut); - } - - private function onStageMouseOver(event:MouseEvent):void - { - mouseOver = true; - visible = _autoHide ? mouseOver : true; - } - - private function onStageMouseOut(event:MouseEvent):void - { - mouseOver = false; - visible = _autoHide ? mouseOver : true; - } - - private function autoHideChangeCallback(value:Boolean):void - { - _autoHide = value; - visible = _autoHide ? mouseOver : true; - } - - private var autoHideWatcher:MetadataWatcher; - private var _autoHide:Boolean; - private var mouseOver:Boolean; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.Event; + import flash.events.MouseEvent; + + import org.osmf.chrome.metadata.ChromeMetadata; + import org.osmf.media.MediaElement; + import org.osmf.metadata.MetadataWatcher; + + public class AutoHideWidget extends Widget + { + public function AutoHideWidget() + { + super(); + + addEventListener(Event.ADDED_TO_STAGE, onFirstAddedToStage); + } + + // Overrides + // + + override protected function processMediaElementChange(oldElement:MediaElement):void + { + if (autoHideWatcher) + { + autoHideWatcher.unwatch(); + autoHideWatcher = null; + } + + if (media != null) + { + autoHideWatcher + = new MetadataWatcher + ( media.metadata + , ChromeMetadata.CHROME_METADATA_KEY + , ChromeMetadata.AUTO_HIDE + , autoHideChangeCallback + ); + autoHideWatcher.watch(); + } + else + { + visible = true; + } + } + + private function onFirstAddedToStage(event:Event):void + { + removeEventListener(Event.ADDED_TO_STAGE, onFirstAddedToStage); + + stage.addEventListener(MouseEvent.MOUSE_OVER, onStageMouseOver); + stage.addEventListener(MouseEvent.MOUSE_OUT, onStageMouseOut); + } + + private function onStageMouseOver(event:MouseEvent):void + { + mouseOver = true; + visible = _autoHide ? mouseOver : true; + } + + private function onStageMouseOut(event:MouseEvent):void + { + mouseOver = false; + visible = _autoHide ? mouseOver : true; + } + + private function autoHideChangeCallback(value:Boolean):void + { + _autoHide = value; + visible = _autoHide ? mouseOver : true; + } + + private var autoHideWatcher:MetadataWatcher; + private var _autoHide:Boolean; + private var mouseOver:Boolean; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ButtonWidget.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ButtonWidget.as index 5bbfed6..d90b901 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ButtonWidget.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ButtonWidget.as @@ -1,128 +1,128 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.display.DisplayObject; - import flash.events.MouseEvent; - - import org.osmf.chrome.assets.Asset; - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.assets.DisplayObjectAsset; - - public class ButtonWidget extends Widget - { - public function ButtonWidget() - { - mouseEnabled = true; - - addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); - addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); - addEventListener(MouseEvent.CLICK, onMouseClick_internal); - } - - // Overrides - // - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - up = assetManager.getDisplayObject(xml.@upFace); - down = assetManager.getDisplayObject(xml.@downFace); - disabled = assetManager.getDisplayObject(xml.@disabledFace); - - super.configure(xml, assetManager); - } - - // Internals - // - - private function onMouseOver(event:MouseEvent):void - { - mouseOver = true; - setFace(enabled ? down : disabled); - } - - private function onMouseOut(event:MouseEvent):void - { - mouseOver = false; - setFace(enabled ? up : disabled); - } - - private function setFace(face:DisplayObject):void - { - if (currentFace != face) - { - if (currentFace != null) - { - removeChild(currentFace); - } - - currentFace = face; - - if (currentFace != null) - { - addChildAt(currentFace, 0); - - width = currentFace.width; - height = currentFace.height; - } - } - } - - private function onMouseClick_internal(event:MouseEvent):void - { - if (enabled == false) - { - event.stopImmediatePropagation(); - } - else - { - onMouseClick(event); - } - } - - // Overrides - // - - override protected function processEnabledChange():void - { - setFace(enabled ? mouseOver ? down : up : disabled); - - super.processEnabledChange(); - } - - // Stubs - // - - protected function onMouseClick(event:MouseEvent):void - { - } - - protected var currentFace:DisplayObject; - protected var mouseOver:Boolean; - - protected var up:DisplayObject; - protected var down:DisplayObject; - protected var disabled:DisplayObject; - - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.display.DisplayObject; + import flash.events.MouseEvent; + + import org.osmf.chrome.assets.Asset; + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.assets.DisplayObjectAsset; + + public class ButtonWidget extends Widget + { + public function ButtonWidget() + { + mouseEnabled = true; + + addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); + addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); + addEventListener(MouseEvent.CLICK, onMouseClick_internal); + } + + // Overrides + // + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + up = assetManager.getDisplayObject(xml.@upFace); + down = assetManager.getDisplayObject(xml.@downFace); + disabled = assetManager.getDisplayObject(xml.@disabledFace); + + super.configure(xml, assetManager); + } + + // Internals + // + + private function onMouseOver(event:MouseEvent):void + { + mouseOver = true; + setFace(enabled ? down : disabled); + } + + private function onMouseOut(event:MouseEvent):void + { + mouseOver = false; + setFace(enabled ? up : disabled); + } + + private function setFace(face:DisplayObject):void + { + if (currentFace != face) + { + if (currentFace != null) + { + removeChild(currentFace); + } + + currentFace = face; + + if (currentFace != null) + { + addChildAt(currentFace, 0); + + width = currentFace.width; + height = currentFace.height; + } + } + } + + private function onMouseClick_internal(event:MouseEvent):void + { + if (enabled == false) + { + event.stopImmediatePropagation(); + } + else + { + onMouseClick(event); + } + } + + // Overrides + // + + override protected function processEnabledChange():void + { + setFace(enabled ? mouseOver ? down : up : disabled); + + super.processEnabledChange(); + } + + // Stubs + // + + protected function onMouseClick(event:MouseEvent):void + { + } + + protected var currentFace:DisplayObject; + protected var mouseOver:Boolean; + + protected var up:DisplayObject; + protected var down:DisplayObject; + protected var disabled:DisplayObject; + + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ContextMenuOverlay.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ContextMenuOverlay.as index 2eaa027..178c929 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ContextMenuOverlay.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ContextMenuOverlay.as @@ -1,113 +1,113 @@ -package org.osmf.chrome.widgets -{ - import flash.events.ContextMenuEvent; - import flash.events.Event; - import flash.net.URLRequest; - import flash.net.navigateToURL; - import flash.system.Capabilities; - import flash.ui.ContextMenu; - import flash.ui.ContextMenuItem; - - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.utils.Version; - - public class ContextMenuOverlay extends Widget - { - public function ContextMenuOverlay() - { - super(); - - // Create a transparent overlay. This is a work-around for the - // context menu otherwise not triggering MENU_ITEM_SELECT when being - // invoked while over a Video object: - - graphics.beginFill(0, 0); - graphics.drawRect(0, 0, 100, 100); - graphics.endFill(); - } - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - super.configure(xml, assetManager); - - var customItems:Array = []; - - // Setup a context menu: - var customContextMenu:ContextMenu = new ContextMenu(); - customContextMenu.hideBuiltInItems(); - - var menuItem:ContextMenuItem - = new ContextMenuItem - ( String(parseAttribute(xml, "menuItemLabel", "")) - . replace("${version}", Version.version) - ); - menuItemLink = parseAttribute(xml, "menuItemLink", null); - menuItemWindow = parseAttribute(xml, "menuItemWindow", "_blank"); - - if (menuItemLink != null) - { - menuItem.addEventListener - ( ContextMenuEvent.MENU_ITEM_SELECT - , onContextMenuItemSelect - ); - } - - customItems.push(menuItem); - - if ( String(parseAttribute(xml, "addVersionDetails", "false")) - . toLocaleLowerCase() == "true" - ) - { - menuItem - = new ContextMenuItem - ( Capabilities.version - , false - , false - ); - customItems.push(menuItem); - - if (Version.FLASH_10_1 == true) - { - menuItem - = new ContextMenuItem - ( "FLASH_10_1" - , false - , false - ); - customItems.push(menuItem); - } - - if (Version.LOGGING == true) - { - menuItem - = new ContextMenuItem - ( "LOGGING" - , false - , false - ); - customItems.push(menuItem); - } - } - - customContextMenu.customItems = customItems; - contextMenu = customContextMenu; - - addEventListener(Event.ADDED_TO_STAGE, onFirstAddedToStage); - } - - private var menuItemLink:String; - private var menuItemWindow:String; - - private function onFirstAddedToStage(event:Event):void - { - removeEventListener(Event.ADDED_TO_STAGE, onFirstAddedToStage); - - parent.contextMenu = contextMenu; - } - - private function onContextMenuItemSelect(event:Event):void - { - navigateToURL(new URLRequest(menuItemLink), menuItemWindow); - } - } +package org.osmf.chrome.widgets +{ + import flash.events.ContextMenuEvent; + import flash.events.Event; + import flash.net.URLRequest; + import flash.net.navigateToURL; + import flash.system.Capabilities; + import flash.ui.ContextMenu; + import flash.ui.ContextMenuItem; + + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.utils.Version; + + public class ContextMenuOverlay extends Widget + { + public function ContextMenuOverlay() + { + super(); + + // Create a transparent overlay. This is a work-around for the + // context menu otherwise not triggering MENU_ITEM_SELECT when being + // invoked while over a Video object: + + graphics.beginFill(0, 0); + graphics.drawRect(0, 0, 100, 100); + graphics.endFill(); + } + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + super.configure(xml, assetManager); + + var customItems:Array = []; + + // Setup a context menu: + var customContextMenu:ContextMenu = new ContextMenu(); + customContextMenu.hideBuiltInItems(); + + var menuItem:ContextMenuItem + = new ContextMenuItem + ( String(parseAttribute(xml, "menuItemLabel", "")) + . replace("${version}", Version.version) + ); + menuItemLink = parseAttribute(xml, "menuItemLink", null); + menuItemWindow = parseAttribute(xml, "menuItemWindow", "_blank"); + + if (menuItemLink != null) + { + menuItem.addEventListener + ( ContextMenuEvent.MENU_ITEM_SELECT + , onContextMenuItemSelect + ); + } + + customItems.push(menuItem); + + if ( String(parseAttribute(xml, "addVersionDetails", "false")) + . toLocaleLowerCase() == "true" + ) + { + menuItem + = new ContextMenuItem + ( Capabilities.version + , false + , false + ); + customItems.push(menuItem); + + if (Version.FLASH_10_1 == true) + { + menuItem + = new ContextMenuItem + ( "FLASH_10_1" + , false + , false + ); + customItems.push(menuItem); + } + + if (Version.LOGGING == true) + { + menuItem + = new ContextMenuItem + ( "LOGGING" + , false + , false + ); + customItems.push(menuItem); + } + } + + customContextMenu.customItems = customItems; + contextMenu = customContextMenu; + + addEventListener(Event.ADDED_TO_STAGE, onFirstAddedToStage); + } + + private var menuItemLink:String; + private var menuItemWindow:String; + + private function onFirstAddedToStage(event:Event):void + { + removeEventListener(Event.ADDED_TO_STAGE, onFirstAddedToStage); + + parent.contextMenu = contextMenu; + } + + private function onContextMenuItemSelect(event:Event):void + { + navigateToURL(new URLRequest(menuItemLink), menuItemWindow); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/EjectButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/EjectButton.as index d5c41d3..cc47b94 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/EjectButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/EjectButton.as @@ -1,34 +1,34 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import org.osmf.media.MediaElement; - - public class EjectButton extends ButtonWidget - { - override protected function processMediaElementChange(oldElement:MediaElement):void - { - visible = media != null; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import org.osmf.media.MediaElement; + + public class EjectButton extends ButtonWidget + { + override protected function processMediaElementChange(oldElement:MediaElement):void + { + visible = media != null; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FadingLayoutTargetSprite.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FadingLayoutTargetSprite.as index 411b735..8d05283 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FadingLayoutTargetSprite.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FadingLayoutTargetSprite.as @@ -1,207 +1,207 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.Event; - - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutTargetSprite; - - public class FadingLayoutTargetSprite extends LayoutTargetSprite - { - // Public Interface - // - - public function FadingLayoutTargetSprite(layoutMetadata:LayoutMetadata=null) - { - super(layoutMetadata); - - _visible = super.visible; - _alpha = super.alpha; - } - - public function get fadeSteps():Number - { - return _fadeSteps; - } - - public function set fadeSteps(value:Number):void - { - if (_fadeSteps != value) - { - _fadeSteps = value; - - if (_fadeSteps <= 0) - { - setIdle(); - } - else - { - addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); - } - } - } - - // Overrides - // - - override public function set visible(value:Boolean):void - { - if (value != _visible) - { - _visible = value; - if (parent) - { - mode = _visible - ? MODE_IN - : MODE_OUT; - } - else - { - setIdle(); - } - } - } - - override public function get visible():Boolean - { - return _visible; - } - - override public function set alpha(value:Number):void - { - if (value != _alpha) - { - _alpha = value; - } - } - - override public function get alpha():Number - { - return _alpha; - } - - // Stubs - // - - protected function setSuperVisible(value:Boolean):void - { - super.visible = value; - } - - // Internals - // - - private static const MODE_IDLE:String = null; - private static const MODE_IN:String = "in"; - private static const MODE_OUT:String = "out"; - - private var _fadeSteps:Number = 15; - private var _visible:Boolean = true; - private var _alpha:Number; - private var _mode:String; - - private var remainingSteps:uint = 0; - - private function get mode():String - { - return _mode; - } - - private function set mode(value:String):void - { - if (value != _mode) - { - _mode = value; - var fadeRequired:Boolean - = _fadeSteps - && ( ( _mode == MODE_OUT - && super.alpha != 0 - && super.visible != false - ) - || ( _mode == MODE_IN - && super.alpha != _alpha - ) - ); - - if (fadeRequired) - { - if (remainingSteps <= 0) - { - remainingSteps = _fadeSteps; - } - else - { - remainingSteps = _fadeSteps - remainingSteps; - } - addEventListener(Event.ENTER_FRAME, onEnterFrame); - } - else - { - setIdle(); - } - } - } - - private function setIdle():void - { - removeEventListener(Event.ENTER_FRAME, onEnterFrame); - _mode = MODE_IDLE; - remainingSteps = 0; - super.alpha = _visible ? _alpha : 0; - setSuperVisible(_visible); - } - - private function onAddedToStage(event:Event):void - { - if (visible) - { - super.alpha = 0; - mode = MODE_IN; - } - } - - private function onEnterFrame(event:Event = null):void - { - if (remainingSteps <= 0) - { - setSuperVisible(_visible); - mode = MODE_IDLE; - } - else - { - remainingSteps--; - - if (mode == MODE_IN) - { - super.alpha = _alpha - (_alpha * remainingSteps / _fadeSteps); - setSuperVisible(true); - } - else if (mode == MODE_OUT) - { - super.alpha = _alpha * remainingSteps / _fadeSteps; - } - } - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.Event; + + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutTargetSprite; + + public class FadingLayoutTargetSprite extends LayoutTargetSprite + { + // Public Interface + // + + public function FadingLayoutTargetSprite(layoutMetadata:LayoutMetadata=null) + { + super(layoutMetadata); + + _visible = super.visible; + _alpha = super.alpha; + } + + public function get fadeSteps():Number + { + return _fadeSteps; + } + + public function set fadeSteps(value:Number):void + { + if (_fadeSteps != value) + { + _fadeSteps = value; + + if (_fadeSteps <= 0) + { + setIdle(); + } + else + { + addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); + } + } + } + + // Overrides + // + + override public function set visible(value:Boolean):void + { + if (value != _visible) + { + _visible = value; + if (parent) + { + mode = _visible + ? MODE_IN + : MODE_OUT; + } + else + { + setIdle(); + } + } + } + + override public function get visible():Boolean + { + return _visible; + } + + override public function set alpha(value:Number):void + { + if (value != _alpha) + { + _alpha = value; + } + } + + override public function get alpha():Number + { + return _alpha; + } + + // Stubs + // + + protected function setSuperVisible(value:Boolean):void + { + super.visible = value; + } + + // Internals + // + + private static const MODE_IDLE:String = null; + private static const MODE_IN:String = "in"; + private static const MODE_OUT:String = "out"; + + private var _fadeSteps:Number = 15; + private var _visible:Boolean = true; + private var _alpha:Number; + private var _mode:String; + + private var remainingSteps:uint = 0; + + private function get mode():String + { + return _mode; + } + + private function set mode(value:String):void + { + if (value != _mode) + { + _mode = value; + var fadeRequired:Boolean + = _fadeSteps + && ( ( _mode == MODE_OUT + && super.alpha != 0 + && super.visible != false + ) + || ( _mode == MODE_IN + && super.alpha != _alpha + ) + ); + + if (fadeRequired) + { + if (remainingSteps <= 0) + { + remainingSteps = _fadeSteps; + } + else + { + remainingSteps = _fadeSteps - remainingSteps; + } + addEventListener(Event.ENTER_FRAME, onEnterFrame); + } + else + { + setIdle(); + } + } + } + + private function setIdle():void + { + removeEventListener(Event.ENTER_FRAME, onEnterFrame); + _mode = MODE_IDLE; + remainingSteps = 0; + super.alpha = _visible ? _alpha : 0; + setSuperVisible(_visible); + } + + private function onAddedToStage(event:Event):void + { + if (visible) + { + super.alpha = 0; + mode = MODE_IN; + } + } + + private function onEnterFrame(event:Event = null):void + { + if (remainingSteps <= 0) + { + setSuperVisible(_visible); + mode = MODE_IDLE; + } + else + { + remainingSteps--; + + if (mode == MODE_IN) + { + super.alpha = _alpha - (_alpha * remainingSteps / _fadeSteps); + setSuperVisible(true); + } + else if (mode == MODE_OUT) + { + super.alpha = _alpha * remainingSteps / _fadeSteps; + } + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FullScreenEnterButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FullScreenEnterButton.as index cc30d9c..17d5c95 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FullScreenEnterButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FullScreenEnterButton.as @@ -1,87 +1,87 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.display.StageDisplayState; - import flash.events.Event; - import flash.events.FullScreenEvent; - import flash.events.MouseEvent; - - import org.osmf.chrome.widgets.ButtonWidget; - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - - public class FullScreenEnterButton extends ButtonWidget - { - public function FullScreenEnterButton() - { - addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); - } - - // Overrides - // - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - visible = false; - } - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - visible - = element != null - && stage != null - && stage.displayState == StageDisplayState.NORMAL; - } - - override protected function onMouseClick(event:MouseEvent):void - { - stage.displayState = StageDisplayState.FULL_SCREEN; - } - - // Internals - // - - private function onAddedToStage(event:Event):void - { - stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullScreenEvent); - processRequiredTraitsAvailable(media); - } - - private function onFullScreenEvent(event:FullScreenEvent):void - { - processRequiredTraitsAvailable(media); - } - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.DISPLAY_OBJECT; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.display.StageDisplayState; + import flash.events.Event; + import flash.events.FullScreenEvent; + import flash.events.MouseEvent; + + import org.osmf.chrome.widgets.ButtonWidget; + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + + public class FullScreenEnterButton extends ButtonWidget + { + public function FullScreenEnterButton() + { + addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); + } + + // Overrides + // + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + visible = false; + } + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + visible + = element != null + && stage != null + && stage.displayState == StageDisplayState.NORMAL; + } + + override protected function onMouseClick(event:MouseEvent):void + { + stage.displayState = StageDisplayState.FULL_SCREEN; + } + + // Internals + // + + private function onAddedToStage(event:Event):void + { + stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullScreenEvent); + processRequiredTraitsAvailable(media); + } + + private function onFullScreenEvent(event:FullScreenEvent):void + { + processRequiredTraitsAvailable(media); + } + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.DISPLAY_OBJECT; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FullScreenLeaveButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FullScreenLeaveButton.as index 8b945d7..b22901c 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FullScreenLeaveButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/FullScreenLeaveButton.as @@ -1,86 +1,86 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.display.StageDisplayState; - import flash.events.Event; - import flash.events.FullScreenEvent; - import flash.events.MouseEvent; - - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - - public class FullScreenLeaveButton extends ButtonWidget - { - public function FullScreenLeaveButton() - { - addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); - } - - // Overrides - // - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - visible = false; - } - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - visible - = element != null - && stage != null - && stage.displayState != StageDisplayState.NORMAL; - } - - override protected function onMouseClick(event:MouseEvent):void - { - stage.displayState = StageDisplayState.NORMAL; - } - - // Internals - // - - private function onAddedToStage(event:Event):void - { - stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullScreenEvent); - processRequiredTraitsAvailable(media); - } - - private function onFullScreenEvent(event:FullScreenEvent):void - { - processRequiredTraitsAvailable(media); - } - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.DISPLAY_OBJECT; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.display.StageDisplayState; + import flash.events.Event; + import flash.events.FullScreenEvent; + import flash.events.MouseEvent; + + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + + public class FullScreenLeaveButton extends ButtonWidget + { + public function FullScreenLeaveButton() + { + addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); + } + + // Overrides + // + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + visible = false; + } + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + visible + = element != null + && stage != null + && stage.displayState != StageDisplayState.NORMAL; + } + + override protected function onMouseClick(event:MouseEvent):void + { + stage.displayState = StageDisplayState.NORMAL; + } + + // Internals + // + + private function onAddedToStage(event:Event):void + { + stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullScreenEvent); + processRequiredTraitsAvailable(media); + } + + private function onFullScreenEvent(event:FullScreenEvent):void + { + processRequiredTraitsAvailable(media); + } + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.DISPLAY_OBJECT; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/LabelWidget.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/LabelWidget.as index 3e98bba..97fe8b0 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/LabelWidget.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/LabelWidget.as @@ -1,88 +1,88 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.text.TextField; - import flash.text.TextFieldType; - import flash.text.TextFormat; - - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.assets.FontAsset; - - public class LabelWidget extends Widget - { - public function LabelWidget() - { - textField = new TextField(); - addChild(textField); - - super(); - } - - public function get text():String - { - return textField.text; - } - - public function set text(value:String):void - { - textField.text = value; - } - - // Overrides - // - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - super.configure(xml, assetManager); - - var fontId:String = xml.@font || "defaultFont"; - var fontAsset:FontAsset = assetManager.getAsset(fontId) as FontAsset; - var format:TextFormat = fontAsset.format; - format.color = parseInt(xml.@textColor || format.color.toString()); - - textField.defaultTextFormat = format; - textField.embedFonts = true; - textField.type = String(parseAttribute(xml, "input", "false")).toLocaleLowerCase()=="true" ? TextFieldType.INPUT : TextFieldType.DYNAMIC; - textField.selectable = textField.type == TextFieldType.INPUT || String(parseAttribute(xml, "selectable", "false")).toLocaleLowerCase()=="true"; - textField.background = String(parseAttribute(xml, "background", "false")).toLocaleLowerCase()=="true"; - textField.displayAsPassword = String(parseAttribute(xml, "password", "false")).toLocaleLowerCase()=="true"; - textField.backgroundColor = Number(xml.@backgroundColor || NaN); - textField.alpha = Number(xml.@textAlpha) || 1; - textField.text = xml.@text; - textField.multiline = String(parseAttribute(xml, "multiline", "false")).toLocaleLowerCase()=="true"; - textField.wordWrap = textField.multiline; - } - - override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void - { - textField.width = availableWidth; - textField.height = availableHeight; - } - - // Internals - // - - private var textField:TextField; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.text.TextField; + import flash.text.TextFieldType; + import flash.text.TextFormat; + + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.assets.FontAsset; + + public class LabelWidget extends Widget + { + public function LabelWidget() + { + textField = new TextField(); + addChild(textField); + + super(); + } + + public function get text():String + { + return textField.text; + } + + public function set text(value:String):void + { + textField.text = value; + } + + // Overrides + // + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + super.configure(xml, assetManager); + + var fontId:String = xml.@font || "defaultFont"; + var fontAsset:FontAsset = assetManager.getAsset(fontId) as FontAsset; + var format:TextFormat = fontAsset.format; + format.color = parseInt(xml.@textColor || format.color.toString()); + + textField.defaultTextFormat = format; + textField.embedFonts = true; + textField.type = String(parseAttribute(xml, "input", "false")).toLocaleLowerCase()=="true" ? TextFieldType.INPUT : TextFieldType.DYNAMIC; + textField.selectable = textField.type == TextFieldType.INPUT || String(parseAttribute(xml, "selectable", "false")).toLocaleLowerCase()=="true"; + textField.background = String(parseAttribute(xml, "background", "false")).toLocaleLowerCase()=="true"; + textField.displayAsPassword = String(parseAttribute(xml, "password", "false")).toLocaleLowerCase()=="true"; + textField.backgroundColor = Number(xml.@backgroundColor || NaN); + textField.alpha = Number(xml.@textAlpha) || 1; + textField.text = xml.@text; + textField.multiline = String(parseAttribute(xml, "multiline", "false")).toLocaleLowerCase()=="true"; + textField.wordWrap = textField.multiline; + } + + override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void + { + textField.width = availableWidth; + textField.height = availableHeight; + } + + // Internals + // + + private var textField:TextField; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/LiveButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/LiveButton.as index b07822e..e4535a2 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/LiveButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/LiveButton.as @@ -1,107 +1,107 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.Event; - - import org.osmf.chrome.widgets.ButtonWidget; - import org.osmf.events.DVREvent; - import org.osmf.events.TimeEvent; - import org.osmf.media.MediaElement; - import org.osmf.net.NetStreamLoadTrait; - import org.osmf.traits.DVRTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.TimeTrait; - - public class LiveButton extends ButtonWidget - { - // Overrides - // - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - dvrTrait = element.getTrait(MediaTraitType.DVR) as DVRTrait; - dvrTrait.addEventListener(DVREvent.IS_RECORDING_CHANGE, visibilityDeterminingEventHandler); - - timeTrait = element.getTrait(MediaTraitType.TIME) as TimeTrait; - timeTrait.addEventListener(TimeEvent.DURATION_CHANGE, visibilityDeterminingEventHandler); - - visibilityDeterminingEventHandler(); - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - if (dvrTrait) - { - dvrTrait.removeEventListener(DVREvent.IS_RECORDING_CHANGE, visibilityDeterminingEventHandler); - dvrTrait = null; - } - - if (timeTrait) - { - timeTrait.removeEventListener(TimeEvent.DURATION_CHANGE, visibilityDeterminingEventHandler); - timeTrait = null; - } - - visibilityDeterminingEventHandler(); - } - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - // Internals - // - - private function visibilityDeterminingEventHandler(event:Event = null):void - { - visible - = dvrTrait != null - && dvrTrait.isRecording == true - && timeTrait - && timeTrait.currentTime >= Math.max(0, timeTrait.duration - getBufferTime() - 5); - } - - private function getBufferTime():Number - { - var result:Number = 0; - - var loadable:NetStreamLoadTrait = media.getTrait(MediaTraitType.LOAD) as NetStreamLoadTrait; - if (loadable) - { - result = loadable.netStream.bufferTime; - } - - return result; - } - - private var dvrTrait:DVRTrait; - private var timeTrait:TimeTrait; - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.DVR; - _requiredTraits[1] = MediaTraitType.TIME; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.Event; + + import org.osmf.chrome.widgets.ButtonWidget; + import org.osmf.events.DVREvent; + import org.osmf.events.TimeEvent; + import org.osmf.media.MediaElement; + import org.osmf.net.NetStreamLoadTrait; + import org.osmf.traits.DVRTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.TimeTrait; + + public class LiveButton extends ButtonWidget + { + // Overrides + // + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + dvrTrait = element.getTrait(MediaTraitType.DVR) as DVRTrait; + dvrTrait.addEventListener(DVREvent.IS_RECORDING_CHANGE, visibilityDeterminingEventHandler); + + timeTrait = element.getTrait(MediaTraitType.TIME) as TimeTrait; + timeTrait.addEventListener(TimeEvent.DURATION_CHANGE, visibilityDeterminingEventHandler); + + visibilityDeterminingEventHandler(); + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + if (dvrTrait) + { + dvrTrait.removeEventListener(DVREvent.IS_RECORDING_CHANGE, visibilityDeterminingEventHandler); + dvrTrait = null; + } + + if (timeTrait) + { + timeTrait.removeEventListener(TimeEvent.DURATION_CHANGE, visibilityDeterminingEventHandler); + timeTrait = null; + } + + visibilityDeterminingEventHandler(); + } + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + // Internals + // + + private function visibilityDeterminingEventHandler(event:Event = null):void + { + visible + = dvrTrait != null + && dvrTrait.isRecording == true + && timeTrait + && timeTrait.currentTime >= Math.max(0, timeTrait.duration - getBufferTime() - 5); + } + + private function getBufferTime():Number + { + var result:Number = 0; + + var loadable:NetStreamLoadTrait = media.getTrait(MediaTraitType.LOAD) as NetStreamLoadTrait; + if (loadable) + { + result = loadable.netStream.bufferTime; + } + + return result; + } + + private var dvrTrait:DVRTrait; + private var timeTrait:TimeTrait; + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.DVR; + _requiredTraits[1] = MediaTraitType.TIME; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/MetadataLabel.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/MetadataLabel.as index ef1913a..051cade 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/MetadataLabel.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/MetadataLabel.as @@ -1,90 +1,90 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.media.MediaElement; - import org.osmf.metadata.MetadataWatcher; - - public class MetadataLabel extends LabelWidget - { - // Overrides - // - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - metadataNamespace = xml.@metadataNamespace; - metadataKey = xml.@metadataKey; - prefix = xml.@text; - postfix = xml.@postfix; - - super.configure(xml, assetManager); - } - - override public function set media(value:MediaElement):void - { - if (media != value) - { - if (watcher) - { - // Clean up: - watcher.unwatch(); - watcher = null; - } - - if (value) - { - // Watch the indicated metadata value for change: - watcher = - new MetadataWatcher - ( value.metadata - , metadataNamespace - , metadataKey - , onMetadataValueChange - ); - watcher.watch(); - } - else - { - text = ""; - } - } - - super.media = value; - } - - // Internals - // - - private var watcher:MetadataWatcher; - private var metadataNamespace:String; - private var metadataKey:String; - private var prefix:String = ""; - private var postfix:String = ""; - - private function onMetadataValueChange(value:*):void - { - text = prefix + value + postfix; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.media.MediaElement; + import org.osmf.metadata.MetadataWatcher; + + public class MetadataLabel extends LabelWidget + { + // Overrides + // + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + metadataNamespace = xml.@metadataNamespace; + metadataKey = xml.@metadataKey; + prefix = xml.@text; + postfix = xml.@postfix; + + super.configure(xml, assetManager); + } + + override public function set media(value:MediaElement):void + { + if (media != value) + { + if (watcher) + { + // Clean up: + watcher.unwatch(); + watcher = null; + } + + if (value) + { + // Watch the indicated metadata value for change: + watcher = + new MetadataWatcher + ( value.metadata + , metadataNamespace + , metadataKey + , onMetadataValueChange + ); + watcher.watch(); + } + else + { + text = ""; + } + } + + super.media = value; + } + + // Internals + // + + private var watcher:MetadataWatcher; + private var metadataNamespace:String; + private var metadataKey:String; + private var prefix:String = ""; + private var postfix:String = ""; + + private function onMetadataValueChange(value:*):void + { + text = prefix + value + postfix; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PauseButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PauseButton.as index 5f0c8e6..4a83b3e 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PauseButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PauseButton.as @@ -1,52 +1,52 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.events.Event; - import flash.events.MouseEvent; - - import org.osmf.events.PlayEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - - public class PauseButton extends PlayableButton - { - // Overrides - // - - override protected function onMouseClick(event:MouseEvent):void - { - var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; - playable.pause(); - } - - override protected function visibilityDeterminingEventHandler(event:Event = null):void - { - visible = playable && playable.playState != PlayState.PAUSED && playable.canPause; - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.events.Event; + import flash.events.MouseEvent; + + import org.osmf.events.PlayEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + + public class PauseButton extends PlayableButton + { + // Overrides + // + + override protected function onMouseClick(event:MouseEvent):void + { + var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; + playable.pause(); + } + + override protected function visibilityDeterminingEventHandler(event:Event = null):void + { + visible = playable && playable.playState != PlayState.PAUSED && playable.canPause; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PinDownButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PinDownButton.as index fa9aefa..4394a68 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PinDownButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PinDownButton.as @@ -1,37 +1,37 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.MouseEvent; - - public class PinDownButton extends PinUpButton - { - // Overrides - // - - override protected function get matchingAutoHideValue():Boolean - { - return true; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.MouseEvent; + + public class PinDownButton extends PinUpButton + { + // Overrides + // + + override protected function get matchingAutoHideValue():Boolean + { + return true; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PinUpButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PinUpButton.as index eeeecdf..2970d14 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PinUpButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PinUpButton.as @@ -1,98 +1,98 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.MouseEvent; - - import org.osmf.chrome.metadata.ChromeMetadata; - import org.osmf.media.MediaElement; - import org.osmf.metadata.Metadata; - import org.osmf.metadata.MetadataWatcher; - - public class PinUpButton extends ButtonWidget - { - // Overrides - // - - override protected function processMediaElementChange(oldElement:MediaElement):void - { - if (autoHideWatcher) - { - autoHideWatcher.unwatch(); - autoHideWatcher = null; - } - - if (media != null) - { - autoHideWatcher - = new MetadataWatcher - ( media.metadata - , ChromeMetadata.CHROME_METADATA_KEY - , ChromeMetadata.AUTO_HIDE - , autoHideChangeCallback - ); - autoHideWatcher.watch(); - } - else - { - visible = false; - } - } - - // Overrides - // - - override protected function onMouseClick(event:MouseEvent):void - { - if (media) - { - var metadata:Metadata = media.getMetadata(ChromeMetadata.CHROME_METADATA_KEY); - if (metadata) - { - metadata.addValue(ChromeMetadata.AUTO_HIDE, !matchingAutoHideValue); - } - else - { - metadata = new Metadata(); - metadata.addValue(ChromeMetadata.AUTO_HIDE, !matchingAutoHideValue); - media.addMetadata(ChromeMetadata.CHROME_METADATA_KEY, metadata); - } - } - } - - // Internals - // - - protected function get matchingAutoHideValue():Boolean - { - return false; - } - - protected function autoHideChangeCallback(value:Boolean):void - { - visible = value == matchingAutoHideValue; - } - - private var autoHideWatcher:MetadataWatcher; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.MouseEvent; + + import org.osmf.chrome.metadata.ChromeMetadata; + import org.osmf.media.MediaElement; + import org.osmf.metadata.Metadata; + import org.osmf.metadata.MetadataWatcher; + + public class PinUpButton extends ButtonWidget + { + // Overrides + // + + override protected function processMediaElementChange(oldElement:MediaElement):void + { + if (autoHideWatcher) + { + autoHideWatcher.unwatch(); + autoHideWatcher = null; + } + + if (media != null) + { + autoHideWatcher + = new MetadataWatcher + ( media.metadata + , ChromeMetadata.CHROME_METADATA_KEY + , ChromeMetadata.AUTO_HIDE + , autoHideChangeCallback + ); + autoHideWatcher.watch(); + } + else + { + visible = false; + } + } + + // Overrides + // + + override protected function onMouseClick(event:MouseEvent):void + { + if (media) + { + var metadata:Metadata = media.getMetadata(ChromeMetadata.CHROME_METADATA_KEY); + if (metadata) + { + metadata.addValue(ChromeMetadata.AUTO_HIDE, !matchingAutoHideValue); + } + else + { + metadata = new Metadata(); + metadata.addValue(ChromeMetadata.AUTO_HIDE, !matchingAutoHideValue); + media.addMetadata(ChromeMetadata.CHROME_METADATA_KEY, metadata); + } + } + } + + // Internals + // + + protected function get matchingAutoHideValue():Boolean + { + return false; + } + + protected function autoHideChangeCallback(value:Boolean):void + { + visible = value == matchingAutoHideValue; + } + + private var autoHideWatcher:MetadataWatcher; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PlayButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PlayButton.as index c0389bf..9554be7 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PlayButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PlayButton.as @@ -1,51 +1,51 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.Event; - import flash.events.MouseEvent; - - import org.osmf.events.MediaElementEvent; - import org.osmf.events.PlayEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - - public class PlayButton extends PlayableButton - { - // Overrides - // - - override protected function onMouseClick(event:MouseEvent):void - { - var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; - playable.play(); - } - - override protected function visibilityDeterminingEventHandler(event:Event = null):void - { - visible = playable && playable.playState != PlayState.PLAYING; - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.Event; + import flash.events.MouseEvent; + + import org.osmf.events.MediaElementEvent; + import org.osmf.events.PlayEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + + public class PlayButton extends PlayableButton + { + // Overrides + // + + override protected function onMouseClick(event:MouseEvent):void + { + var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; + playable.play(); + } + + override protected function visibilityDeterminingEventHandler(event:Event = null):void + { + visible = playable && playable.playState != PlayState.PLAYING; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PlayableButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PlayableButton.as index de5cd65..5f0ff60 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PlayableButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/PlayableButton.as @@ -1,89 +1,89 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.events.Event; - - import org.osmf.events.PlayEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - - public class PlayableButton extends ButtonWidget - { - // Protected - // - - protected function get playable():PlayTrait - { - return _playable; - } - - // Overrides - // - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - _playable = element.getTrait(MediaTraitType.PLAY) as PlayTrait; - _playable.addEventListener(PlayEvent.CAN_PAUSE_CHANGE, visibilityDeterminingEventHandler); - _playable.addEventListener(PlayEvent.PLAY_STATE_CHANGE, visibilityDeterminingEventHandler); - - visibilityDeterminingEventHandler(); - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - if (_playable) - { - _playable.removeEventListener(PlayEvent.CAN_PAUSE_CHANGE, visibilityDeterminingEventHandler); - _playable.removeEventListener(PlayEvent.PLAY_STATE_CHANGE, visibilityDeterminingEventHandler); - _playable = null; - } - - visibilityDeterminingEventHandler(); - } - - // Stubs - // - - protected function visibilityDeterminingEventHandler(event:Event = null):void - { - } - - // Internals - // - - private var _playable:PlayTrait; - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.PLAY; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.events.Event; + + import org.osmf.events.PlayEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + + public class PlayableButton extends ButtonWidget + { + // Protected + // + + protected function get playable():PlayTrait + { + return _playable; + } + + // Overrides + // + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + _playable = element.getTrait(MediaTraitType.PLAY) as PlayTrait; + _playable.addEventListener(PlayEvent.CAN_PAUSE_CHANGE, visibilityDeterminingEventHandler); + _playable.addEventListener(PlayEvent.PLAY_STATE_CHANGE, visibilityDeterminingEventHandler); + + visibilityDeterminingEventHandler(); + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + if (_playable) + { + _playable.removeEventListener(PlayEvent.CAN_PAUSE_CHANGE, visibilityDeterminingEventHandler); + _playable.removeEventListener(PlayEvent.PLAY_STATE_CHANGE, visibilityDeterminingEventHandler); + _playable = null; + } + + visibilityDeterminingEventHandler(); + } + + // Stubs + // + + protected function visibilityDeterminingEventHandler(event:Event = null):void + { + } + + // Internals + // + + private var _playable:PlayTrait; + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.PLAY; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityDecreaseButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityDecreaseButton.as index 89ec600..dca739b 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityDecreaseButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityDecreaseButton.as @@ -1,50 +1,50 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.Event; - import flash.events.MouseEvent; - - public class QualityDecreaseButton extends QualityIncreaseButton - { - // Overrides - // - - override protected function onMouseClick(event:MouseEvent):void - { - dynamicStream.switchTo(dynamicStream.currentIndex - 1); - } - - override protected function visibilityDeterminingEventHandler(event:Event = null):void - { - visible - = dynamicStream != null - && dynamicStream.autoSwitch == false; - - enabled - = dynamicStream != null - && dynamicStream.switching == false - && dynamicStream.currentIndex != 0; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.Event; + import flash.events.MouseEvent; + + public class QualityDecreaseButton extends QualityIncreaseButton + { + // Overrides + // + + override protected function onMouseClick(event:MouseEvent):void + { + dynamicStream.switchTo(dynamicStream.currentIndex - 1); + } + + override protected function visibilityDeterminingEventHandler(event:Event = null):void + { + visible + = dynamicStream != null + && dynamicStream.autoSwitch == false; + + enabled + = dynamicStream != null + && dynamicStream.switching == false + && dynamicStream.currentIndex != 0; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityIncreaseButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityIncreaseButton.as index 67a5143..eea0faf 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityIncreaseButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityIncreaseButton.as @@ -1,95 +1,95 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.events.Event; - import flash.events.MouseEvent; - - import org.osmf.events.DynamicStreamEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.DynamicStreamTrait; - import org.osmf.traits.MediaTraitType; - - public class QualityIncreaseButton extends ButtonWidget - { - // Overrides - // - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - dynamicStream = element.getTrait(MediaTraitType.DYNAMIC_STREAM) as DynamicStreamTrait; - dynamicStream.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, visibilityDeterminingEventHandler); - dynamicStream.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, visibilityDeterminingEventHandler); - dynamicStream.addEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, visibilityDeterminingEventHandler); - - visibilityDeterminingEventHandler(); - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - if (dynamicStream) - { - dynamicStream.removeEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, visibilityDeterminingEventHandler); - dynamicStream.removeEventListener(DynamicStreamEvent.SWITCHING_CHANGE, visibilityDeterminingEventHandler); - dynamicStream.removeEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, visibilityDeterminingEventHandler); - dynamicStream = null; - } - - visibilityDeterminingEventHandler(); - } - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function onMouseClick(event:MouseEvent):void - { - dynamicStream.switchTo(dynamicStream.currentIndex + 1); - } - - // Internals - // - - protected function visibilityDeterminingEventHandler(event:Event = null):void - { - visible - = dynamicStream != null - && dynamicStream.autoSwitch == false; - - enabled - = dynamicStream != null - && dynamicStream.switching == false - && dynamicStream.numDynamicStreams > 0 - && dynamicStream.currentIndex < (dynamicStream.numDynamicStreams - 1); - } - - protected var dynamicStream:DynamicStreamTrait; - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.DYNAMIC_STREAM; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.events.Event; + import flash.events.MouseEvent; + + import org.osmf.events.DynamicStreamEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.DynamicStreamTrait; + import org.osmf.traits.MediaTraitType; + + public class QualityIncreaseButton extends ButtonWidget + { + // Overrides + // + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + dynamicStream = element.getTrait(MediaTraitType.DYNAMIC_STREAM) as DynamicStreamTrait; + dynamicStream.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, visibilityDeterminingEventHandler); + dynamicStream.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, visibilityDeterminingEventHandler); + dynamicStream.addEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, visibilityDeterminingEventHandler); + + visibilityDeterminingEventHandler(); + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + if (dynamicStream) + { + dynamicStream.removeEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, visibilityDeterminingEventHandler); + dynamicStream.removeEventListener(DynamicStreamEvent.SWITCHING_CHANGE, visibilityDeterminingEventHandler); + dynamicStream.removeEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, visibilityDeterminingEventHandler); + dynamicStream = null; + } + + visibilityDeterminingEventHandler(); + } + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function onMouseClick(event:MouseEvent):void + { + dynamicStream.switchTo(dynamicStream.currentIndex + 1); + } + + // Internals + // + + protected function visibilityDeterminingEventHandler(event:Event = null):void + { + visible + = dynamicStream != null + && dynamicStream.autoSwitch == false; + + enabled + = dynamicStream != null + && dynamicStream.switching == false + && dynamicStream.numDynamicStreams > 0 + && dynamicStream.currentIndex < (dynamicStream.numDynamicStreams - 1); + } + + protected var dynamicStream:DynamicStreamTrait; + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.DYNAMIC_STREAM; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityLabel.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityLabel.as index b0c4d56..3c9fd00 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityLabel.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityLabel.as @@ -1,93 +1,93 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.events.Event; - - import org.osmf.events.DynamicStreamEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.DynamicStreamTrait; - import org.osmf.traits.MediaTraitType; - - - public class QualityLabel extends LabelWidget - { - // Overrides - // - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function processMediaElementChange(oldElement:MediaElement):void - { - visibilityDeterminingEventHandler(); - } - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - dynamicStream = element.getTrait(MediaTraitType.DYNAMIC_STREAM) as DynamicStreamTrait; - dynamicStream.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, visibilityDeterminingEventHandler); - dynamicStream.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, visibilityDeterminingEventHandler); - - visibilityDeterminingEventHandler(); - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - if (dynamicStream) - { - dynamicStream.removeEventListener(DynamicStreamEvent.SWITCHING_CHANGE, visibilityDeterminingEventHandler); - dynamicStream.removeEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, visibilityDeterminingEventHandler); - dynamicStream = null; - } - - visibilityDeterminingEventHandler(); - } - - // Internals - // - - private function visibilityDeterminingEventHandler(event:Event = null):void - { - enabled = dynamicStream != null; - - visible - = media != null - && enabled == true - - text = dynamicStream - ? dynamicStream.getBitrateForIndex(dynamicStream.currentIndex).toString() + " kbps" - : ""; - } - - private var dynamicStream:DynamicStreamTrait; - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.DYNAMIC_STREAM; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.events.Event; + + import org.osmf.events.DynamicStreamEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.DynamicStreamTrait; + import org.osmf.traits.MediaTraitType; + + + public class QualityLabel extends LabelWidget + { + // Overrides + // + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function processMediaElementChange(oldElement:MediaElement):void + { + visibilityDeterminingEventHandler(); + } + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + dynamicStream = element.getTrait(MediaTraitType.DYNAMIC_STREAM) as DynamicStreamTrait; + dynamicStream.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, visibilityDeterminingEventHandler); + dynamicStream.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, visibilityDeterminingEventHandler); + + visibilityDeterminingEventHandler(); + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + if (dynamicStream) + { + dynamicStream.removeEventListener(DynamicStreamEvent.SWITCHING_CHANGE, visibilityDeterminingEventHandler); + dynamicStream.removeEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, visibilityDeterminingEventHandler); + dynamicStream = null; + } + + visibilityDeterminingEventHandler(); + } + + // Internals + // + + private function visibilityDeterminingEventHandler(event:Event = null):void + { + enabled = dynamicStream != null; + + visible + = media != null + && enabled == true + + text = dynamicStream + ? dynamicStream.getBitrateForIndex(dynamicStream.currentIndex).toString() + " kbps" + : ""; + } + + private var dynamicStream:DynamicStreamTrait; + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.DYNAMIC_STREAM; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityModeToggle.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityModeToggle.as index 49338a3..dd3ab59 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityModeToggle.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/QualityModeToggle.as @@ -1,85 +1,85 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.events.Event; - import flash.events.MouseEvent; - - import org.osmf.chrome.widgets.ButtonWidget; - import org.osmf.media.MediaElement; - import org.osmf.traits.DynamicStreamTrait; - import org.osmf.traits.MediaTraitType; - - public class QualityModeToggle extends ButtonWidget - { - // Overrides - // - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function processMediaElementChange(oldElement:MediaElement):void - { - visibilityDeterminingEventHandler(); - } - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - dynamicStream = element.getTrait(MediaTraitType.DYNAMIC_STREAM) as DynamicStreamTrait; - visibilityDeterminingEventHandler(); - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - dynamicStream = null; - visibilityDeterminingEventHandler(); - } - - override protected function onMouseClick(event:MouseEvent):void - { - dynamicStream.autoSwitch = !dynamicStream.autoSwitch; - } - - // Internals - // - - private function visibilityDeterminingEventHandler(event:Event = null):void - { - enabled = dynamicStream != null; - - visible - = media != null - && enabled == true - } - - private var dynamicStream:DynamicStreamTrait; - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.DYNAMIC_STREAM; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.events.Event; + import flash.events.MouseEvent; + + import org.osmf.chrome.widgets.ButtonWidget; + import org.osmf.media.MediaElement; + import org.osmf.traits.DynamicStreamTrait; + import org.osmf.traits.MediaTraitType; + + public class QualityModeToggle extends ButtonWidget + { + // Overrides + // + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function processMediaElementChange(oldElement:MediaElement):void + { + visibilityDeterminingEventHandler(); + } + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + dynamicStream = element.getTrait(MediaTraitType.DYNAMIC_STREAM) as DynamicStreamTrait; + visibilityDeterminingEventHandler(); + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + dynamicStream = null; + visibilityDeterminingEventHandler(); + } + + override protected function onMouseClick(event:MouseEvent):void + { + dynamicStream.autoSwitch = !dynamicStream.autoSwitch; + } + + // Internals + // + + private function visibilityDeterminingEventHandler(event:Event = null):void + { + enabled = dynamicStream != null; + + visible + = media != null + && enabled == true + } + + private var dynamicStream:DynamicStreamTrait; + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.DYNAMIC_STREAM; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/RecordButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/RecordButton.as index a0bb71a..6d5d7fd 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/RecordButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/RecordButton.as @@ -1,141 +1,141 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.Event; - import flash.events.MouseEvent; - - import org.osmf.events.DVREvent; - import org.osmf.events.SeekEvent; - import org.osmf.events.TimeEvent; - import org.osmf.media.MediaElement; - import org.osmf.net.NetStreamLoadTrait; - import org.osmf.traits.DVRTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - - public class RecordButton extends ButtonWidget - { - // Overrides - // - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - dvrTrait = element.getTrait(MediaTraitType.DVR) as DVRTrait; - dvrTrait.addEventListener(DVREvent.IS_RECORDING_CHANGE, visibilityDeterminingEventHandler); - - timeTrait = element.getTrait(MediaTraitType.TIME) as TimeTrait; - timeTrait.addEventListener(TimeEvent.DURATION_CHANGE, visibilityDeterminingEventHandler); - - visibilityDeterminingEventHandler(); - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - if (dvrTrait) - { - dvrTrait.removeEventListener(DVREvent.IS_RECORDING_CHANGE, visibilityDeterminingEventHandler); - dvrTrait = null; - } - - if (timeTrait) - { - timeTrait.removeEventListener(TimeEvent.DURATION_CHANGE, visibilityDeterminingEventHandler); - timeTrait = null; - } - - visibilityDeterminingEventHandler(); - } - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function onMouseClick(event:MouseEvent):void - { - var seekable:SeekTrait = media.getTrait(MediaTraitType.SEEK) as SeekTrait; - if (seekable && dvrTrait) - { - var bufferTime:Number = getBufferTime(); - var livePosition:Number = Math.max(0, timeTrait.duration - bufferTime - 2); - if (seekable.canSeekTo(livePosition)) - { - // While seeking, disable the button: - enabled = false; - seekable.addEventListener - ( SeekEvent.SEEKING_CHANGE - , function(event:SeekEvent):void - { - if (event.seeking == false) - { - // Re-enable the button: - removeEventListener(event.type, arguments.callee); - enabled = true; - } - } - ); - - // Seek to the live position: - seekable.seek(livePosition); - } - } - } - - // Internals - // - - private function visibilityDeterminingEventHandler(event:Event = null):void - { - visible - = dvrTrait != null - && dvrTrait.isRecording == true - && timeTrait - && timeTrait.currentTime < Math.max(0, timeTrait.duration - getBufferTime() - 5); - - enabled = media && media.hasTrait(MediaTraitType.SEEK); - } - - private function getBufferTime():Number - { - var result:Number = 0; - - var loadable:NetStreamLoadTrait = media.getTrait(MediaTraitType.LOAD) as NetStreamLoadTrait; - if (loadable) - { - result = loadable.netStream.bufferTime; - } - - return result; - } - - private var dvrTrait:DVRTrait; - private var timeTrait:TimeTrait; - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.DVR; - _requiredTraits[1] = MediaTraitType.TIME; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.Event; + import flash.events.MouseEvent; + + import org.osmf.events.DVREvent; + import org.osmf.events.SeekEvent; + import org.osmf.events.TimeEvent; + import org.osmf.media.MediaElement; + import org.osmf.net.NetStreamLoadTrait; + import org.osmf.traits.DVRTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + + public class RecordButton extends ButtonWidget + { + // Overrides + // + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + dvrTrait = element.getTrait(MediaTraitType.DVR) as DVRTrait; + dvrTrait.addEventListener(DVREvent.IS_RECORDING_CHANGE, visibilityDeterminingEventHandler); + + timeTrait = element.getTrait(MediaTraitType.TIME) as TimeTrait; + timeTrait.addEventListener(TimeEvent.DURATION_CHANGE, visibilityDeterminingEventHandler); + + visibilityDeterminingEventHandler(); + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + if (dvrTrait) + { + dvrTrait.removeEventListener(DVREvent.IS_RECORDING_CHANGE, visibilityDeterminingEventHandler); + dvrTrait = null; + } + + if (timeTrait) + { + timeTrait.removeEventListener(TimeEvent.DURATION_CHANGE, visibilityDeterminingEventHandler); + timeTrait = null; + } + + visibilityDeterminingEventHandler(); + } + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function onMouseClick(event:MouseEvent):void + { + var seekable:SeekTrait = media.getTrait(MediaTraitType.SEEK) as SeekTrait; + if (seekable && dvrTrait) + { + var bufferTime:Number = getBufferTime(); + var livePosition:Number = Math.max(0, timeTrait.duration - bufferTime - 2); + if (seekable.canSeekTo(livePosition)) + { + // While seeking, disable the button: + enabled = false; + seekable.addEventListener + ( SeekEvent.SEEKING_CHANGE + , function(event:SeekEvent):void + { + if (event.seeking == false) + { + // Re-enable the button: + removeEventListener(event.type, arguments.callee); + enabled = true; + } + } + ); + + // Seek to the live position: + seekable.seek(livePosition); + } + } + } + + // Internals + // + + private function visibilityDeterminingEventHandler(event:Event = null):void + { + visible + = dvrTrait != null + && dvrTrait.isRecording == true + && timeTrait + && timeTrait.currentTime < Math.max(0, timeTrait.duration - getBufferTime() - 5); + + enabled = media && media.hasTrait(MediaTraitType.SEEK); + } + + private function getBufferTime():Number + { + var result:Number = 0; + + var loadable:NetStreamLoadTrait = media.getTrait(MediaTraitType.LOAD) as NetStreamLoadTrait; + if (loadable) + { + result = loadable.netStream.bufferTime; + } + + return result; + } + + private var dvrTrait:DVRTrait; + private var timeTrait:TimeTrait; + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.DVR; + _requiredTraits[1] = MediaTraitType.TIME; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ScrubBar.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ScrubBar.as index 439292a..2a1c805 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ScrubBar.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/ScrubBar.as @@ -1,356 +1,356 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.chrome.widgets -{ - import flash.display.DisplayObject; - import flash.display.Sprite; - import flash.events.Event; - import flash.events.MouseEvent; - import flash.events.TimerEvent; - import flash.text.TextField; - import flash.text.TextFormat; - import flash.text.TextFormatAlign; - import flash.utils.Timer; - - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.assets.FontAsset; - import org.osmf.chrome.events.ScrubberEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.events.SeekEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - - public class ScrubBar extends Widget - { - public function ScrubBar() - { - currentTime = new TextField(); - addChild(currentTime); - - remainingTime = new TextField(); - addChild(remainingTime); - - scrubBarClickArea = new Sprite(); - scrubBarClickArea.addEventListener(MouseEvent.MOUSE_DOWN, onTrackMouseDown); - addChild(scrubBarClickArea); - - super(); - } - - // Overrides - // - - override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void - { - if (lastWidth != availableWidth || lastHeight != availableHeight) - { - lastWidth = availableWidth; - lastHeight = availableHeight; - - currentTime.height - = remainingTime.height - = timeFieldsHeight; - - currentTime.width - = remainingTime.width - = timeFieldsWidth; - - remainingTime.x = availableWidth - timeFieldsWidth; - - var scrubBarWidth:Number = Math.max(10, availableWidth - ((timeFieldsWidth + timeFieldSpacing) * 2)); - - scrubBarTrack.x = Math.round(timeFieldsWidth + timeFieldSpacing); - scrubBarTrack.y = Math.round((timeFieldsHeight - scrubBarTrack.height) / 2) - scrubBarTrack.width = scrubBarWidth; - - scrubberStart = scrubBarTrack.x - Math.round(scrubber.width / 2); - scrubberEnd = scrubberStart + scrubBarWidth; - - scrubber.range = scrubBarWidth; - scrubber.y = scrubBarTrack.y; - scrubber.origin = scrubberStart; - - scrubBarClickArea.x = scrubBarTrack.x; - scrubBarClickArea.y = scrubBarTrack.y; - scrubBarClickArea.graphics.clear(); - scrubBarClickArea.graphics.beginFill(0xFFFFFF, 0); - scrubBarClickArea.graphics.drawRect(0, 0, scrubBarWidth, scrubber.height); - scrubBarClickArea.graphics.endFill(); - - onTimerTick(); - } - } - - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - super.configure(xml, assetManager); - - timeFieldsWidth = Number(xml.@timeFieldsWidth || 52); - timeFieldsHeight = Number(xml.@timeFieldsHeight || 20); - timeFieldSpacing = Number(xml.@timeFieldSpacing || 10); - - var fontId:String = xml.@font || "defaultFont"; - var fontAsset:FontAsset = assetManager.getAsset(fontId) as FontAsset; - - currentTime.defaultTextFormat = fontAsset.format; - currentTime.selectable = false; - currentTime.embedFonts = true; - currentTime.alpha = 0.4; - - var format:TextFormat = fontAsset.format; - format.align = TextFormatAlign.RIGHT; - remainingTime.defaultTextFormat = format; - remainingTime.selectable = false; - remainingTime.embedFonts = true; - remainingTime.alpha = 0.4; - - scrubBarTrack = assetManager.getDisplayObject(xml.@track) || new Sprite(); - addChild(scrubBarTrack); - - scrubber - = new Scrubber - ( assetManager.getDisplayObject(xml.@scrubberUp) || new Sprite() - , assetManager.getDisplayObject(xml.@scrubberDown) || new Sprite() - , assetManager.getDisplayObject(xml.@scrubberDisabled) || new Sprite() - ); - - scrubber.enabled = false; - scrubber.addEventListener(ScrubberEvent.SCRUB_START, onScrubberStart); - scrubber.addEventListener(ScrubberEvent.SCRUB_UPDATE, onScrubberUpdate); - scrubber.addEventListener(ScrubberEvent.SCRUB_END, onScrubberEnd); - addChild(scrubber); - - currentPositionTimer = new Timer(CURRENT_POSITION_UPDATE_INTERVAL); - currentPositionTimer.addEventListener(TimerEvent.TIMER, onTimerTick); - - measure(); - - updateState(); - } - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function processRequiredTraitsAvailable(media:MediaElement):void - { - updateState(); - } - - override protected function processRequiredTraitsUnavailable(media:MediaElement):void - { - updateState(); - } - - override protected function onMediaElementTraitAdd(event:MediaElementEvent):void - { - updateState(); - } - - override protected function onMediaElementTraitRemove(event:MediaElementEvent):void - { - updateState(); - } - - // Internals - // - - private function updateState():void - { - visible = media != null; - scrubber.enabled = media ? media.hasTrait(MediaTraitType.SEEK) : false; - updateTimerState(); - } - - private function updateTimerState():void - { - var temporal:TimeTrait = media ? media.getTrait(MediaTraitType.TIME) as TimeTrait : null; - if (temporal == null) - { - currentPositionTimer.stop(); - - resetUI(); - } - else - { - currentPositionTimer.start(); - } - } - - private function onTimerTick(event:Event = null):void - { - var temporal:TimeTrait = media ? media.getTrait(MediaTraitType.TIME) as TimeTrait : null; - if (temporal != null) - { - var duration:Number = temporal.duration; - var position:Number = isNaN(seekToTime) ? temporal.currentTime : seekToTime; - - currentTime.text - = prettyPrintSeconds(position); - - remainingTime.text - = "-" - + prettyPrintSeconds(Math.max(0, duration - position)); - - var scrubberX:Number - = scrubberStart - + ( (scrubberEnd - scrubberStart) - * position - ) - / duration - || scrubberStart; // defaul value if calc. returns NaN. - - scrubber.x = Math.min(scrubberEnd, Math.max(scrubberStart, scrubberX)); - } - else - { - resetUI(); - } - } - - private function prettyPrintSeconds(seconds:Number):String - { - seconds = Math.floor(isNaN(seconds) ? 0 : Math.max(0, seconds)); - return Math.floor(seconds / 3600) - + ":" - + (seconds % 3600 < 600 ? "0" : "") - + Math.floor(seconds % 3600 / 60) - + ":" - + (seconds % 60 < 10 ? "0" : "") + seconds % 60; - } - - private function onScrubberStart(event:ScrubberEvent):void - { - var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; - if (playable) - { - preScrubPlayState = playable.playState; - if (playable.canPause && playable.playState != PlayState.PAUSED) - { - playable.pause(); - } - } - } - - private function onScrubberUpdate(event:ScrubberEvent = null):void - { - var temporal:TimeTrait = media ? media.getTrait(MediaTraitType.TIME) as TimeTrait : null; - var seekable:SeekTrait = media ? media.getTrait(MediaTraitType.SEEK) as SeekTrait : null; - if (temporal && seekable) - { - var time:Number - = (temporal.duration * (scrubber.x - scrubberStart)) - / scrubber.range; - - if (seekable.canSeekTo(time)) - { - seekable.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange) - seekToTime = time; - seekable.seek(time); - } - } - } - - private function onSeekingChange(event:SeekEvent):void - { - var seekable:SeekTrait = event.target as SeekTrait; - if (event.seeking == false) - { - seekable.removeEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); - seekToTime = NaN; - onTimerTick(); - } - } - - private function onScrubberEnd(event:ScrubberEvent):void - { - onScrubberUpdate(); - - if (preScrubPlayState) - { - var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; - if (playable) - { - if (playable.playState != preScrubPlayState) - { - switch (preScrubPlayState) - { - case PlayState.STOPPED: - playable.stop(); - break; - case PlayState.PLAYING: - playable.play(); - break; - } - } - } - } - } - - private function onTrackMouseDown(evenet:MouseEvent):void - { - scrubber.start(); - } - - private function resetUI():void - { - currentTime.text = "0:00:00"; - remainingTime.text = "-0:00:00"; - scrubber.x = scrubberStart; - } - - private var scrubber:Scrubber; - private var scrubBarClickArea:Sprite; - - private var scrubberStart:Number; - private var scrubberEnd:Number; - - private var timeFieldsWidth:Number; - private var timeFieldsHeight:Number; - private var timeFieldSpacing:Number; - - private var currentTime:TextField; - private var remainingTime:TextField; - - private var currentPositionTimer:Timer; - - private var scrubBarTrack:DisplayObject; - - private var preScrubPlayState:String; - - private var lastWidth:Number; - private var lastHeight:Number; - - private var seekToTime:Number; - - /* static */ - private static const CURRENT_POSITION_UPDATE_INTERVAL:int = 100; - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.TIME; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.chrome.widgets +{ + import flash.display.DisplayObject; + import flash.display.Sprite; + import flash.events.Event; + import flash.events.MouseEvent; + import flash.events.TimerEvent; + import flash.text.TextField; + import flash.text.TextFormat; + import flash.text.TextFormatAlign; + import flash.utils.Timer; + + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.assets.FontAsset; + import org.osmf.chrome.events.ScrubberEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.events.SeekEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + + public class ScrubBar extends Widget + { + public function ScrubBar() + { + currentTime = new TextField(); + addChild(currentTime); + + remainingTime = new TextField(); + addChild(remainingTime); + + scrubBarClickArea = new Sprite(); + scrubBarClickArea.addEventListener(MouseEvent.MOUSE_DOWN, onTrackMouseDown); + addChild(scrubBarClickArea); + + super(); + } + + // Overrides + // + + override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void + { + if (lastWidth != availableWidth || lastHeight != availableHeight) + { + lastWidth = availableWidth; + lastHeight = availableHeight; + + currentTime.height + = remainingTime.height + = timeFieldsHeight; + + currentTime.width + = remainingTime.width + = timeFieldsWidth; + + remainingTime.x = availableWidth - timeFieldsWidth; + + var scrubBarWidth:Number = Math.max(10, availableWidth - ((timeFieldsWidth + timeFieldSpacing) * 2)); + + scrubBarTrack.x = Math.round(timeFieldsWidth + timeFieldSpacing); + scrubBarTrack.y = Math.round((timeFieldsHeight - scrubBarTrack.height) / 2) + scrubBarTrack.width = scrubBarWidth; + + scrubberStart = scrubBarTrack.x - Math.round(scrubber.width / 2); + scrubberEnd = scrubberStart + scrubBarWidth; + + scrubber.range = scrubBarWidth; + scrubber.y = scrubBarTrack.y; + scrubber.origin = scrubberStart; + + scrubBarClickArea.x = scrubBarTrack.x; + scrubBarClickArea.y = scrubBarTrack.y; + scrubBarClickArea.graphics.clear(); + scrubBarClickArea.graphics.beginFill(0xFFFFFF, 0); + scrubBarClickArea.graphics.drawRect(0, 0, scrubBarWidth, scrubber.height); + scrubBarClickArea.graphics.endFill(); + + onTimerTick(); + } + } + + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + super.configure(xml, assetManager); + + timeFieldsWidth = Number(xml.@timeFieldsWidth || 52); + timeFieldsHeight = Number(xml.@timeFieldsHeight || 20); + timeFieldSpacing = Number(xml.@timeFieldSpacing || 10); + + var fontId:String = xml.@font || "defaultFont"; + var fontAsset:FontAsset = assetManager.getAsset(fontId) as FontAsset; + + currentTime.defaultTextFormat = fontAsset.format; + currentTime.selectable = false; + currentTime.embedFonts = true; + currentTime.alpha = 0.4; + + var format:TextFormat = fontAsset.format; + format.align = TextFormatAlign.RIGHT; + remainingTime.defaultTextFormat = format; + remainingTime.selectable = false; + remainingTime.embedFonts = true; + remainingTime.alpha = 0.4; + + scrubBarTrack = assetManager.getDisplayObject(xml.@track) || new Sprite(); + addChild(scrubBarTrack); + + scrubber + = new Scrubber + ( assetManager.getDisplayObject(xml.@scrubberUp) || new Sprite() + , assetManager.getDisplayObject(xml.@scrubberDown) || new Sprite() + , assetManager.getDisplayObject(xml.@scrubberDisabled) || new Sprite() + ); + + scrubber.enabled = false; + scrubber.addEventListener(ScrubberEvent.SCRUB_START, onScrubberStart); + scrubber.addEventListener(ScrubberEvent.SCRUB_UPDATE, onScrubberUpdate); + scrubber.addEventListener(ScrubberEvent.SCRUB_END, onScrubberEnd); + addChild(scrubber); + + currentPositionTimer = new Timer(CURRENT_POSITION_UPDATE_INTERVAL); + currentPositionTimer.addEventListener(TimerEvent.TIMER, onTimerTick); + + measure(); + + updateState(); + } + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function processRequiredTraitsAvailable(media:MediaElement):void + { + updateState(); + } + + override protected function processRequiredTraitsUnavailable(media:MediaElement):void + { + updateState(); + } + + override protected function onMediaElementTraitAdd(event:MediaElementEvent):void + { + updateState(); + } + + override protected function onMediaElementTraitRemove(event:MediaElementEvent):void + { + updateState(); + } + + // Internals + // + + private function updateState():void + { + visible = media != null; + scrubber.enabled = media ? media.hasTrait(MediaTraitType.SEEK) : false; + updateTimerState(); + } + + private function updateTimerState():void + { + var temporal:TimeTrait = media ? media.getTrait(MediaTraitType.TIME) as TimeTrait : null; + if (temporal == null) + { + currentPositionTimer.stop(); + + resetUI(); + } + else + { + currentPositionTimer.start(); + } + } + + private function onTimerTick(event:Event = null):void + { + var temporal:TimeTrait = media ? media.getTrait(MediaTraitType.TIME) as TimeTrait : null; + if (temporal != null) + { + var duration:Number = temporal.duration; + var position:Number = isNaN(seekToTime) ? temporal.currentTime : seekToTime; + + currentTime.text + = prettyPrintSeconds(position); + + remainingTime.text + = "-" + + prettyPrintSeconds(Math.max(0, duration - position)); + + var scrubberX:Number + = scrubberStart + + ( (scrubberEnd - scrubberStart) + * position + ) + / duration + || scrubberStart; // defaul value if calc. returns NaN. + + scrubber.x = Math.min(scrubberEnd, Math.max(scrubberStart, scrubberX)); + } + else + { + resetUI(); + } + } + + private function prettyPrintSeconds(seconds:Number):String + { + seconds = Math.floor(isNaN(seconds) ? 0 : Math.max(0, seconds)); + return Math.floor(seconds / 3600) + + ":" + + (seconds % 3600 < 600 ? "0" : "") + + Math.floor(seconds % 3600 / 60) + + ":" + + (seconds % 60 < 10 ? "0" : "") + seconds % 60; + } + + private function onScrubberStart(event:ScrubberEvent):void + { + var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; + if (playable) + { + preScrubPlayState = playable.playState; + if (playable.canPause && playable.playState != PlayState.PAUSED) + { + playable.pause(); + } + } + } + + private function onScrubberUpdate(event:ScrubberEvent = null):void + { + var temporal:TimeTrait = media ? media.getTrait(MediaTraitType.TIME) as TimeTrait : null; + var seekable:SeekTrait = media ? media.getTrait(MediaTraitType.SEEK) as SeekTrait : null; + if (temporal && seekable) + { + var time:Number + = (temporal.duration * (scrubber.x - scrubberStart)) + / scrubber.range; + + if (seekable.canSeekTo(time)) + { + seekable.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange) + seekToTime = time; + seekable.seek(time); + } + } + } + + private function onSeekingChange(event:SeekEvent):void + { + var seekable:SeekTrait = event.target as SeekTrait; + if (event.seeking == false) + { + seekable.removeEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); + seekToTime = NaN; + onTimerTick(); + } + } + + private function onScrubberEnd(event:ScrubberEvent):void + { + onScrubberUpdate(); + + if (preScrubPlayState) + { + var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; + if (playable) + { + if (playable.playState != preScrubPlayState) + { + switch (preScrubPlayState) + { + case PlayState.STOPPED: + playable.stop(); + break; + case PlayState.PLAYING: + playable.play(); + break; + } + } + } + } + } + + private function onTrackMouseDown(evenet:MouseEvent):void + { + scrubber.start(); + } + + private function resetUI():void + { + currentTime.text = "0:00:00"; + remainingTime.text = "-0:00:00"; + scrubber.x = scrubberStart; + } + + private var scrubber:Scrubber; + private var scrubBarClickArea:Sprite; + + private var scrubberStart:Number; + private var scrubberEnd:Number; + + private var timeFieldsWidth:Number; + private var timeFieldsHeight:Number; + private var timeFieldSpacing:Number; + + private var currentTime:TextField; + private var remainingTime:TextField; + + private var currentPositionTimer:Timer; + + private var scrubBarTrack:DisplayObject; + + private var preScrubPlayState:String; + + private var lastWidth:Number; + private var lastHeight:Number; + + private var seekToTime:Number; + + /* static */ + private static const CURRENT_POSITION_UPDATE_INTERVAL:int = 100; + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.TIME; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/Scrubber.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/Scrubber.as index 3ca5c23..e90bebb 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/Scrubber.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/Scrubber.as @@ -1,161 +1,161 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.display.DisplayObject; - import flash.display.Sprite; - import flash.events.MouseEvent; - import flash.events.TimerEvent; - import flash.geom.Rectangle; - import flash.utils.Timer; - - import org.osmf.chrome.events.ScrubberEvent; - - [Event(name="scrubStart", type="org.osmf.samples.controlbar.ScrubberEvent")] - [Event(name="scrubUpdate", type="org.osmf.samples.controlbar.ScrubberEvent")] - [Event(name="scrubEnd", type="org.osmf.samples.controlbar.ScrubberEvent")] - - public class Scrubber extends Sprite - { - public function Scrubber(up:DisplayObject, down:DisplayObject, disabled:DisplayObject) - { - this.up = up; - this.down = down; - this.disabled = disabled; - - scrubTimer = new Timer(1000); - scrubTimer.addEventListener(TimerEvent.TIMER, onDraggingTimer); - - updateFace(this.up); - - addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); - - super(); - } - - public function set enabled(value:Boolean):void - { - if (value != _enabled) - { - _enabled = value; - mouseEnabled = value; - updateFace(_enabled ? up : disabled); - } - } - - public function set origin(value:Number):void - { - _origin = value; - } - public function get origin():Number - { - return _origin; - } - - public function set range(value:Number):void - { - _range = value; - } - public function get range():Number - { - return _range; - } - - public function start(lockCenter:Boolean = true):void - { - if (_enabled && scrubbing == false) - { - scrubbing = true; - stage.addEventListener(MouseEvent.MOUSE_UP, onStageExitDrag); - updateFace(down); - startDrag(lockCenter, new Rectangle(_origin, y, _range, 0)); - scrubTimer.start(); - dispatchEvent(new ScrubberEvent(ScrubberEvent.SCRUB_START)); - } - } - - // Overrides - // - - override public function set x(value:Number):void - { - if (scrubbing == false) - { - super.x = value; - } - } - - // Internals - // - - private function updateFace(face:DisplayObject):void - { - if (currentFace != face) - { - if (currentFace) - { - removeChild(currentFace); - } - - currentFace = face; - - if (currentFace) - { - addChild(currentFace); - } - } - } - - private function onMouseDown(event:MouseEvent):void - { - start(false); - } - - private function onStageExitDrag(event:MouseEvent):void - { - scrubTimer.stop(); - stopDrag(); - updateFace(up); - scrubbing = false; - stage.removeEventListener(MouseEvent.MOUSE_UP, onStageExitDrag); - dispatchEvent(new ScrubberEvent(ScrubberEvent.SCRUB_END)); - } - - private function onDraggingTimer(event:TimerEvent):void - { - dispatchEvent(new ScrubberEvent(ScrubberEvent.SCRUB_UPDATE)); - } - - private var currentFace:DisplayObject; - private var up:DisplayObject; - private var down:DisplayObject; - private var disabled:DisplayObject; - - private var _enabled:Boolean = true; - private var _origin:Number = 0; - private var _range:Number = 100; - - private var scrubbing:Boolean; - private var scrubTimer:Timer; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.display.DisplayObject; + import flash.display.Sprite; + import flash.events.MouseEvent; + import flash.events.TimerEvent; + import flash.geom.Rectangle; + import flash.utils.Timer; + + import org.osmf.chrome.events.ScrubberEvent; + + [Event(name="scrubStart", type="org.osmf.samples.controlbar.ScrubberEvent")] + [Event(name="scrubUpdate", type="org.osmf.samples.controlbar.ScrubberEvent")] + [Event(name="scrubEnd", type="org.osmf.samples.controlbar.ScrubberEvent")] + + public class Scrubber extends Sprite + { + public function Scrubber(up:DisplayObject, down:DisplayObject, disabled:DisplayObject) + { + this.up = up; + this.down = down; + this.disabled = disabled; + + scrubTimer = new Timer(1000); + scrubTimer.addEventListener(TimerEvent.TIMER, onDraggingTimer); + + updateFace(this.up); + + addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + + super(); + } + + public function set enabled(value:Boolean):void + { + if (value != _enabled) + { + _enabled = value; + mouseEnabled = value; + updateFace(_enabled ? up : disabled); + } + } + + public function set origin(value:Number):void + { + _origin = value; + } + public function get origin():Number + { + return _origin; + } + + public function set range(value:Number):void + { + _range = value; + } + public function get range():Number + { + return _range; + } + + public function start(lockCenter:Boolean = true):void + { + if (_enabled && scrubbing == false) + { + scrubbing = true; + stage.addEventListener(MouseEvent.MOUSE_UP, onStageExitDrag); + updateFace(down); + startDrag(lockCenter, new Rectangle(_origin, y, _range, 0)); + scrubTimer.start(); + dispatchEvent(new ScrubberEvent(ScrubberEvent.SCRUB_START)); + } + } + + // Overrides + // + + override public function set x(value:Number):void + { + if (scrubbing == false) + { + super.x = value; + } + } + + // Internals + // + + private function updateFace(face:DisplayObject):void + { + if (currentFace != face) + { + if (currentFace) + { + removeChild(currentFace); + } + + currentFace = face; + + if (currentFace) + { + addChild(currentFace); + } + } + } + + private function onMouseDown(event:MouseEvent):void + { + start(false); + } + + private function onStageExitDrag(event:MouseEvent):void + { + scrubTimer.stop(); + stopDrag(); + updateFace(up); + scrubbing = false; + stage.removeEventListener(MouseEvent.MOUSE_UP, onStageExitDrag); + dispatchEvent(new ScrubberEvent(ScrubberEvent.SCRUB_END)); + } + + private function onDraggingTimer(event:TimerEvent):void + { + dispatchEvent(new ScrubberEvent(ScrubberEvent.SCRUB_UPDATE)); + } + + private var currentFace:DisplayObject; + private var up:DisplayObject; + private var down:DisplayObject; + private var disabled:DisplayObject; + + private var _enabled:Boolean = true; + private var _origin:Number = 0; + private var _range:Number = 100; + + private var scrubbing:Boolean; + private var scrubTimer:Timer; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/SoundLessButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/SoundLessButton.as index 068fc51..2fbc6f3 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/SoundLessButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/SoundLessButton.as @@ -1,47 +1,47 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.MouseEvent; - - import org.osmf.events.AudioEvent; - - public class SoundLessButton extends SoundMoreButton - { - // Overrides - // - - override protected function onMouseClick(event:MouseEvent):void - { - if (audible) - { - audible.volume = Math.max(0, audible.volume - 0.2); - } - } - - override protected function onVolumeChange(event:AudioEvent = null):void - { - enabled = audible ? audible.volume != 0 : false; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.MouseEvent; + + import org.osmf.events.AudioEvent; + + public class SoundLessButton extends SoundMoreButton + { + // Overrides + // + + override protected function onMouseClick(event:MouseEvent):void + { + if (audible) + { + audible.volume = Math.max(0, audible.volume - 0.2); + } + } + + override protected function onVolumeChange(event:AudioEvent = null):void + { + enabled = audible ? audible.volume != 0 : false; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/SoundMoreButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/SoundMoreButton.as index 5a59f54..1c71def 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/SoundMoreButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/SoundMoreButton.as @@ -1,88 +1,88 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.events.MouseEvent; - - import org.osmf.chrome.widgets.ButtonWidget; - import org.osmf.events.AudioEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.AudioTrait; - import org.osmf.traits.MediaTraitType; - - public class SoundMoreButton extends ButtonWidget - { - // Overrides - // - - override protected function get requiredTraits():Vector. - { - return _requiredTraits; - } - - override protected function processRequiredTraitsAvailable(element:MediaElement):void - { - visible = true; - audible = element.getTrait(MediaTraitType.AUDIO) as AudioTrait; - if (audible) - { - audible.addEventListener(AudioEvent.VOLUME_CHANGE, onVolumeChange); - } - onVolumeChange(); - } - - override protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - visible = false; - if (audible) - { - audible.removeEventListener(AudioEvent.VOLUME_CHANGE, onVolumeChange); - audible = null; - } - } - - override protected function onMouseClick(event:MouseEvent):void - { - if (audible) - { - audible.volume = Math.min(1, audible.volume + 0.2); - } - } - - // Internals - // - - protected var audible:AudioTrait; - - protected function onVolumeChange(event:AudioEvent = null):void - { - enabled = audible ? audible.volume != 1 : false; - } - - /* static */ - private static const _requiredTraits:Vector. = new Vector.; - _requiredTraits[0] = MediaTraitType.AUDIO; - } -} +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.events.MouseEvent; + + import org.osmf.chrome.widgets.ButtonWidget; + import org.osmf.events.AudioEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.AudioTrait; + import org.osmf.traits.MediaTraitType; + + public class SoundMoreButton extends ButtonWidget + { + // Overrides + // + + override protected function get requiredTraits():Vector. + { + return _requiredTraits; + } + + override protected function processRequiredTraitsAvailable(element:MediaElement):void + { + visible = true; + audible = element.getTrait(MediaTraitType.AUDIO) as AudioTrait; + if (audible) + { + audible.addEventListener(AudioEvent.VOLUME_CHANGE, onVolumeChange); + } + onVolumeChange(); + } + + override protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + visible = false; + if (audible) + { + audible.removeEventListener(AudioEvent.VOLUME_CHANGE, onVolumeChange); + audible = null; + } + } + + override protected function onMouseClick(event:MouseEvent):void + { + if (audible) + { + audible.volume = Math.min(1, audible.volume + 0.2); + } + } + + // Internals + // + + protected var audible:AudioTrait; + + protected function onVolumeChange(event:AudioEvent = null):void + { + enabled = audible ? audible.volume != 1 : false; + } + + /* static */ + private static const _requiredTraits:Vector. = new Vector.; + _requiredTraits[0] = MediaTraitType.AUDIO; + } +} diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/StopButton.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/StopButton.as index 87ac8bf..1492a76 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/StopButton.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/StopButton.as @@ -1,58 +1,58 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.Event; - import flash.events.MouseEvent; - - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - - public class StopButton extends PlayableButton - { - // Overrides - // - - override protected function onMouseClick(event:MouseEvent):void - { - var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; - playable.stop(); - - // On stop being invoked, rewind manually. NOTE: this is a work-around - // for the PlayTrait currently not doing so automatically. See bug report - // FM-350. - var seekable:SeekTrait = media.getTrait(MediaTraitType.SEEK) as SeekTrait; - if (seekable && seekable.canSeekTo(0)) - { - seekable.seek(0); - } - } - - override protected function visibilityDeterminingEventHandler(event:Event = null):void - { - visible = playable && playable.playState != PlayState.STOPPED; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.Event; + import flash.events.MouseEvent; + + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + + public class StopButton extends PlayableButton + { + // Overrides + // + + override protected function onMouseClick(event:MouseEvent):void + { + var playable:PlayTrait = media.getTrait(MediaTraitType.PLAY) as PlayTrait; + playable.stop(); + + // On stop being invoked, rewind manually. NOTE: this is a work-around + // for the PlayTrait currently not doing so automatically. See bug report + // FM-350. + var seekable:SeekTrait = media.getTrait(MediaTraitType.SEEK) as SeekTrait; + if (seekable && seekable.canSeekTo(0)) + { + seekable.seek(0); + } + } + + override protected function visibilityDeterminingEventHandler(event:Event = null):void + { + visible = playable && playable.playState != PlayState.STOPPED; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/URLInput.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/URLInput.as index 4fe7bf9..73c514a 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/URLInput.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/URLInput.as @@ -1,129 +1,129 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import flash.events.Event; - import flash.events.KeyboardEvent; - import flash.text.TextField; - import flash.text.TextFieldType; - import flash.text.TextFormat; - - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.assets.FontAsset; - import org.osmf.media.MediaElement; - - [Event(name="change", type="flash.events.Change")]; - - public class URLInput extends Widget - { - public function URLInput() - { - label = new TextField(); - addChild(label); - - input = new TextField(); - input.type = TextFieldType.INPUT; - input.selectable = true; - input.background = true; - - input.addEventListener(KeyboardEvent.KEY_DOWN, onInputKeyDown); - addChild(input); - - super(); - } - - public function set url(value:String):void - { - input.text = value; - focus(); - } - public function get url():String - { - return input.text; - } - - public function focus():void - { - if (visible && stage) - { - stage.focus = input; - } - input.setSelection(0, input.text.length); - } - - // Overrides - // - - override public function configure(xml:XML, assetManager:AssetsManager):void - { - super.configure(xml, assetManager); - - var fontId:String = xml.@font || "defaultFont"; - var fontAsset:FontAsset = assetManager.getAsset(fontId) as FontAsset; - var format:TextFormat = fontAsset.format; - format.color = parseInt(xml.@textColor || format.color.toString()); - - label.defaultTextFormat = format; - label.embedFonts = true; - label.selectable = false; - label.height = 20; - label.alpha = 0.4; - label.y = 6; - label.text = String(parseAttribute(xml, "title", "MEDIA URL:")); - - input.defaultTextFormat = format; - input.embedFonts = true; - input.backgroundColor = 0x808080; - input.height = 16; - input.alpha = 0.8; - input.x = 2; - input.y = 21; - } - - override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void - { - label.width = availableWidth; - input.width = availableWidth - input.x * 2; - } - - override protected function processMediaElementChange(oldElement:MediaElement):void - { - visible = media == null; - focus(); - } - - // Internals - // - - private function onInputKeyDown(event:KeyboardEvent):void - { - if (event.keyCode == 13 /*enter*/) - { - dispatchEvent(new Event(Event.CHANGE)); - } - } - - private var label:TextField; - private var input:TextField; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import flash.events.Event; + import flash.events.KeyboardEvent; + import flash.text.TextField; + import flash.text.TextFieldType; + import flash.text.TextFormat; + + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.assets.FontAsset; + import org.osmf.media.MediaElement; + + [Event(name="change", type="flash.events.Change")]; + + public class URLInput extends Widget + { + public function URLInput() + { + label = new TextField(); + addChild(label); + + input = new TextField(); + input.type = TextFieldType.INPUT; + input.selectable = true; + input.background = true; + + input.addEventListener(KeyboardEvent.KEY_DOWN, onInputKeyDown); + addChild(input); + + super(); + } + + public function set url(value:String):void + { + input.text = value; + focus(); + } + public function get url():String + { + return input.text; + } + + public function focus():void + { + if (visible && stage) + { + stage.focus = input; + } + input.setSelection(0, input.text.length); + } + + // Overrides + // + + override public function configure(xml:XML, assetManager:AssetsManager):void + { + super.configure(xml, assetManager); + + var fontId:String = xml.@font || "defaultFont"; + var fontAsset:FontAsset = assetManager.getAsset(fontId) as FontAsset; + var format:TextFormat = fontAsset.format; + format.color = parseInt(xml.@textColor || format.color.toString()); + + label.defaultTextFormat = format; + label.embedFonts = true; + label.selectable = false; + label.height = 20; + label.alpha = 0.4; + label.y = 6; + label.text = String(parseAttribute(xml, "title", "MEDIA URL:")); + + input.defaultTextFormat = format; + input.embedFonts = true; + input.backgroundColor = 0x808080; + input.height = 16; + input.alpha = 0.8; + input.x = 2; + input.y = 21; + } + + override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void + { + label.width = availableWidth; + input.width = availableWidth - input.x * 2; + } + + override protected function processMediaElementChange(oldElement:MediaElement):void + { + visible = media == null; + focus(); + } + + // Internals + // + + private function onInputKeyDown(event:KeyboardEvent):void + { + if (event.keyCode == 13 /*enter*/) + { + dispatchEvent(new Event(Event.CHANGE)); + } + } + + private var label:TextField; + private var input:TextField; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/Widget.as b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/Widget.as index 65d607f..5300365 100644 --- a/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/Widget.as +++ b/lib/osmf/samples/ChromeLibrary/src/org/osmf/chrome/widgets/Widget.as @@ -1,431 +1,431 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.chrome.widgets -{ - import __AS3__.vec.Vector; - - import flash.display.DisplayObject; - import flash.display.Sprite; - import flash.events.MouseEvent; - - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.configuration.LayoutAttributesParser; - import org.osmf.chrome.hint.Hint; - import org.osmf.events.MediaElementEvent; - import org.osmf.layout.LayoutRenderer; - import org.osmf.layout.LayoutRendererBase; - import org.osmf.layout.LayoutTargetEvent; - import org.osmf.media.MediaElement; - - public class Widget extends FadingLayoutTargetSprite - { - public function Widget() - { - super(); - - children = new Vector.(); - } - - public function configure(xml:XML, assetManager:AssetsManager):void - { - _configuration = xml; - _assetManager = assetManager; - - _id = String(xml.@id || ""); - fadeSteps = parseInt(xml.@fadeSteps || "0"); - face = assetManager.getDisplayObject(xml.@face) || new Sprite(); - enabled = String(xml.@enabled || "").toLocaleLowerCase() != "false"; - hint = xml.@hint != undefined ? xml.@hint : null; - - LayoutAttributesParser.parse(xml, layoutMetadata); - } - - public function get configuration():XML - { - return _configuration; - } - - public function get assetManager():AssetsManager - { - return _assetManager; - } - - public function get id():String - { - return _id; - } - - public function set media(value:MediaElement):void - { - if (_media != value) - { - var oldValue:MediaElement = _media; - _media = null; - - if (oldValue) - { - oldValue.removeEventListener(MediaElementEvent.TRAIT_ADD, onMediaElementTraitsChange); - oldValue.removeEventListener(MediaElementEvent.TRAIT_REMOVE, onMediaElementTraitsChange); - onMediaElementTraitsChange(null); - } - - _media = value; - - if (_media) - { - _media.addEventListener(MediaElementEvent.TRAIT_ADD, onMediaElementTraitsChange); - _media.addEventListener(MediaElementEvent.TRAIT_REMOVE, onMediaElementTraitsChange); - } - - for each (var child:Widget in children) - { - child.media = _media; - } - - processMediaElementChange(oldValue); - onMediaElementTraitsChange(null); - } - } - - public function get media():MediaElement - { - return _media; - } - - public function set face(value:DisplayObject):void - { - if (value != _face) - { - if (_face) - { - removeChild(_face); - } - _face = value; - if (_face) - { - addChildAt(_face, 0); - } - - measure(); - } - } - - public function set enabled(value:Boolean):void - { - if (_enabled != value) - { - _enabled = value; - processEnabledChange(); - } - } - - public function get enabled():Boolean - { - return _enabled; - } - - public function addChildWidget(widget:Widget):void - { - if (layoutRenderer == null) - { - layoutRenderer = constructLayoutRenderer(); - if (layoutRenderer) - { - layoutRenderer.container = this; - } - } - - if (layoutRenderer != null) - { - layoutRenderer.addTarget(widget); - children.push(widget); - widget.media = _media; - } - } - - public function removeChildWidget(widget:Widget):void - { - if (layoutRenderer && layoutRenderer.hasTarget(widget)) - { - layoutRenderer.removeTarget(widget); - children.splice(children.indexOf(widget), 1); - } - } - - public function getChildWidget(id:String):Widget - { - var result:Widget - - for each (var child:Widget in children) - { - if (child.id && child.id.toLowerCase() == id.toLocaleLowerCase()) - { - result = child; - break; - } - } - - return result; - } - - public function set hint(value:String):void - { - if (value != _hint) - { - if (_hint == null) - { - addEventListener(MouseEvent.ROLL_OVER, onRollOver); - addEventListener(MouseEvent.ROLL_OUT, onRollOut); - } - - if ( stage - && _hint - && _hint != "" - && Hint.getInstance(stage, _assetManager).text == _hint - ) - { - Hint.getInstance(stage, _assetManager).text = value; - } - - _hint = value; - - if (_hint == null) - { - removeEventListener(MouseEvent.ROLL_OVER, onRollOver); - removeEventListener(MouseEvent.ROLL_OUT, onRollOut); - } - } - } - - public function get hint():String - { - return _hint; - } - - // Overrides - // - - override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void - { - if (_face) - { - _face.width = availableWidth / scaleX; - _face.height = availableHeight / scaleY; - } - super.layout(availableWidth, availableHeight, deep); - } - - override public function set width(value:Number):void - { - if (_face) - { - _face.width = value / scaleX; - } - super.width = value; - } - - override public function set height(value:Number):void - { - if (_face) - { - _face.height = value / scaleY; - } - super.height = value; - } - - override protected function onAddChildAt(event:LayoutTargetEvent):void - { - event = new LayoutTargetEvent - ( event.type - , event.bubbles - , event.cancelable - , event.layoutRenderer - , event.layoutTarget - , event.displayObject - , event.index == -1 ? -1 : event.index + 1 - ); - super.onAddChildAt(event); - } - - override protected function onRemoveChild(event:LayoutTargetEvent):void - { - event = new LayoutTargetEvent - ( event.type - , event.bubbles - , event.cancelable - , event.layoutRenderer - , event.layoutTarget - , event.displayObject - , event.index == -1 ? -1 : event.index + 1 - ); - super.onRemoveChild(event); - } - - override protected function onSetChildIndex(event:LayoutTargetEvent):void - { - event = new LayoutTargetEvent - ( event.type - , event.bubbles - , event.cancelable - , event.layoutRenderer - , event.layoutTarget - , event.displayObject - , event.index == -1 ? -1 : event.index + 1 - ); - super.onSetChildIndex(event); - } - - override protected function setSuperVisible(value:Boolean):void - { - super.setSuperVisible(value); - layoutMetadata.includeInLayout = value && (configuration ? configuration.@includeInLayout != "false" : true); - } - - // Stubs - // - - protected function constructLayoutRenderer():LayoutRendererBase - { - return new LayoutRenderer(); - } - - protected function processEnabledChange():void - { - } - - protected function processMediaElementChange(oldMediaElement:MediaElement):void - { - } - - protected function onMediaElementTraitAdd(event:MediaElementEvent):void - { - } - - protected function onMediaElementTraitRemove(event:MediaElementEvent):void - { - } - - protected function processRequiredTraitsAvailable(element:MediaElement):void - { - } - - protected function processRequiredTraitsUnavailable(element:MediaElement):void - { - } - - protected function get requiredTraits():Vector. - { - return null; - } - - // Internals - // - - private var _media:MediaElement; - - private var _configuration:XML; - private var _assetManager:AssetsManager; - private var _id:String; - private var _enabled:Boolean; - private var _hint:String; - - private var _face:DisplayObject; - private var layoutRenderer:LayoutRendererBase; - - private var children:Vector.; - - private var _requiredTraitsAvailable:Boolean; - - private function onRollOver(event:MouseEvent):void - { - Hint.getInstance(stage, assetManager).text = _hint; - } - - private function onRollOut(event:MouseEvent):void - { - Hint.getInstance(stage, assetManager).text = null; - } - - private function onMediaElementTraitsChange(event:MediaElementEvent = null):void - { - var element:MediaElement - = event - ? event.target as MediaElement - : _media; - - var priorRequiredTraitsAvailable:Boolean = _requiredTraitsAvailable; - - if (element) - { - _requiredTraitsAvailable = true; - for each (var type:String in requiredTraits) - { - if (element.hasTrait(type) == false) - { - _requiredTraitsAvailable = false; - break; - } - } - } - else - { - _requiredTraitsAvailable = false; - } - - if ( event == null // always invoke handlers, if change is not event driven. - || _requiredTraitsAvailable != priorRequiredTraitsAvailable - ) - { - _requiredTraitsAvailable - ? processRequiredTraitsAvailable(element) - : processRequiredTraitsUnavailable(element); - } - - if (event) - { - event.type == MediaElementEvent.TRAIT_ADD - ? onMediaElementTraitAdd(event) - : onMediaElementTraitRemove(event); - } - } - - // Utils - // - - protected function parseAttribute(xml:XML, attributeName:String, defaultValue:*):* - { - var result:*; - - if (xml.@[attributeName] == undefined) - { - result = defaultValue; - } - else - { - result = xml.@[attributeName]; - } - - return result; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.chrome.widgets +{ + import __AS3__.vec.Vector; + + import flash.display.DisplayObject; + import flash.display.Sprite; + import flash.events.MouseEvent; + + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.configuration.LayoutAttributesParser; + import org.osmf.chrome.hint.Hint; + import org.osmf.events.MediaElementEvent; + import org.osmf.layout.LayoutRenderer; + import org.osmf.layout.LayoutRendererBase; + import org.osmf.layout.LayoutTargetEvent; + import org.osmf.media.MediaElement; + + public class Widget extends FadingLayoutTargetSprite + { + public function Widget() + { + super(); + + children = new Vector.(); + } + + public function configure(xml:XML, assetManager:AssetsManager):void + { + _configuration = xml; + _assetManager = assetManager; + + _id = String(xml.@id || ""); + fadeSteps = parseInt(xml.@fadeSteps || "0"); + face = assetManager.getDisplayObject(xml.@face) || new Sprite(); + enabled = String(xml.@enabled || "").toLocaleLowerCase() != "false"; + hint = xml.@hint != undefined ? xml.@hint : null; + + LayoutAttributesParser.parse(xml, layoutMetadata); + } + + public function get configuration():XML + { + return _configuration; + } + + public function get assetManager():AssetsManager + { + return _assetManager; + } + + public function get id():String + { + return _id; + } + + public function set media(value:MediaElement):void + { + if (_media != value) + { + var oldValue:MediaElement = _media; + _media = null; + + if (oldValue) + { + oldValue.removeEventListener(MediaElementEvent.TRAIT_ADD, onMediaElementTraitsChange); + oldValue.removeEventListener(MediaElementEvent.TRAIT_REMOVE, onMediaElementTraitsChange); + onMediaElementTraitsChange(null); + } + + _media = value; + + if (_media) + { + _media.addEventListener(MediaElementEvent.TRAIT_ADD, onMediaElementTraitsChange); + _media.addEventListener(MediaElementEvent.TRAIT_REMOVE, onMediaElementTraitsChange); + } + + for each (var child:Widget in children) + { + child.media = _media; + } + + processMediaElementChange(oldValue); + onMediaElementTraitsChange(null); + } + } + + public function get media():MediaElement + { + return _media; + } + + public function set face(value:DisplayObject):void + { + if (value != _face) + { + if (_face) + { + removeChild(_face); + } + _face = value; + if (_face) + { + addChildAt(_face, 0); + } + + measure(); + } + } + + public function set enabled(value:Boolean):void + { + if (_enabled != value) + { + _enabled = value; + processEnabledChange(); + } + } + + public function get enabled():Boolean + { + return _enabled; + } + + public function addChildWidget(widget:Widget):void + { + if (layoutRenderer == null) + { + layoutRenderer = constructLayoutRenderer(); + if (layoutRenderer) + { + layoutRenderer.container = this; + } + } + + if (layoutRenderer != null) + { + layoutRenderer.addTarget(widget); + children.push(widget); + widget.media = _media; + } + } + + public function removeChildWidget(widget:Widget):void + { + if (layoutRenderer && layoutRenderer.hasTarget(widget)) + { + layoutRenderer.removeTarget(widget); + children.splice(children.indexOf(widget), 1); + } + } + + public function getChildWidget(id:String):Widget + { + var result:Widget + + for each (var child:Widget in children) + { + if (child.id && child.id.toLowerCase() == id.toLocaleLowerCase()) + { + result = child; + break; + } + } + + return result; + } + + public function set hint(value:String):void + { + if (value != _hint) + { + if (_hint == null) + { + addEventListener(MouseEvent.ROLL_OVER, onRollOver); + addEventListener(MouseEvent.ROLL_OUT, onRollOut); + } + + if ( stage + && _hint + && _hint != "" + && Hint.getInstance(stage, _assetManager).text == _hint + ) + { + Hint.getInstance(stage, _assetManager).text = value; + } + + _hint = value; + + if (_hint == null) + { + removeEventListener(MouseEvent.ROLL_OVER, onRollOver); + removeEventListener(MouseEvent.ROLL_OUT, onRollOut); + } + } + } + + public function get hint():String + { + return _hint; + } + + // Overrides + // + + override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void + { + if (_face) + { + _face.width = availableWidth / scaleX; + _face.height = availableHeight / scaleY; + } + super.layout(availableWidth, availableHeight, deep); + } + + override public function set width(value:Number):void + { + if (_face) + { + _face.width = value / scaleX; + } + super.width = value; + } + + override public function set height(value:Number):void + { + if (_face) + { + _face.height = value / scaleY; + } + super.height = value; + } + + override protected function onAddChildAt(event:LayoutTargetEvent):void + { + event = new LayoutTargetEvent + ( event.type + , event.bubbles + , event.cancelable + , event.layoutRenderer + , event.layoutTarget + , event.displayObject + , event.index == -1 ? -1 : event.index + 1 + ); + super.onAddChildAt(event); + } + + override protected function onRemoveChild(event:LayoutTargetEvent):void + { + event = new LayoutTargetEvent + ( event.type + , event.bubbles + , event.cancelable + , event.layoutRenderer + , event.layoutTarget + , event.displayObject + , event.index == -1 ? -1 : event.index + 1 + ); + super.onRemoveChild(event); + } + + override protected function onSetChildIndex(event:LayoutTargetEvent):void + { + event = new LayoutTargetEvent + ( event.type + , event.bubbles + , event.cancelable + , event.layoutRenderer + , event.layoutTarget + , event.displayObject + , event.index == -1 ? -1 : event.index + 1 + ); + super.onSetChildIndex(event); + } + + override protected function setSuperVisible(value:Boolean):void + { + super.setSuperVisible(value); + layoutMetadata.includeInLayout = value && (configuration ? configuration.@includeInLayout != "false" : true); + } + + // Stubs + // + + protected function constructLayoutRenderer():LayoutRendererBase + { + return new LayoutRenderer(); + } + + protected function processEnabledChange():void + { + } + + protected function processMediaElementChange(oldMediaElement:MediaElement):void + { + } + + protected function onMediaElementTraitAdd(event:MediaElementEvent):void + { + } + + protected function onMediaElementTraitRemove(event:MediaElementEvent):void + { + } + + protected function processRequiredTraitsAvailable(element:MediaElement):void + { + } + + protected function processRequiredTraitsUnavailable(element:MediaElement):void + { + } + + protected function get requiredTraits():Vector. + { + return null; + } + + // Internals + // + + private var _media:MediaElement; + + private var _configuration:XML; + private var _assetManager:AssetsManager; + private var _id:String; + private var _enabled:Boolean; + private var _hint:String; + + private var _face:DisplayObject; + private var layoutRenderer:LayoutRendererBase; + + private var children:Vector.; + + private var _requiredTraitsAvailable:Boolean; + + private function onRollOver(event:MouseEvent):void + { + Hint.getInstance(stage, assetManager).text = _hint; + } + + private function onRollOut(event:MouseEvent):void + { + Hint.getInstance(stage, assetManager).text = null; + } + + private function onMediaElementTraitsChange(event:MediaElementEvent = null):void + { + var element:MediaElement + = event + ? event.target as MediaElement + : _media; + + var priorRequiredTraitsAvailable:Boolean = _requiredTraitsAvailable; + + if (element) + { + _requiredTraitsAvailable = true; + for each (var type:String in requiredTraits) + { + if (element.hasTrait(type) == false) + { + _requiredTraitsAvailable = false; + break; + } + } + } + else + { + _requiredTraitsAvailable = false; + } + + if ( event == null // always invoke handlers, if change is not event driven. + || _requiredTraitsAvailable != priorRequiredTraitsAvailable + ) + { + _requiredTraitsAvailable + ? processRequiredTraitsAvailable(element) + : processRequiredTraitsUnavailable(element); + } + + if (event) + { + event.type == MediaElementEvent.TRAIT_ADD + ? onMediaElementTraitAdd(event) + : onMediaElementTraitRemove(event); + } + } + + // Utils + // + + protected function parseAttribute(xml:XML, attributeName:String, defaultValue:*):* + { + var result:*; + + if (xml.@[attributeName] == undefined) + { + result = defaultValue; + } + else + { + result = xml.@[attributeName]; + } + + return result; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ControlBarPlugin/.actionScriptProperties b/lib/osmf/samples/ControlBarPlugin/.actionScriptProperties index cb0709f..63088c8 100644 --- a/lib/osmf/samples/ControlBarPlugin/.actionScriptProperties +++ b/lib/osmf/samples/ControlBarPlugin/.actionScriptProperties @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/ControlBarPlugin/ControlBarPlugin-build-config.xml b/lib/osmf/samples/ControlBarPlugin/ControlBarPlugin-build-config.xml index 0d678f6..8d53afd 100644 --- a/lib/osmf/samples/ControlBarPlugin/ControlBarPlugin-build-config.xml +++ b/lib/osmf/samples/ControlBarPlugin/ControlBarPlugin-build-config.xml @@ -24,18 +24,18 @@ - false - @@ -93,11 +93,11 @@ - @@ -105,8 +105,8 @@ - @@ -124,13 +124,13 @@ - @@ -139,11 +139,11 @@ flash.fonts.AFEFontManager flash.fonts.BatikFontManager - @@ -237,28 +237,28 @@ false - - - true - - true diff --git a/lib/osmf/samples/ControlBarPlugin/assets/configuration.xml b/lib/osmf/samples/ControlBarPlugin/assets/configuration.xml index ee08375..4965dee 100644 --- a/lib/osmf/samples/ControlBarPlugin/assets/configuration.xml +++ b/lib/osmf/samples/ControlBarPlugin/assets/configuration.xml @@ -1,79 +1,79 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/osmf/samples/ControlBarPlugin/src/ControlBarElement.as b/lib/osmf/samples/ControlBarPlugin/src/ControlBarElement.as index 456d592..0fc7644 100644 --- a/lib/osmf/samples/ControlBarPlugin/src/ControlBarElement.as +++ b/lib/osmf/samples/ControlBarPlugin/src/ControlBarElement.as @@ -1,190 +1,190 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import org.osmf.chrome.assets.AssetsManager; - import org.osmf.chrome.configuration.LayoutAttributesParser; - import org.osmf.chrome.configuration.WidgetsParser; - import org.osmf.chrome.widgets.Widget; - import org.osmf.layout.LayoutMetadata; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaResourceBase; - import org.osmf.metadata.Metadata; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.MediaTraitType; - - public class ControlBarElement extends MediaElement - { - // Embedded assets (see configuration.xml for their assignments): - // - - [Embed(source="../assets/configuration.xml", mimeType="application/octet-stream")] - private static const CONFIGURATION_XML:Class; - - [Embed(source="../assets/Standard0755.swf#Standard0755")] - private static const DEFAULT_FONT:Class; - - [Embed(source="../assets/backDrop.png")] - private static const BACKDROP:Class; - - [Embed(source="../assets/pause_disabled.png")] - private static const PAUSE_DISABLED:Class; - [Embed(source="../assets/pause_up.png")] - private static const PAUSE_UP:Class; - [Embed(source="../assets/pause_down.png")] - private static const PAUSE_DOWN:Class; - - [Embed(source="../assets/stop_disabled.png")] - private static const STOP_DISABLED:Class; - [Embed(source="../assets/stop_up.png")] - private static const STOP_UP:Class; - [Embed(source="../assets/stop_down.png")] - private static const STOP_DOWN:Class; - - [Embed(source="../assets/play_disabled.png")] - private static const PLAY_DISABLED:Class; - [Embed(source="../assets/play_up.png")] - private static const PLAY_UP:Class; - [Embed(source="../assets/play_down.png")] - private static const PLAY_DOWN:Class; - - [Embed(source="../assets/scrubber_disabled.png")] - private static const SCRUBBER_DISABLED:Class; - [Embed(source="../assets/scrubber_up.png")] - private static const SCRUBBER_UP:Class; - [Embed(source="../assets/scrubber_down.png")] - private static const SCRUBBER_DOWN:Class; - [Embed(source="../assets/scrubBarTrack.png")] - private static const SCRUB_BAR_TRACK:Class; - - // Public interface - // - - public function addReference(target:MediaElement):void - { - if (this.target == null) - { - this.target = target; - - processTarget(); - } - } - - private function processTarget():void - { - if (target != null && settings != null) - { - // We use the NS_CONTROL_BAR_TARGET namespaced metadata in order - // to find out if the instantiated element is the element that our - // control bar should control: - var targetMetadata:Metadata = target.getMetadata(ControlBarPlugin.NS_CONTROL_BAR_TARGET); - if (targetMetadata) - { - if ( targetMetadata.getValue(ID) != null - && targetMetadata.getValue(ID) == settings.getValue(ID) - ) - { - controlBar.media = target; - } - } - } - } - - // Overrides - // - - override public function set resource(value:MediaResourceBase):void - { - // Right after the media factory has instantiated us, it will set the - // resource that it used to do so. We look the NS_CONTROL_BAR_SETTINGS - // namespaced metadata, and retain it as our settings record - // (containing only one field: "ID" that tells us the ID of the media - // element that we should be controlling): - if (value != null) - { - settings - = value.getMetadataValue(ControlBarPlugin.NS_CONTROL_BAR_SETTINGS) as Metadata; - - processTarget(); - } - - super.resource = value; - } - - override protected function setupTraits():void - { - // Setup a control bar using the ChromeLibrary: - setupControlBar(); - - // Use the control bar's layout metadata as the element's layout metadata: - var layoutMetadata:LayoutMetadata = new LayoutMetadata(); - LayoutAttributesParser.parse(controlBar.configuration, layoutMetadata); - addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); - - // Signal that this media element is viewable: create a DisplayObjectTrait. - // Assign controlBar (which is a Sprite) to be our view's displayObject. - // Additionally, use its current width and height for the trait's mediaWidth - // and mediaHeight properties: - viewable = new DisplayObjectTrait(controlBar, controlBar.measuredWidth, controlBar.measuredHeight); - // Add the trait: - addTrait(MediaTraitType.DISPLAY_OBJECT, viewable); - - controlBar.measure(); - - super.setupTraits(); - } - - // Internals - // - - private function setupControlBar():void - { - try - { - var configuration:XML = XML(new CONFIGURATION_XML()); - - var assetsManager:AssetsManager = new AssetsManager(); - assetsManager.addConfigurationAssets(configuration); - assetsManager.load(); - - var widgetsParser:WidgetsParser = new WidgetsParser() - widgetsParser.parse(configuration.widgets.*, assetsManager); - - controlBar = widgetsParser.getWidget("controlBar"); - } - catch (error:Error) - { - trace("WARNING: failed setting up control bar:", error.message); - } - } - - private var settings:Metadata; - - private var target:MediaElement; - private var controlBar:Widget; - private var viewable:DisplayObjectTrait; - - /* static */ - - private static const ID:String = "ID"; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import org.osmf.chrome.assets.AssetsManager; + import org.osmf.chrome.configuration.LayoutAttributesParser; + import org.osmf.chrome.configuration.WidgetsParser; + import org.osmf.chrome.widgets.Widget; + import org.osmf.layout.LayoutMetadata; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaResourceBase; + import org.osmf.metadata.Metadata; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.MediaTraitType; + + public class ControlBarElement extends MediaElement + { + // Embedded assets (see configuration.xml for their assignments): + // + + [Embed(source="../assets/configuration.xml", mimeType="application/octet-stream")] + private static const CONFIGURATION_XML:Class; + + [Embed(source="../assets/Standard0755.swf#Standard0755")] + private static const DEFAULT_FONT:Class; + + [Embed(source="../assets/backDrop.png")] + private static const BACKDROP:Class; + + [Embed(source="../assets/pause_disabled.png")] + private static const PAUSE_DISABLED:Class; + [Embed(source="../assets/pause_up.png")] + private static const PAUSE_UP:Class; + [Embed(source="../assets/pause_down.png")] + private static const PAUSE_DOWN:Class; + + [Embed(source="../assets/stop_disabled.png")] + private static const STOP_DISABLED:Class; + [Embed(source="../assets/stop_up.png")] + private static const STOP_UP:Class; + [Embed(source="../assets/stop_down.png")] + private static const STOP_DOWN:Class; + + [Embed(source="../assets/play_disabled.png")] + private static const PLAY_DISABLED:Class; + [Embed(source="../assets/play_up.png")] + private static const PLAY_UP:Class; + [Embed(source="../assets/play_down.png")] + private static const PLAY_DOWN:Class; + + [Embed(source="../assets/scrubber_disabled.png")] + private static const SCRUBBER_DISABLED:Class; + [Embed(source="../assets/scrubber_up.png")] + private static const SCRUBBER_UP:Class; + [Embed(source="../assets/scrubber_down.png")] + private static const SCRUBBER_DOWN:Class; + [Embed(source="../assets/scrubBarTrack.png")] + private static const SCRUB_BAR_TRACK:Class; + + // Public interface + // + + public function addReference(target:MediaElement):void + { + if (this.target == null) + { + this.target = target; + + processTarget(); + } + } + + private function processTarget():void + { + if (target != null && settings != null) + { + // We use the NS_CONTROL_BAR_TARGET namespaced metadata in order + // to find out if the instantiated element is the element that our + // control bar should control: + var targetMetadata:Metadata = target.getMetadata(ControlBarPlugin.NS_CONTROL_BAR_TARGET); + if (targetMetadata) + { + if ( targetMetadata.getValue(ID) != null + && targetMetadata.getValue(ID) == settings.getValue(ID) + ) + { + controlBar.media = target; + } + } + } + } + + // Overrides + // + + override public function set resource(value:MediaResourceBase):void + { + // Right after the media factory has instantiated us, it will set the + // resource that it used to do so. We look the NS_CONTROL_BAR_SETTINGS + // namespaced metadata, and retain it as our settings record + // (containing only one field: "ID" that tells us the ID of the media + // element that we should be controlling): + if (value != null) + { + settings + = value.getMetadataValue(ControlBarPlugin.NS_CONTROL_BAR_SETTINGS) as Metadata; + + processTarget(); + } + + super.resource = value; + } + + override protected function setupTraits():void + { + // Setup a control bar using the ChromeLibrary: + setupControlBar(); + + // Use the control bar's layout metadata as the element's layout metadata: + var layoutMetadata:LayoutMetadata = new LayoutMetadata(); + LayoutAttributesParser.parse(controlBar.configuration, layoutMetadata); + addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); + + // Signal that this media element is viewable: create a DisplayObjectTrait. + // Assign controlBar (which is a Sprite) to be our view's displayObject. + // Additionally, use its current width and height for the trait's mediaWidth + // and mediaHeight properties: + viewable = new DisplayObjectTrait(controlBar, controlBar.measuredWidth, controlBar.measuredHeight); + // Add the trait: + addTrait(MediaTraitType.DISPLAY_OBJECT, viewable); + + controlBar.measure(); + + super.setupTraits(); + } + + // Internals + // + + private function setupControlBar():void + { + try + { + var configuration:XML = XML(new CONFIGURATION_XML()); + + var assetsManager:AssetsManager = new AssetsManager(); + assetsManager.addConfigurationAssets(configuration); + assetsManager.load(); + + var widgetsParser:WidgetsParser = new WidgetsParser() + widgetsParser.parse(configuration.widgets.*, assetsManager); + + controlBar = widgetsParser.getWidget("controlBar"); + } + catch (error:Error) + { + trace("WARNING: failed setting up control bar:", error.message); + } + } + + private var settings:Metadata; + + private var target:MediaElement; + private var controlBar:Widget; + private var viewable:DisplayObjectTrait; + + /* static */ + + private static const ID:String = "ID"; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ControlBarPlugin/src/ControlBarPlugin.as b/lib/osmf/samples/ControlBarPlugin/src/ControlBarPlugin.as index df00ef8..9e2e9e1 100644 --- a/lib/osmf/samples/ControlBarPlugin/src/ControlBarPlugin.as +++ b/lib/osmf/samples/ControlBarPlugin/src/ControlBarPlugin.as @@ -1,123 +1,123 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import __AS3__.vec.Vector; - - import flash.display.Sprite; - import flash.system.Security; - - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.PluginInfo; - import org.osmf.metadata.Metadata; - - public class ControlBarPlugin extends Sprite - { - /** - * Constructor - */ - public function ControlBarPlugin() - { - // Allow any SWF that loads this SWF to access objects and - // variables in this SWF. - Security.allowDomain("*"); - - super(); - } - - /** - * Gives the player the PluginInfo. - */ - public function get pluginInfo():PluginInfo - { - if (_pluginInfo == null) - { - var item:MediaFactoryItem - = new MediaFactoryItem - ( ID - , canHandleResourceCallback - , mediaElementCreationCallback - ); - - var items:Vector. = new Vector.(); - items.push(item); - - _pluginInfo = new PluginInfo(items, mediaElementCreationNotificationCallback); - } - - return _pluginInfo; - } - - // Internals - // - - public static const ID:String = "org.osmf.samples.controlbar"; - public static const NS_CONTROL_BAR_SETTINGS:String = "http://www.osmf.org/samples/controlbar/settings"; - public static const NS_CONTROL_BAR_TARGET:String = "http://www.osmf.org/samples/controlbar/target"; - - private var _pluginInfo:PluginInfo; - private var controlBarElement:ControlBarElement; - private var targetElement:MediaElement; - - private function canHandleResourceCallback(resource:MediaResourceBase):Boolean - { - var result:Boolean; - - if (resource != null) - { - var settings:Metadata - = resource.getMetadataValue(NS_CONTROL_BAR_SETTINGS) as Metadata; - - result = settings != null; - } - - return result; - } - - private function mediaElementCreationCallback():MediaElement - { - controlBarElement = new ControlBarElement(); - - updateControls(); - - return controlBarElement; - } - - private function mediaElementCreationNotificationCallback(target:MediaElement):void - { - // If the control bar has been created, notify it about the just-created element. - targetElement = target; - - updateControls(); - } - - private function updateControls():void - { - if (controlBarElement != null && targetElement != null && controlBarElement != targetElement) - { - controlBarElement.addReference(targetElement); - } - } - } -} +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import __AS3__.vec.Vector; + + import flash.display.Sprite; + import flash.system.Security; + + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.PluginInfo; + import org.osmf.metadata.Metadata; + + public class ControlBarPlugin extends Sprite + { + /** + * Constructor + */ + public function ControlBarPlugin() + { + // Allow any SWF that loads this SWF to access objects and + // variables in this SWF. + Security.allowDomain("*"); + + super(); + } + + /** + * Gives the player the PluginInfo. + */ + public function get pluginInfo():PluginInfo + { + if (_pluginInfo == null) + { + var item:MediaFactoryItem + = new MediaFactoryItem + ( ID + , canHandleResourceCallback + , mediaElementCreationCallback + ); + + var items:Vector. = new Vector.(); + items.push(item); + + _pluginInfo = new PluginInfo(items, mediaElementCreationNotificationCallback); + } + + return _pluginInfo; + } + + // Internals + // + + public static const ID:String = "org.osmf.samples.controlbar"; + public static const NS_CONTROL_BAR_SETTINGS:String = "http://www.osmf.org/samples/controlbar/settings"; + public static const NS_CONTROL_BAR_TARGET:String = "http://www.osmf.org/samples/controlbar/target"; + + private var _pluginInfo:PluginInfo; + private var controlBarElement:ControlBarElement; + private var targetElement:MediaElement; + + private function canHandleResourceCallback(resource:MediaResourceBase):Boolean + { + var result:Boolean; + + if (resource != null) + { + var settings:Metadata + = resource.getMetadataValue(NS_CONTROL_BAR_SETTINGS) as Metadata; + + result = settings != null; + } + + return result; + } + + private function mediaElementCreationCallback():MediaElement + { + controlBarElement = new ControlBarElement(); + + updateControls(); + + return controlBarElement; + } + + private function mediaElementCreationNotificationCallback(target:MediaElement):void + { + // If the control bar has been created, notify it about the just-created element. + targetElement = target; + + updateControls(); + } + + private function updateControls():void + { + if (controlBarElement != null && targetElement != null && controlBarElement != targetElement) + { + controlBarElement.addReference(targetElement); + } + } + } +} diff --git a/lib/osmf/samples/ControlBarSample/.actionScriptProperties b/lib/osmf/samples/ControlBarSample/.actionScriptProperties index 3b175ce..9da9abb 100644 --- a/lib/osmf/samples/ControlBarSample/.actionScriptProperties +++ b/lib/osmf/samples/ControlBarSample/.actionScriptProperties @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/ControlBarSample/html-template/AC_OETags.js b/lib/osmf/samples/ControlBarSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/ControlBarSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/ControlBarSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/ControlBarSample/html-template/history/historyFrame.html b/lib/osmf/samples/ControlBarSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/ControlBarSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/ControlBarSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/ControlBarSample/html-template/index.template.html b/lib/osmf/samples/ControlBarSample/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/ControlBarSample/html-template/index.template.html +++ b/lib/osmf/samples/ControlBarSample/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/ControlBarSample/src/ControlBarSample.as b/lib/osmf/samples/ControlBarSample/src/ControlBarSample.as index 1288afb..2e2aee6 100644 --- a/lib/osmf/samples/ControlBarSample/src/ControlBarSample.as +++ b/lib/osmf/samples/ControlBarSample/src/ControlBarSample.as @@ -1,161 +1,161 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - - import org.osmf.elements.ParallelElement; - import org.osmf.events.MediaFactoryEvent; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.*; - import org.osmf.metadata.Metadata; - - [SWF(width="640", height="360", backgroundColor="0x000000",frameRate="25")] - public class ControlBarSample extends Sprite - { - public function ControlBarSample() - { - // Construct an OSMFConfiguration helper class: - osmf = new OSMFConfiguration(); - - // Construct the main element to play back. This will be a - // parallel element, that will hold the main content to - // playback, and the control bar (from a plug-in) as its - // children: - osmf.mediaElement = constructRootElement(); - osmf.view = this; - - // Add event listeners to the plug-in manager so we'll get - // a heads-up when the control bar plug-in finishes loading: - osmf.factory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); - osmf.factory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadError); - - // Ask the plug-in manager to load the control bar plug-in: - osmf.factory.loadPlugin(pluginResource); - } - - // Internals - // - - private var osmf:OSMFConfiguration; - private var rootElement:ParallelElement; - - private function onPluginLoaded(event:MediaFactoryEvent):void - { - // The plugin loaded successfully. We can now construct a control - // bar media element, and add it as a child to the root parallel - // element: - rootElement.addChild(constructControlBarElement()); - } - - private function onPluginLoadError(event:MediaFactoryEvent):void - { - trace("ERROR: the control bar plugin failed to load."); - } - - private function constructRootElement():MediaElement - { - // Construct a parallel media element to hold the main content, - // and later on, the control bar. - rootElement = new ParallelElement(); - rootElement.addChild(constructVideoElement()); - - // Use the layout api to set the parallel element's width and - // height. Make it as big as the stage currently is: - var rootElementLayout:LayoutMetadata = new LayoutMetadata(); - rootElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, rootElementLayout); - rootElementLayout.width = stage.stageWidth; - rootElementLayout.height = stage.stageHeight; - - return rootElement; - } - - private function constructVideoElement():MediaElement - { - // Construct a metadata object that we can append to the video's collection - // of metadata. The control bar plug-in will use the metadata to identify - // the video element as its target: - var controlBarTarget:Metadata = new Metadata(); - controlBarTarget.addValue(ID, "mainContent"); - - // Construct a video element: - var video:MediaElement = osmf.factory.createMediaElement(new URLResource(VIDEO_URL)); - - // Add the metadata to the video's metadata: - video.addMetadata(ControlBarPlugin.NS_CONTROL_BAR_TARGET, controlBarTarget); - - return video; - } - - private function constructControlBarElement():MediaElement - { - // Construct a metadata object that we'll send to the media factory on - // requesting a control bar element to be instantiated. The factory - // will use it to parameterize the element. Specifically, the ID field - // will tell the plug-in what the ID of the content it should control - // is: - var controlBarSettings:Metadata = new Metadata(); - controlBarSettings.addValue(ID, "mainContent"); - - // Add the metadata to an otherwise empty media resource object: - var resource:MediaResourceBase = new MediaResourceBase(); - resource.addMetadataValue(ControlBarPlugin.NS_CONTROL_BAR_SETTINGS, controlBarSettings); - - // Request the media factory to construct a control bar element. The - // factory will infer a control bar element is requested by inspecting - // the resource's metadata (and encountering a metadata object of namespace - // NS_CONTROL_BAR_SETTINGS there): - var controlBar:MediaElement = osmf.factory.createMediaElement(resource); - - // Set some layout properties on the control bar. Specifically, have it - // appear at the bottom of the parallel element, horizontally centererd: - var layout:LayoutMetadata = controlBar.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; - if (layout == null) - { - layout = new LayoutMetadata(); - controlBar.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - } - layout.verticalAlign = VerticalAlign.BOTTOM; - layout.horizontalAlign = HorizontalAlign.CENTER; - - // Make sure that the element shows over the video: element's with a - // higher order number set are placed higher in the display list: - layout.index = 1; - - return controlBar; - } - - /* static */ - - private static const VIDEO_URL:String - = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; - - private static var ID:String = "ID"; - - // Comment out to load the plug-in for a SWF (instead of using static linking, for testing): - //private static const pluginResource:URLResource = new URLResource("http://mediapm.edgesuite.net/osmf/swf/ControlBarPlugin.swf"); - - private static const pluginResource:PluginInfoResource = new PluginInfoResource(new ControlBarPlugin().pluginInfo); - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + + import org.osmf.elements.ParallelElement; + import org.osmf.events.MediaFactoryEvent; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.*; + import org.osmf.metadata.Metadata; + + [SWF(width="640", height="360", backgroundColor="0x000000",frameRate="25")] + public class ControlBarSample extends Sprite + { + public function ControlBarSample() + { + // Construct an OSMFConfiguration helper class: + osmf = new OSMFConfiguration(); + + // Construct the main element to play back. This will be a + // parallel element, that will hold the main content to + // playback, and the control bar (from a plug-in) as its + // children: + osmf.mediaElement = constructRootElement(); + osmf.view = this; + + // Add event listeners to the plug-in manager so we'll get + // a heads-up when the control bar plug-in finishes loading: + osmf.factory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); + osmf.factory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadError); + + // Ask the plug-in manager to load the control bar plug-in: + osmf.factory.loadPlugin(pluginResource); + } + + // Internals + // + + private var osmf:OSMFConfiguration; + private var rootElement:ParallelElement; + + private function onPluginLoaded(event:MediaFactoryEvent):void + { + // The plugin loaded successfully. We can now construct a control + // bar media element, and add it as a child to the root parallel + // element: + rootElement.addChild(constructControlBarElement()); + } + + private function onPluginLoadError(event:MediaFactoryEvent):void + { + trace("ERROR: the control bar plugin failed to load."); + } + + private function constructRootElement():MediaElement + { + // Construct a parallel media element to hold the main content, + // and later on, the control bar. + rootElement = new ParallelElement(); + rootElement.addChild(constructVideoElement()); + + // Use the layout api to set the parallel element's width and + // height. Make it as big as the stage currently is: + var rootElementLayout:LayoutMetadata = new LayoutMetadata(); + rootElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, rootElementLayout); + rootElementLayout.width = stage.stageWidth; + rootElementLayout.height = stage.stageHeight; + + return rootElement; + } + + private function constructVideoElement():MediaElement + { + // Construct a metadata object that we can append to the video's collection + // of metadata. The control bar plug-in will use the metadata to identify + // the video element as its target: + var controlBarTarget:Metadata = new Metadata(); + controlBarTarget.addValue(ID, "mainContent"); + + // Construct a video element: + var video:MediaElement = osmf.factory.createMediaElement(new URLResource(VIDEO_URL)); + + // Add the metadata to the video's metadata: + video.addMetadata(ControlBarPlugin.NS_CONTROL_BAR_TARGET, controlBarTarget); + + return video; + } + + private function constructControlBarElement():MediaElement + { + // Construct a metadata object that we'll send to the media factory on + // requesting a control bar element to be instantiated. The factory + // will use it to parameterize the element. Specifically, the ID field + // will tell the plug-in what the ID of the content it should control + // is: + var controlBarSettings:Metadata = new Metadata(); + controlBarSettings.addValue(ID, "mainContent"); + + // Add the metadata to an otherwise empty media resource object: + var resource:MediaResourceBase = new MediaResourceBase(); + resource.addMetadataValue(ControlBarPlugin.NS_CONTROL_BAR_SETTINGS, controlBarSettings); + + // Request the media factory to construct a control bar element. The + // factory will infer a control bar element is requested by inspecting + // the resource's metadata (and encountering a metadata object of namespace + // NS_CONTROL_BAR_SETTINGS there): + var controlBar:MediaElement = osmf.factory.createMediaElement(resource); + + // Set some layout properties on the control bar. Specifically, have it + // appear at the bottom of the parallel element, horizontally centererd: + var layout:LayoutMetadata = controlBar.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; + if (layout == null) + { + layout = new LayoutMetadata(); + controlBar.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + } + layout.verticalAlign = VerticalAlign.BOTTOM; + layout.horizontalAlign = HorizontalAlign.CENTER; + + // Make sure that the element shows over the video: element's with a + // higher order number set are placed higher in the display list: + layout.index = 1; + + return controlBar; + } + + /* static */ + + private static const VIDEO_URL:String + = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; + + private static var ID:String = "ID"; + + // Comment out to load the plug-in for a SWF (instead of using static linking, for testing): + //private static const pluginResource:URLResource = new URLResource("http://mediapm.edgesuite.net/osmf/swf/ControlBarPlugin.swf"); + + private static const pluginResource:PluginInfoResource = new PluginInfoResource(new ControlBarPlugin().pluginInfo); + } } \ No newline at end of file diff --git a/lib/osmf/samples/ControlBarSample/src/OSMFConfiguration.as b/lib/osmf/samples/ControlBarSample/src/OSMFConfiguration.as index e579c38..a72b05c 100644 --- a/lib/osmf/samples/ControlBarSample/src/OSMFConfiguration.as +++ b/lib/osmf/samples/ControlBarSample/src/OSMFConfiguration.as @@ -1,215 +1,215 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.DisplayObjectContainer; - - import org.osmf.containers.MediaContainer; - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaPlayer; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - - /** - * The Configuration class defines an object that simplifies setting up - * an OSMF configuration. The class implements the boiler plate code - * that is required to setup commonly used framework building blocks: - * - * MediaPlayer (accessible from the player property) - * MediaContainer (accessible from the container property) - * DefaultMediaFactory (accessible from the factory property) - * - * Furthermore, the object contains a 'view' property. When it is set, - * the object will add the constructed media container as a child to - * the designated DisplayObjectContainer. - * - * Last, the object allows for 3 ways of controlling the configuration's - * principle media element. - * - * At the highest level, a string can be passed to the url property. The - * configuration will construct a URL and URLResource. - * - * At mid-level, a MediaResourceBase typed object can be passed to the - * resource propery. - * - * When either the url or a resource property is set, the object will use - * its media factory to create a corresponding media element. The resulting - * element gets forwared to the internal player, and container instances. - * Alternatively, an existing media element can be assigned to the - * mediaElement property directly. This constitues the third, lowest level - * of controlling the configuration's principle media element. - */ - public class OSMFConfiguration - { - /** - * Constructor - */ - public function OSMFConfiguration() - { - _player = new MediaPlayer(); - _container = new MediaContainer(); - } - - /** - * Defines the url string that is used to construct the configuration's - * principle media element. - * - * On a url being set, a URLResource gets constructed and set on the - * object's resource property. - */ - public function set url(value:String):void - { - if (url != value) - { - resource = new URLResource(value); - } - } - public function get url():String - { - return _resource is URLResource - ? URLResource(_resource).url - : null; - } - - /** - * Defines the resource that is used to construct the configuration's - * principle media element. - * - * On a resource being set, the media factory is requested to create - * a media element for the resource. The resulting media element is set - * the configuration's mediaElement property. - */ - public function set resource(value:MediaResourceBase):void - { - _resource = value; - mediaElement = factory.createMediaElement(resource); - } - public function get resource():MediaResourceBase - { - return _resource; - } - - /** - * Defines the DisplayObjectContainer that will hold the configuration's - * media container. - * - * On a view being set, the configuration adds its media container to - * the designated view. - */ - public function set view(value:DisplayObjectContainer):void - { - if (_view) - { - _view.removeChild(_container); - } - _view = value; - if (_view) - { - _view.addChild(container); - } - } - public function get view():DisplayObjectContainer - { - return _view; - } - - /** - * Defines the configuration's current media element. - * - * On a media element being set, the configuration forwards the - * value to its player and container objects. - */ - public function set mediaElement(value:MediaElement):void - { - if (value != _mediaElement) - { - // Remove the current media element from the various - // components that use it: - if (_mediaElement) - { - _container.removeMediaElement(_mediaElement); - } - - // Set the new media element: - _mediaElement = value; - - // Add the newly set element to the various components - // that use it: - _player.media = _mediaElement; - if (_mediaElement) - { - _resource = _mediaElement.resource; - _container.addMediaElement(_mediaElement); - } - } - } - public function get mediaElement():MediaElement - { - return _mediaElement; - } - - /** - * Defines the configuration's container object. - */ - public function get container():MediaContainer - { - return _container; - } - - /** - * Defines the configuration's factory object. - */ - public function get factory():MediaFactory - { - if (_factory == null) - { - _factory = constructFactory(); - } - return _factory; - } - - // Subclass stubs - // - - /** - * Subclasses may override this method to construct an alternative - * media factory implementation to DefaultMediaFactory. - */ - protected function constructFactory():MediaFactory - { - return new DefaultMediaFactory(); - } - - // Internals - // - - private var _mediaElement:MediaElement; - private var _player:MediaPlayer; - private var _container:MediaContainer; - private var _factory:MediaFactory; - - private var _resource:MediaResourceBase; - private var _view:DisplayObjectContainer; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.DisplayObjectContainer; + + import org.osmf.containers.MediaContainer; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaPlayer; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + + /** + * The Configuration class defines an object that simplifies setting up + * an OSMF configuration. The class implements the boiler plate code + * that is required to setup commonly used framework building blocks: + * + * MediaPlayer (accessible from the player property) + * MediaContainer (accessible from the container property) + * DefaultMediaFactory (accessible from the factory property) + * + * Furthermore, the object contains a 'view' property. When it is set, + * the object will add the constructed media container as a child to + * the designated DisplayObjectContainer. + * + * Last, the object allows for 3 ways of controlling the configuration's + * principle media element. + * + * At the highest level, a string can be passed to the url property. The + * configuration will construct a URL and URLResource. + * + * At mid-level, a MediaResourceBase typed object can be passed to the + * resource propery. + * + * When either the url or a resource property is set, the object will use + * its media factory to create a corresponding media element. The resulting + * element gets forwared to the internal player, and container instances. + * Alternatively, an existing media element can be assigned to the + * mediaElement property directly. This constitues the third, lowest level + * of controlling the configuration's principle media element. + */ + public class OSMFConfiguration + { + /** + * Constructor + */ + public function OSMFConfiguration() + { + _player = new MediaPlayer(); + _container = new MediaContainer(); + } + + /** + * Defines the url string that is used to construct the configuration's + * principle media element. + * + * On a url being set, a URLResource gets constructed and set on the + * object's resource property. + */ + public function set url(value:String):void + { + if (url != value) + { + resource = new URLResource(value); + } + } + public function get url():String + { + return _resource is URLResource + ? URLResource(_resource).url + : null; + } + + /** + * Defines the resource that is used to construct the configuration's + * principle media element. + * + * On a resource being set, the media factory is requested to create + * a media element for the resource. The resulting media element is set + * the configuration's mediaElement property. + */ + public function set resource(value:MediaResourceBase):void + { + _resource = value; + mediaElement = factory.createMediaElement(resource); + } + public function get resource():MediaResourceBase + { + return _resource; + } + + /** + * Defines the DisplayObjectContainer that will hold the configuration's + * media container. + * + * On a view being set, the configuration adds its media container to + * the designated view. + */ + public function set view(value:DisplayObjectContainer):void + { + if (_view) + { + _view.removeChild(_container); + } + _view = value; + if (_view) + { + _view.addChild(container); + } + } + public function get view():DisplayObjectContainer + { + return _view; + } + + /** + * Defines the configuration's current media element. + * + * On a media element being set, the configuration forwards the + * value to its player and container objects. + */ + public function set mediaElement(value:MediaElement):void + { + if (value != _mediaElement) + { + // Remove the current media element from the various + // components that use it: + if (_mediaElement) + { + _container.removeMediaElement(_mediaElement); + } + + // Set the new media element: + _mediaElement = value; + + // Add the newly set element to the various components + // that use it: + _player.media = _mediaElement; + if (_mediaElement) + { + _resource = _mediaElement.resource; + _container.addMediaElement(_mediaElement); + } + } + } + public function get mediaElement():MediaElement + { + return _mediaElement; + } + + /** + * Defines the configuration's container object. + */ + public function get container():MediaContainer + { + return _container; + } + + /** + * Defines the configuration's factory object. + */ + public function get factory():MediaFactory + { + if (_factory == null) + { + _factory = constructFactory(); + } + return _factory; + } + + // Subclass stubs + // + + /** + * Subclasses may override this method to construct an alternative + * media factory implementation to DefaultMediaFactory. + */ + protected function constructFactory():MediaFactory + { + return new DefaultMediaFactory(); + } + + // Internals + // + + private var _mediaElement:MediaElement; + private var _player:MediaPlayer; + private var _container:MediaContainer; + private var _factory:MediaFactory; + + private var _resource:MediaResourceBase; + private var _view:DisplayObjectContainer; + } } \ No newline at end of file diff --git a/lib/osmf/samples/CuePointSample/.actionScriptProperties b/lib/osmf/samples/CuePointSample/.actionScriptProperties index 6d7342c..0ace950 100644 --- a/lib/osmf/samples/CuePointSample/.actionScriptProperties +++ b/lib/osmf/samples/CuePointSample/.actionScriptProperties @@ -1,41 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/CuePointSample/.flexProperties b/lib/osmf/samples/CuePointSample/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/CuePointSample/.flexProperties +++ b/lib/osmf/samples/CuePointSample/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/CuePointSample/readme.txt b/lib/osmf/samples/CuePointSample/readme.txt index 1dd0d7d..7fd449e 100644 --- a/lib/osmf/samples/CuePointSample/readme.txt +++ b/lib/osmf/samples/CuePointSample/readme.txt @@ -2,7 +2,7 @@ Sample Application: CuePointSample A. Overview -This sample application demonstrates temporal metadata within the OSMF framework. Its purpose is to demonstrate how the TemporalFacet and TemporalIndentifier classes in the org.osmf.metadata package can be used to inspect, add to, and listen for temporal metadata associated with a media element. The sample uses the new CuePoint class found in org.osmf.elements. +This sample application demonstrates temporal metadata within the OSMF framework. Its purpose is to demonstrate how the TemporalFacet and TemporalIndentifier classes in the org.osmf.metadata package can be used to inspect, add to, and listen for temporal metadata associated with a media element. The sample uses the new CuePoint class found in org.osmf.elements. B. Installation Instructions (Flex Builder) @@ -15,4 +15,4 @@ B. Installation Instructions (Flex Builder) C. Usage Instructions -The sample is a Flex application containing a DataGrid in the upper right which shows initially, all the cue points found in the media. If the user clicks on a navigation cue point in the grid, the media will seek to that cue point. The TextArea below the media shows the events dispatched by the TemporalFacet class. The "Add a cue point:" area in the lower right allows the user to add an ActionScript cue point at run-time. The DataGrid can be sorted by the Time column. If you add an ActionScript cue point and do not see it in the grid, try clicking the Time column and scrolling to the proper place in the grid. +The sample is a Flex application containing a DataGrid in the upper right which shows initially, all the cue points found in the media. If the user clicks on a navigation cue point in the grid, the media will seek to that cue point. The TextArea below the media shows the events dispatched by the TemporalFacet class. The "Add a cue point:" area in the lower right allows the user to add an ActionScript cue point at run-time. The DataGrid can be sorted by the Time column. If you add an ActionScript cue point and do not see it in the grid, try clicking the Time column and scrolling to the proper place in the grid. diff --git a/lib/osmf/samples/CuePointSample/src/CuePointSample.css b/lib/osmf/samples/CuePointSample/src/CuePointSample.css index 96df779..efa547d 100644 --- a/lib/osmf/samples/CuePointSample/src/CuePointSample.css +++ b/lib/osmf/samples/CuePointSample/src/CuePointSample.css @@ -1,78 +1,78 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ - -@namespace mx "library://ns.adobe.com/flex/mx"; - -global { - color: #ffffff; - fontFamily: "Verdana"; - fontSize: 11px; - fontWeight: normal; - disabledColor: #3d3d3d; -} - -.title { - fontSize: 20px; -} - -.timeCode { - fontSize: 10px; - color: #999999; -} - -.error { - fontSize: 10px; - color: #FF1111; -} - -mx|Label { - fontSize: 10px; - color: #aaaaaa; -} - -mx|Button { - themeColor: "haloSilver"; -} - -mx|TextInput { - color: #000000; -} - -mx|TextArea { - color: #111111; - disabledColor: #111111; -} - -mx|HSlider { - themeColor: "haloSilver"; - dataTipStyleName: "dataTip"; - dataTipOffset: 6; -} - -.dataTip { - backgroundColor: black; -} - -mx|DataGrid { - color: #333333; - themeColor: "haloSilver"; -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ + +@namespace mx "library://ns.adobe.com/flex/mx"; + +global { + color: #ffffff; + fontFamily: "Verdana"; + fontSize: 11px; + fontWeight: normal; + disabledColor: #3d3d3d; +} + +.title { + fontSize: 20px; +} + +.timeCode { + fontSize: 10px; + color: #999999; +} + +.error { + fontSize: 10px; + color: #FF1111; +} + +mx|Label { + fontSize: 10px; + color: #aaaaaa; +} + +mx|Button { + themeColor: "haloSilver"; +} + +mx|TextInput { + color: #000000; +} + +mx|TextArea { + color: #111111; + disabledColor: #111111; +} + +mx|HSlider { + themeColor: "haloSilver"; + dataTipStyleName: "dataTip"; + dataTipOffset: 6; +} + +.dataTip { + backgroundColor: black; +} + +mx|DataGrid { + color: #333333; + themeColor: "haloSilver"; +} diff --git a/lib/osmf/samples/CuePointSample/src/CuePointSample.mxml b/lib/osmf/samples/CuePointSample/src/CuePointSample.mxml index 721be57..80c1971 100644 --- a/lib/osmf/samples/CuePointSample/src/CuePointSample.mxml +++ b/lib/osmf/samples/CuePointSample/src/CuePointSample.mxml @@ -1,450 +1,450 @@ - - - - - - MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) - { - if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) - { - mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; - mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); - } - else - { - mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); - mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; - } - } - else if (width > 0 && height > 0) - { - mediaContainerUIComponent.width = event.newWidth; - mediaContainerUIComponent.height = event.newHeight; - } - } - - private function onDurationChange(event:TimeEvent):void - { - seekBar.maximum = event.time; - lblDuration.text = timeCode(event.time); - } - - private function onCurrentTimeChange(event:TimeEvent):void - { - if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) - { - seekBar.value = event.time; - lblPlayhead.text = timeCode(event.time); - } - } - - private function onSeekingChange(event:SeekEvent):void - { - if (event.seeking == false) - { - waitForSeek = false; - } - } - - private function toggleDragging(state:Boolean):void - { - sliderDragging = state; - if (!state) - { - waitForSeek = true; - if (mediaPlayer.canSeek) - { - mediaPlayer.seek(seekBar.value); - } - } - } - - private function onTraitAdd(event:MediaElementEvent):void - { - switch (event.traitType) - { - case MediaTraitType.SEEK: - seekBar.enabled = seekBar.visible = true; - break; - } - } - - private function onClickPlayBtn():void - { - if (mediaPlayer.playing && mediaPlayer.canPause) - { - playBtn.label = "Play"; - mediaPlayer.pause(); - } - else if (mediaPlayer.paused && mediaPlayer.canPlay) - { - playBtn.label = "Pause"; - mediaPlayer.play(); - } - } - - private function onClickAddCuePoint(event:Event):void - { - var cuePoint:CuePoint = new CuePoint(CuePointType.ACTIONSCRIPT, Number(tiCuePointTime.text), tiCuePointName.text, null); - if (dynamicTimelineMetadata == null) - { - dynamicTimelineMetadata = new TimelineMetadata(mediaPlayer.media); - mediaPlayer.media.addMetadata(CuePoint.DYNAMIC_CUEPOINTS_NAMESPACE, dynamicTimelineMetadata); - - } - dynamicTimelineMetadata.addMarker(cuePoint); - - updateInternalCollection(cuePoint); - - tiCuePointTime.text = tiCuePointName.text = ""; - } - - private function onCuePointAdd(event:TimelineMetadataEvent):void - { - updateInternalCollection(event.marker as CuePoint); - } - - private function updateInternalCollection(newCuePoint:CuePoint):void - { - // See if there is an existing value, if so replace it - for (var i:int = 0; i < _cuePointsCollection.length; i++) - { - if ((_cuePointsCollection[i] as TimelineMarker).time == newCuePoint.time) - { - _cuePointsCollection.removeItemAt(i); - break; - } - } - - _cuePointsCollection.addItem(newCuePoint); - } - - private function onClickCuePoint(event:Event):void - { - var cuePoint:CuePoint = this.gridCuePoints.selectedItem as CuePoint; - - if (cuePoint.type == CuePointType.NAVIGATION && this.mediaPlayer.canSeek) - { - this.mediaPlayer.seek(cuePoint.time); - } - } - - private function enablePlayerControls(enable:Boolean=true):void - { - playBtn.enabled = seekBar.enabled = enable; - } - - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) + { + if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) + { + mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; + mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); + } + else + { + mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); + mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; + } + } + else if (width > 0 && height > 0) + { + mediaContainerUIComponent.width = event.newWidth; + mediaContainerUIComponent.height = event.newHeight; + } + } + + private function onDurationChange(event:TimeEvent):void + { + seekBar.maximum = event.time; + lblDuration.text = timeCode(event.time); + } + + private function onCurrentTimeChange(event:TimeEvent):void + { + if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) + { + seekBar.value = event.time; + lblPlayhead.text = timeCode(event.time); + } + } + + private function onSeekingChange(event:SeekEvent):void + { + if (event.seeking == false) + { + waitForSeek = false; + } + } + + private function toggleDragging(state:Boolean):void + { + sliderDragging = state; + if (!state) + { + waitForSeek = true; + if (mediaPlayer.canSeek) + { + mediaPlayer.seek(seekBar.value); + } + } + } + + private function onTraitAdd(event:MediaElementEvent):void + { + switch (event.traitType) + { + case MediaTraitType.SEEK: + seekBar.enabled = seekBar.visible = true; + break; + } + } + + private function onClickPlayBtn():void + { + if (mediaPlayer.playing && mediaPlayer.canPause) + { + playBtn.label = "Play"; + mediaPlayer.pause(); + } + else if (mediaPlayer.paused && mediaPlayer.canPlay) + { + playBtn.label = "Pause"; + mediaPlayer.play(); + } + } + + private function onClickAddCuePoint(event:Event):void + { + var cuePoint:CuePoint = new CuePoint(CuePointType.ACTIONSCRIPT, Number(tiCuePointTime.text), tiCuePointName.text, null); + if (dynamicTimelineMetadata == null) + { + dynamicTimelineMetadata = new TimelineMetadata(mediaPlayer.media); + mediaPlayer.media.addMetadata(CuePoint.DYNAMIC_CUEPOINTS_NAMESPACE, dynamicTimelineMetadata); + + } + dynamicTimelineMetadata.addMarker(cuePoint); + + updateInternalCollection(cuePoint); + + tiCuePointTime.text = tiCuePointName.text = ""; + } + + private function onCuePointAdd(event:TimelineMetadataEvent):void + { + updateInternalCollection(event.marker as CuePoint); + } + + private function updateInternalCollection(newCuePoint:CuePoint):void + { + // See if there is an existing value, if so replace it + for (var i:int = 0; i < _cuePointsCollection.length; i++) + { + if ((_cuePointsCollection[i] as TimelineMarker).time == newCuePoint.time) + { + _cuePointsCollection.removeItemAt(i); + break; + } + } + + _cuePointsCollection.addItem(newCuePoint); + } + + private function onClickCuePoint(event:Event):void + { + var cuePoint:CuePoint = this.gridCuePoints.selectedItem as CuePoint; + + if (cuePoint.type == CuePointType.NAVIGATION && this.mediaPlayer.canSeek) + { + this.mediaPlayer.seek(cuePoint.time); + } + } + + private function enablePlayerControls(enable:Boolean=true):void + { + playBtn.enabled = seekBar.enabled = enable; + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/DynamicStreamingSample/.actionScriptProperties b/lib/osmf/samples/DynamicStreamingSample/.actionScriptProperties index 3356b10..37c8838 100644 --- a/lib/osmf/samples/DynamicStreamingSample/.actionScriptProperties +++ b/lib/osmf/samples/DynamicStreamingSample/.actionScriptProperties @@ -1,44 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/DynamicStreamingSample/.flexProperties b/lib/osmf/samples/DynamicStreamingSample/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/DynamicStreamingSample/.flexProperties +++ b/lib/osmf/samples/DynamicStreamingSample/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/DynamicStreamingSample/DynamicStreamingSample-build-config.xml b/lib/osmf/samples/DynamicStreamingSample/DynamicStreamingSample-build-config.xml index 7a1b7fc..0c3b225 100644 --- a/lib/osmf/samples/DynamicStreamingSample/DynamicStreamingSample-build-config.xml +++ b/lib/osmf/samples/DynamicStreamingSample/DynamicStreamingSample-build-config.xml @@ -25,8 +25,8 @@ - @@ -39,10 +39,10 @@ false - @@ -132,11 +132,11 @@ - @@ -154,8 +154,8 @@ - @@ -174,13 +174,13 @@ - @@ -190,12 +190,12 @@ flash.fonts.BatikFontManager - @@ -315,19 +315,19 @@ - - - @@ -341,10 +341,10 @@ true - - diff --git a/lib/osmf/samples/DynamicStreamingSample/html-template/AC_OETags.js b/lib/osmf/samples/DynamicStreamingSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/DynamicStreamingSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/DynamicStreamingSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/DynamicStreamingSample/html-template/history/historyFrame.html b/lib/osmf/samples/DynamicStreamingSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/DynamicStreamingSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/DynamicStreamingSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/DynamicStreamingSample/html-template/index.template.html b/lib/osmf/samples/DynamicStreamingSample/html-template/index.template.html index 76aeecf..3b53414 100644 --- a/lib/osmf/samples/DynamicStreamingSample/html-template/index.template.html +++ b/lib/osmf/samples/DynamicStreamingSample/html-template/index.template.html @@ -1,124 +1,124 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/DynamicStreamingSample/readme.txt b/lib/osmf/samples/DynamicStreamingSample/readme.txt index 2a7ef5c..26200ac 100644 --- a/lib/osmf/samples/DynamicStreamingSample/readme.txt +++ b/lib/osmf/samples/DynamicStreamingSample/readme.txt @@ -2,7 +2,7 @@ Sample Application: DynamicStreamingSample A. Overview -This sample application demonstrates dynamic stream switching within the OSMF framework. Its purpose is to demonstrate how the various classes in the org.osmf.net.dynamicstreaming package can be used to dynamically stream a profile of streams represented by a DynamicStreamingResource object. +This sample application demonstrates dynamic stream switching within the OSMF framework. Its purpose is to demonstrate how the various classes in the org.osmf.net.dynamicstreaming package can be used to dynamically stream a profile of streams represented by a DynamicStreamingResource object. This sample application contains a SMIL parser. It downloads a sample SMIL file containing a dynamic stream switching profile (this is the same SMIL format used by the default FMS install), and parses it into a DynamicStreamingResource object. @@ -17,23 +17,23 @@ B. Installation Instructions (Flex Builder) C. Usage Instructions -This sample application contains several test assets, most of which are SMIL files but also contains a few "regular" assets, meaning non-dynamic stream switching assets. The new dynamic stream switching classes can handle a DynamicStreamingResource object (for dynamic stream switching) or an IURLResource for "regular" streaming or progressive download content. The sample app plays both and contains sample content for a progressive download file and a streaming file to prove this functionality. +This sample application contains several test assets, most of which are SMIL files but also contains a few "regular" assets, meaning non-dynamic stream switching assets. The new dynamic stream switching classes can handle a DynamicStreamingResource object (for dynamic stream switching) or an IURLResource for "regular" streaming or progressive download content. The sample app plays both and contains sample content for a progressive download file and a streaming file to prove this functionality. The sample application provides a user interface for manually switching up or down as well as an informational text area control showing the information available to a player. This information includes: 1. When a switching change has been requested and the reason for the switch request (i.e., "move up since" or "moving down due to insufficient buffer length", etc). 2. When a switching change is "complete", meaning the change is in the buffer and is now visible to the end user. 3. The current streaming profile index and its bitrate. -When the Auto/Manual button is selected, the player goes in and out of auto switching mode. The player is smart enough to know whether a switch up or down is possible based on the currently rendering index of the switching profile (the contents of the DynamicStreamingResource object) and therefore enables/disables the switch up/down buttons ("+" and "-" respectively) when appropriate. The auto/manual switching buttons are disabled while a switch is in progress. +When the Auto/Manual button is selected, the player goes in and out of auto switching mode. The player is smart enough to know whether a switch up or down is possible based on the currently rendering index of the switching profile (the contents of the DynamicStreamingResource object) and therefore enables/disables the switch up/down buttons ("+" and "-" respectively) when appropriate. The auto/manual switching buttons are disabled while a switch is in progress. It is important to understand the switching sequence from the client side. The process for a switch involves the following sequence: 1. The client code makes a switch change request (based on a switching rule's recommendation or a manual switch request). 2. The client receives a NetStream.Play.Transition info code, which means the server has successfully accepted the switch and is in the process of switching (or a NetStream.Play.Failed if the server is unable to switch). -3. The client receives a NetStream.Play.TransitionComplete via the onPlayStatus callback. This indicates the switch has completed and is visible to the user. +3. The client receives a NetStream.Play.TransitionComplete via the onPlayStatus callback. This indicates the switch has completed and is visible to the user. *** Important notes about seeking and switching in the sample application *** - If you request a manual switch up or down and then seek before the NetStream.Play.Transition message is received, the switch is ignored. - If you request a manual switch up or down and wait for the NetStream.Play.Transition, then seek, the server will make the switch and return the new stream at that seek location but no NetStream.Play.TransitionComplete message will come due to the buffer flush caused by the seek (the TransitionComplete is a data message in the buffer). - The OSMF framework does not expose the NetStream.Play.Transition message, this was design decision, so the only way to know it happened is to "tail -f" the flashlog.txt file. This tracing is due to the DEBUG const set to true in the DynamicNetStream class. - + diff --git a/lib/osmf/samples/DynamicStreamingSample/src/DynamicStreamingSample.css b/lib/osmf/samples/DynamicStreamingSample/src/DynamicStreamingSample.css index be6358e..84db6ec 100644 --- a/lib/osmf/samples/DynamicStreamingSample/src/DynamicStreamingSample.css +++ b/lib/osmf/samples/DynamicStreamingSample/src/DynamicStreamingSample.css @@ -1,93 +1,93 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -@namespace mx "library://ns.adobe.com/flex/mx"; - -@font-face { - src: local("Verdana"); - embedAsCFF: false; - fontFamily: "Verdana"; - unicodeRange:'U+0020-U+007E'; -} - -@font-face { - src: local("Verdana"); - embedAsCFF: false; - fontFamily: "Verdana"; - fontWeight: bold; - unicodeRange:'U+0020-U+007E'; -} - -global { - color: #FFFFFF; - fontFamily: "Verdana"; - fontSize: 11px; - fontWeight: normal; -} - -.title { - fontSize: 20px; - fontWeight: normal; -} - -.timeCode { - fontSize: 10px; - color: #999999; -} - -.error { - fontSize: 10px; - color: #FF1111; -} - -mx|Label { - fontSize: 10px; - color: #aaaaaa; -} - -mx|ComboBox { - color: #333333; - themeColor: "haloSilver"; -} - -mx|Button { - themeColor: "haloSilver"; -} - -mx|TextInput { - color: #000000; -} - -mx|TextArea { - color: #222222; - disabledColor: #222222; -} - -mx|HSlider { - themeColor: "haloSilver"; - dataTipStyleName: "dataTip"; - dataTipOffset: 6; -} - -.dataTip { - backgroundColor: black; -} - +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +@namespace mx "library://ns.adobe.com/flex/mx"; + +@font-face { + src: local("Verdana"); + embedAsCFF: false; + fontFamily: "Verdana"; + unicodeRange:'U+0020-U+007E'; +} + +@font-face { + src: local("Verdana"); + embedAsCFF: false; + fontFamily: "Verdana"; + fontWeight: bold; + unicodeRange:'U+0020-U+007E'; +} + +global { + color: #FFFFFF; + fontFamily: "Verdana"; + fontSize: 11px; + fontWeight: normal; +} + +.title { + fontSize: 20px; + fontWeight: normal; +} + +.timeCode { + fontSize: 10px; + color: #999999; +} + +.error { + fontSize: 10px; + color: #FF1111; +} + +mx|Label { + fontSize: 10px; + color: #aaaaaa; +} + +mx|ComboBox { + color: #333333; + themeColor: "haloSilver"; +} + +mx|Button { + themeColor: "haloSilver"; +} + +mx|TextInput { + color: #000000; +} + +mx|TextArea { + color: #222222; + disabledColor: #222222; +} + +mx|HSlider { + themeColor: "haloSilver"; + dataTipStyleName: "dataTip"; + dataTipOffset: 6; +} + +.dataTip { + backgroundColor: black; +} + diff --git a/lib/osmf/samples/DynamicStreamingSample/src/DynamicStreamingSample.mxml b/lib/osmf/samples/DynamicStreamingSample/src/DynamicStreamingSample.mxml index bbe3126..dc3d952 100644 --- a/lib/osmf/samples/DynamicStreamingSample/src/DynamicStreamingSample.mxml +++ b/lib/osmf/samples/DynamicStreamingSample/src/DynamicStreamingSample.mxml @@ -1,518 +1,518 @@ - - - - - - - MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) - { - if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) - { - mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; - mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); - } - else - { - mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); - mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; - } - } - else if (width > 0 && height > 0) - { - mediaContainerUIComponent.width = event.newWidth; - mediaContainerUIComponent.height = event.newHeight; - } - } - - private function onDurationChange(event:TimeEvent):void - { - seekBar.maximum = event.time; - lblDuration.text = TimeUtil.formatAsTimeCode(event.time); - } - - private function onCurrentTimeChange(event:TimeEvent):void - { - if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) - { - seekBar.value = event.time; - lblPlayhead.text = TimeUtil.formatAsTimeCode(event.time); - } - } - - private function onSeekingChange(event:SeekEvent):void - { - if (event.seeking == false) - { - waitForSeek = false; - updateSwitchingControls(); - } - } - - private function toggleDragging(state:Boolean):void - { - sliderDragging = state; - if (!state) - { - waitForSeek = true; - if (mediaPlayer.canSeek) - { - mediaPlayer.seek(seekBar.value); - } - } - } - - private function onMediaError(event:MediaErrorEvent):void - { - if (taDebug.text.length) - { - taDebug.text += "\n"; - } - taDebug.text += taDebug.text + "error ID="+event.error.errorID+" message="+event.error.message; - } - - private function onSwitchUp():void - { - if (mediaPlayer.isDynamicStream && !mediaPlayer.autoDynamicStreamSwitch && !mediaPlayer.dynamicStreamSwitching) - { - if (mediaPlayer.currentDynamicStreamIndex < mediaPlayer.maxAllowedDynamicStreamIndex) - { - mediaPlayer.switchDynamicStreamIndex(mediaPlayer.currentDynamicStreamIndex + 1); - } - } - } - - private function onSwitchDown():void - { - if (mediaPlayer.isDynamicStream && !mediaPlayer.autoDynamicStreamSwitch && !mediaPlayer.dynamicStreamSwitching) - { - if (mediaPlayer.currentDynamicStreamIndex > 0) - { - mediaPlayer.switchDynamicStreamIndex(mediaPlayer.currentDynamicStreamIndex - 1); - } - } - } - - private function onAutoSwitchable():void - { - if (mediaPlayer.isDynamicStream) - { - this._isAutoSwitchable = !this._isAutoSwitchable; - mediaPlayer.autoDynamicStreamSwitch = this._isAutoSwitchable; - debug("Setting auto switch mode to " + this._isAutoSwitchable); - - _autoSwitchBtnLabel = (_isAutoSwitchable ? "Manual" : "Auto"); - updateSwitchingControls(); - } - } - - private function onClickPlayBtn():void - { - if (mediaPlayer.playing && mediaPlayer.canPause) - { - playBtn.label = "Play"; - mediaPlayer.pause(); - } - else if (mediaPlayer.paused && mediaPlayer.canPlay) - { - playBtn.label = "Pause"; - mediaPlayer.play(); - } - } - - private function showControls(show:Boolean=true):void - { - mainContainer.visible = mainContainer.includeInLayout = show; - } - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + MAX_VIDEO_WIDTH || height > MAX_VIDEO_HEIGHT) + { + if ((width/height) >= (MAX_VIDEO_WIDTH/MAX_VIDEO_HEIGHT)) + { + mediaContainerUIComponent.width = MAX_VIDEO_WIDTH; + mediaContainerUIComponent.height = MAX_VIDEO_WIDTH * (height/width); + } + else + { + mediaContainerUIComponent.width = MAX_VIDEO_HEIGHT * (width/height); + mediaContainerUIComponent.height = MAX_VIDEO_HEIGHT; + } + } + else if (width > 0 && height > 0) + { + mediaContainerUIComponent.width = event.newWidth; + mediaContainerUIComponent.height = event.newHeight; + } + } + + private function onDurationChange(event:TimeEvent):void + { + seekBar.maximum = event.time; + lblDuration.text = TimeUtil.formatAsTimeCode(event.time); + } + + private function onCurrentTimeChange(event:TimeEvent):void + { + if (mediaPlayer.temporal && !sliderDragging && !waitForSeek) + { + seekBar.value = event.time; + lblPlayhead.text = TimeUtil.formatAsTimeCode(event.time); + } + } + + private function onSeekingChange(event:SeekEvent):void + { + if (event.seeking == false) + { + waitForSeek = false; + updateSwitchingControls(); + } + } + + private function toggleDragging(state:Boolean):void + { + sliderDragging = state; + if (!state) + { + waitForSeek = true; + if (mediaPlayer.canSeek) + { + mediaPlayer.seek(seekBar.value); + } + } + } + + private function onMediaError(event:MediaErrorEvent):void + { + if (taDebug.text.length) + { + taDebug.text += "\n"; + } + taDebug.text += taDebug.text + "error ID="+event.error.errorID+" message="+event.error.message; + } + + private function onSwitchUp():void + { + if (mediaPlayer.isDynamicStream && !mediaPlayer.autoDynamicStreamSwitch && !mediaPlayer.dynamicStreamSwitching) + { + if (mediaPlayer.currentDynamicStreamIndex < mediaPlayer.maxAllowedDynamicStreamIndex) + { + mediaPlayer.switchDynamicStreamIndex(mediaPlayer.currentDynamicStreamIndex + 1); + } + } + } + + private function onSwitchDown():void + { + if (mediaPlayer.isDynamicStream && !mediaPlayer.autoDynamicStreamSwitch && !mediaPlayer.dynamicStreamSwitching) + { + if (mediaPlayer.currentDynamicStreamIndex > 0) + { + mediaPlayer.switchDynamicStreamIndex(mediaPlayer.currentDynamicStreamIndex - 1); + } + } + } + + private function onAutoSwitchable():void + { + if (mediaPlayer.isDynamicStream) + { + this._isAutoSwitchable = !this._isAutoSwitchable; + mediaPlayer.autoDynamicStreamSwitch = this._isAutoSwitchable; + debug("Setting auto switch mode to " + this._isAutoSwitchable); + + _autoSwitchBtnLabel = (_isAutoSwitchable ? "Manual" : "Auto"); + updateSwitchingControls(); + } + } + + private function onClickPlayBtn():void + { + if (mediaPlayer.playing && mediaPlayer.canPause) + { + playBtn.label = "Play"; + mediaPlayer.pause(); + } + else if (mediaPlayer.paused && mediaPlayer.canPlay) + { + playBtn.label = "Pause"; + mediaPlayer.play(); + } + } + + private function showControls(show:Boolean=true):void + { + mainContainer.visible = mainContainer.includeInLayout = show; + } + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/ExamplePlayer/.actionScriptProperties b/lib/osmf/samples/ExamplePlayer/.actionScriptProperties index 56eb3c2..dfe371a 100644 --- a/lib/osmf/samples/ExamplePlayer/.actionScriptProperties +++ b/lib/osmf/samples/ExamplePlayer/.actionScriptProperties @@ -1,41 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/ExamplePlayer/.flexProperties b/lib/osmf/samples/ExamplePlayer/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/ExamplePlayer/.flexProperties +++ b/lib/osmf/samples/ExamplePlayer/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/ExamplePlayer/ExamplePlayer-build-config.xml b/lib/osmf/samples/ExamplePlayer/ExamplePlayer-build-config.xml index fba46ae..b79aa73 100644 --- a/lib/osmf/samples/ExamplePlayer/ExamplePlayer-build-config.xml +++ b/lib/osmf/samples/ExamplePlayer/ExamplePlayer-build-config.xml @@ -23,8 +23,8 @@ - @@ -39,10 +39,10 @@ false - @@ -66,15 +66,15 @@ - library://ns.adobe.com/flex/mx @@ -131,11 +131,11 @@ - @@ -153,8 +153,8 @@ - @@ -173,13 +173,13 @@ - @@ -189,12 +189,12 @@ flash.fonts.BatikFontManager - @@ -316,19 +316,19 @@ ${flexlib}/${configname}-config.xml - - - 0xFFFFFF @@ -338,10 +338,10 @@ true - - diff --git a/lib/osmf/samples/ExamplePlayer/assets/ExamplePlayer.css b/lib/osmf/samples/ExamplePlayer/assets/ExamplePlayer.css index 36a5cf5..bf719fb 100644 --- a/lib/osmf/samples/ExamplePlayer/assets/ExamplePlayer.css +++ b/lib/osmf/samples/ExamplePlayer/assets/ExamplePlayer.css @@ -1,37 +1,37 @@ -/* CSS file */ - -/* -@font-face { - src:url("assets.swf"); - fontStyle: condensed; - fontFamily: "Myriad Pro"; - -} -*/ - - -.buttonPlay -{ - icon: Embed(source="assets.swf#PlayIcon"); -} - -.buttonPause -{ - icon: Embed(source="assets.swf#PauseIcon"); -} - -.panel -{ - backgroundColor: white; - backgroundAlpha: 0.1; - - paddingLeft: 8; - paddingRight: 8; - paddingBottom: 8; - paddingTop: 8; - - cornerRadius: 8; - borderStyle: solid; - borderColor: #333333; - borderAlpha: 0.1; -} +/* CSS file */ + +/* +@font-face { + src:url("assets.swf"); + fontStyle: condensed; + fontFamily: "Myriad Pro"; + +} +*/ + + +.buttonPlay +{ + icon: Embed(source="assets.swf#PlayIcon"); +} + +.buttonPause +{ + icon: Embed(source="assets.swf#PauseIcon"); +} + +.panel +{ + backgroundColor: white; + backgroundAlpha: 0.1; + + paddingLeft: 8; + paddingRight: 8; + paddingBottom: 8; + paddingTop: 8; + + cornerRadius: 8; + borderStyle: solid; + borderColor: #333333; + borderAlpha: 0.1; +} diff --git a/lib/osmf/samples/ExamplePlayer/html-template/AC_OETags.js b/lib/osmf/samples/ExamplePlayer/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/ExamplePlayer/html-template/AC_OETags.js +++ b/lib/osmf/samples/ExamplePlayer/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/ExamplePlayer/html-template/history/historyFrame.html b/lib/osmf/samples/ExamplePlayer/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/ExamplePlayer/html-template/history/historyFrame.html +++ b/lib/osmf/samples/ExamplePlayer/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/ExamplePlayer/html-template/index.template.html b/lib/osmf/samples/ExamplePlayer/html-template/index.template.html index bc09b0b..89b6869 100644 --- a/lib/osmf/samples/ExamplePlayer/html-template/index.template.html +++ b/lib/osmf/samples/ExamplePlayer/html-template/index.template.html @@ -1,272 +1,272 @@ - - - - - - - -${title} - - - - - - - - - - - + + + + + + + +${title} + + + + + + + + + + + diff --git a/lib/osmf/samples/ExamplePlayer/readme.txt b/lib/osmf/samples/ExamplePlayer/readme.txt index f46ceb7..980058b 100644 --- a/lib/osmf/samples/ExamplePlayer/readme.txt +++ b/lib/osmf/samples/ExamplePlayer/readme.txt @@ -1,52 +1,52 @@ -Sample Application: Example Player - -A. Overview - -This sample application demonstrates the playback of various MediaElements within the OSMF framework. -Its purpose is to demonstrate how the MediaElement class can be used to implement a wide variety of -media scenarios, from simple cases (e.g. video, audio, image, SWF), to complex cases (e.g. dynamic -streaming video, embedded chromeless SWF player, sequence of videos, proxy elements). It also shows -some error cases (e.g. streaming video with an invalid URL). - -B. Installation Instructions (Flex Builder) - -1. Unzip/copy the ExamplePlayer project into your Flex Builder workspace folder. -2. In Flex Builder, go to the File menu and select "Import". -3. Select "General", then "Existing Projects into Workspace", and click "Next". -4. Choose "Select root directory" and "Browse". -5. Browse to your Flex Builder workspace folder. -6. Select the checkbox next to "ExamplePlayer", and click "Finish". This will import the project. -7. Build the project. -8. Launch the application from the Run menu. - -If you're compiling this example with the Flex 4.0 SDK, you need to specify that they use the Halo -theme rather than the default Spark theme. The easiest way to do this is to edit the flex-config.xml -file in your SDK's "frameworks" folder and replace the existing content with the following: - - - - themes/Halo/halo.swc - themes/Spark/spark.css - - -The changes will take effect the next time you restart Flash Builder. - -Note that some of the examples (such as the Chromeless SWF examples) require that the Example Player be -launched from the network rather than the file system. Here's how to do so. - -1. Build the project. -2. Copy the ExamplePlayer.swf file from the bin (or bin-debug) folder to your web server. -3. In Flex Builder, go to the Run menu and select "Run Configurations" (or "Debug Configurations"). -4. Create a new configuration for the ExamplePlayer project. -5. Under "URL or path to launch", uncheck the "Use defaults" checkbox. -6. In the "Run" (or "Debug") text box, enter the URL of the ExamplePlayer.swf file on your web server. -7. Click the "Run" (or "Debug") button. - -C. Usage Instructions - -On the left hand side is a list of examples. Each example represents a MediaElement that will be loaded -into a MediaPlayer for playback. When you click on an example in the list, a description of the example -will appear in the upper right, and a control panel which allows interaction will appear in the lower -right. - -The code for each example is in org.osmf.examples.AllExamples.as. +Sample Application: Example Player + +A. Overview + +This sample application demonstrates the playback of various MediaElements within the OSMF framework. +Its purpose is to demonstrate how the MediaElement class can be used to implement a wide variety of +media scenarios, from simple cases (e.g. video, audio, image, SWF), to complex cases (e.g. dynamic +streaming video, embedded chromeless SWF player, sequence of videos, proxy elements). It also shows +some error cases (e.g. streaming video with an invalid URL). + +B. Installation Instructions (Flex Builder) + +1. Unzip/copy the ExamplePlayer project into your Flex Builder workspace folder. +2. In Flex Builder, go to the File menu and select "Import". +3. Select "General", then "Existing Projects into Workspace", and click "Next". +4. Choose "Select root directory" and "Browse". +5. Browse to your Flex Builder workspace folder. +6. Select the checkbox next to "ExamplePlayer", and click "Finish". This will import the project. +7. Build the project. +8. Launch the application from the Run menu. + +If you're compiling this example with the Flex 4.0 SDK, you need to specify that they use the Halo +theme rather than the default Spark theme. The easiest way to do this is to edit the flex-config.xml +file in your SDK's "frameworks" folder and replace the existing content with the following: + + + + themes/Halo/halo.swc + themes/Spark/spark.css + + +The changes will take effect the next time you restart Flash Builder. + +Note that some of the examples (such as the Chromeless SWF examples) require that the Example Player be +launched from the network rather than the file system. Here's how to do so. + +1. Build the project. +2. Copy the ExamplePlayer.swf file from the bin (or bin-debug) folder to your web server. +3. In Flex Builder, go to the Run menu and select "Run Configurations" (or "Debug Configurations"). +4. Create a new configuration for the ExamplePlayer project. +5. Under "URL or path to launch", uncheck the "Use defaults" checkbox. +6. In the "Run" (or "Debug") text box, enter the URL of the ExamplePlayer.swf file on your web server. +7. Click the "Run" (or "Debug") button. + +C. Usage Instructions + +On the left hand side is a list of examples. Each example represents a MediaElement that will be loaded +into a MediaPlayer for playback. When you click on an example in the list, a description of the example +will appear in the upper right, and a control panel which allows interaction will appear in the lower +right. + +The code for each example is in org.osmf.examples.AllExamples.as. diff --git a/lib/osmf/samples/ExamplePlayer/src/ExamplePlayer.mxml b/lib/osmf/samples/ExamplePlayer/src/ExamplePlayer.mxml index aea80c0..4ed739b 100644 --- a/lib/osmf/samples/ExamplePlayer/src/ExamplePlayer.mxml +++ b/lib/osmf/samples/ExamplePlayer/src/ExamplePlayer.mxml @@ -1,42 +1,42 @@ - - - - - - - - - + + + + + + + + + diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/AllExamples.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/AllExamples.as index 4f76cff..6120ff5 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/AllExamples.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/AllExamples.as @@ -1,1205 +1,1205 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples -{ - import flash.events.Event; - import flash.events.TimerEvent; - import flash.net.NetConnection; - import flash.net.NetStream; - import flash.utils.Timer; - - import mx.collections.ArrayCollection; - - import org.osmf.elements.AudioElement; - import org.osmf.elements.BeaconElement; - import org.osmf.elements.DurationElement; - import org.osmf.elements.F4MElement; - import org.osmf.elements.ImageElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.SWFElement; - import org.osmf.elements.SerialElement; - import org.osmf.elements.VideoElement; - import org.osmf.examples.ads.PreMidPostRollElement; - import org.osmf.examples.buffering.DualThresholdBufferingProxyElement; - import org.osmf.examples.buffering.SynchronizedParallelElement; - import org.osmf.examples.chromeless.ChromelessPlayerElement; - import org.osmf.examples.loaderproxy.AsynchLoadingProxyElement; - import org.osmf.examples.loaderproxy.VideoProxyElement; - import org.osmf.examples.netconnection.SimpleNetLoader; - import org.osmf.examples.posterframe.PosterFrameElement; - import org.osmf.examples.posterframe.RTMPPosterFrameElement; - import org.osmf.examples.recommendations.RecommendationsElement; - import org.osmf.examples.seeking.PreloadingProxyElement; - import org.osmf.examples.seeking.UnseekableProxyElement; - import org.osmf.examples.switchingproxy.SwitchingProxyElement; - import org.osmf.examples.text.TextElement; - import org.osmf.examples.traceproxy.TraceListenerProxyElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - import org.osmf.media.URLResource; - import org.osmf.net.DynamicStreamingItem; - import org.osmf.net.DynamicStreamingResource; - import org.osmf.net.NetLoader; - import org.osmf.net.StreamType; - import org.osmf.net.StreamingURLResource; - import org.osmf.net.rtmpstreaming.RTMPDynamicStreamingNetLoader; - import org.osmf.traits.BufferTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - - /** - * Central repository of all examples for this application. - **/ - public class AllExamples - { - /** - * All examples to be used in the player. - **/ - public static function get examples():ArrayCollection - { - var examples:ArrayCollection = new ArrayCollection(); - var mediaElement:MediaElement = null; - - var timer:Timer = new Timer(1000); - var timerHandler:Function; - - - var media:Category = new Category("Media"); - var composition:Category = new Category("Composition"); - var proxies:Category = new Category("Proxies"); - var layout:Category = new Category("Layout"); - var errorHandling:Category = new Category("Error Handling"); - - // Core Media Examples - // - - media.addItem - ( new Example - ( "Progressive Video" - , "Demonstrates playback of a progressive video using VideoElement and NetLoader." - , function():MediaElement - { - return new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); - } - ) - ); - - media.addItem - ( new Example - ( "Streaming Video" - , "Demonstrates playback of a streaming video using VideoElement and NetLoader." - , function():MediaElement - { - return new VideoElement(new URLResource(REMOTE_STREAM)); - } - ) - ); - - media.addItem - ( new Example - ( "Dynamic Streaming Video" - , "Demonstrates the use of dynamic streaming. The player will automatically switch between five variations of the same stream, each encoded at a different bitrate (from 408 Kbps to 1708 Kbps), based on the available bandwidth. Note that the switching behavior can be modified via custom switching rules." - , function():MediaElement - { - var dsResource:DynamicStreamingResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); - for (var i:int = 0; i < 5; i++) - { - dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); - } - return new VideoElement(dsResource); - } - , null - , "letterbox" - ) - ); - - media.addItem - ( new Example - ( "Live Streaming Video" - , "Demonstrates playback of a live video stream." - , function():MediaElement - { - return new VideoElement(new StreamingURLResource(REMOTE_LIVE_STREAM, StreamType.LIVE)); - } - ) - ); - - media.addItem - ( new Example - ( "Streaming Video With Dual-Threshold Buffer" - , "Demonstrates playback of a streaming video with a dual-threshold buffer. The buffer starts small, but increases once we've buffered enough data to enable playback. The larger buffer reduces the chance that a rebuffer will need to occur." - , function():MediaElement - { - var videoElement:VideoElement = new VideoElement(new URLResource(REMOTE_STREAM)); - return new DualThresholdBufferingProxyElement(2, 15, videoElement); - } - ) - ); - - media.addItem - ( new Example - ( "Progressive Video With Dynamic Buffer" - , "Demonstrates playback of a progressive video with a dynamic buffer. The size of the buffer grows slowly as the video plays, then shrinks back down again." - , function():MediaElement - { - var videoElement:VideoElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); - - // Trigger the timer every second. - timer.delay = 1000; - timer.repeatCount = 20; - timer.addEventListener(TimerEvent.TIMER, timerHandler = onTimer); - timer.start(); - - function onTimer(event:TimerEvent):void - { - // Only adjust the buffer while we're playing. - var playTrait:PlayTrait = videoElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - var bufferTrait:BufferTrait = videoElement.getTrait(MediaTraitType.BUFFER) as BufferTrait; - if (bufferTrait && !bufferTrait.buffering && playTrait && playTrait.playState == PlayState.PLAYING) - { - if (timer.currentCount <= 10) - { - bufferTrait.bufferTime += 1.0; - } - else - { - bufferTrait.bufferTime -= 1.0; - } - } - } - - return videoElement; - } - , function():void - { - timer.stop(); - timer.reset(); - timer.removeEventListener - ( TimerEvent.TIMER - , timerHandler - ); - } - ) - ); - - media.addItem - ( new Example - ( "Image" - , "Demonstrates display of an image using ImageElement and ImageLoader." - , function():MediaElement - { - return new ImageElement(new URLResource(REMOTE_IMAGE)); - } - ) - ); - - media.addItem - ( new Example - ( "Timed Image" - , "Demonstrates display of an image for a fixed amount of time." - , function():MediaElement - { - return new DurationElement(4, new ImageElement(new URLResource(REMOTE_IMAGE))); - } - ) - ); - - media.addItem - ( new Example - ( "SWF" - , "Demonstrates display of a SWF using SWFElement and SWFLoader." - , function():MediaElement - { - return new SWFElement(new URLResource(REMOTE_SWF) ); - } - ) - ); - - media.addItem - ( new Example - ( "Progressive Audio" - , "Demonstrates playback of a progressive audio file using AudioElement and SoundLoader." - , function():MediaElement - { - return new AudioElement(new URLResource(REMOTE_MP3)); - } - ) - ); - - media.addItem - ( new Example - ( "Streaming Audio" - , "Demonstrates playback of a streaming audio file using AudioElement and NetLoader." - , function():MediaElement - { - return new AudioElement(new StreamingURLResource(REMOTE_AUDIO_STREAM)); - } - ) - ); - - media.addItem - ( new Example - ( "Streaming Video with Connection-level Parameters" - , "Demonstrates how parameters can be passed to both the NetConnection.connect call, and NetStream.play()." - , function():MediaElement - { - var videoElement:VideoElement = new VideoElement(new URLResource(REMOTE_STREAM + "?param1=value1¶m2=value2")); - return videoElement; - } - ) - ); - - media.addItem - ( new Example - ( "Streaming Video As Subclip" - , "Demonstrates playback of a subclip of a streaming video using metadata to specify the start and end times." - , function():MediaElement - { - var resource:StreamingURLResource = new StreamingURLResource(REMOTE_STREAM); - resource.clipStartTime = 10; - resource.clipEndTime = 25; - return new VideoElement(resource); - } - ) - ); - - media.addItem - ( new Example - ( "Flash Media Manifest (F4M) with Progressive Video" - , "Demonstrates the use of a Flash Media Manifest file (F4M) for a progressive video." - , function():MediaElement - { - var elem:F4MElement = new F4MElement(); - elem.resource = new URLResource(REMOTE_MANIFEST); - return elem; - } - ) - ); - - media.addItem - ( new Example - ( "Flash Media Manifest (F4M) with Dynamic Streaming Video" - , "Demonstrates the use of a Flash Media Manifest file (F4M) for dynamic streaming video." - , function():MediaElement - { - var elem:F4MElement = new F4MElement(); - elem.resource = new URLResource(REMOTE_MBR_MANIFEST); - return elem; - } - ) - ); - - media.addItem - ( new Example - ( "Streaming Video With an Injected NetConnection" - , "Demonstrates playback of a video where the NetConnection and NetStream are specified externally, rather than created by the NetLoader. This approach is useful when you're integrating with an existing NetConnection framework. For simplicity, this example plays a progressive video, but the approach should also work for streaming video." - , function():MediaElement - { - var netConnection:NetConnection = new NetConnection(); - netConnection.connect(null); - var netStream:NetStream = new NetStream(netConnection); - return new VideoElement(new URLResource(REMOTE_PROGRESSIVE), new SimpleNetLoader(netConnection, netStream)); - } - ) - ); - - media.addItem - ( new Example - ( "Text" - , "Demonstrates a custom MediaElement that displays text." - , function():MediaElement - { - return new TextElement("Hello world!"); - } - ) - ); - - media.addItem - ( new Example - ( "Chromeless SWF (AS3)" - , "Demonstrates playback of a chromeless, AS3 SWF. The SWF exposes an API that a custom MediaElement uses to control the video." - , function():MediaElement - { - return new ChromelessPlayerElement(new URLResource(CHROMELESS_SWF_AS3)); - } - ) - ); - - media.addItem - ( new Example - ( "Chromeless SWF (Flex)" - , "Demonstrates playback of a chromeless, Flex-based SWF. The SWF exposes an API that a custom MediaElement uses to control the video. Note that the SWF also exposes some simple controls for playback (Play, Pause, Mute). These buttons are included to demonstrate how the loaded SWF and the player can stay in sync." - , function():MediaElement - { - return new ChromelessPlayerElement(new URLResource(CHROMELESS_SWF_FLEX)); - } - ) - ); - - /* This example requires a local video file to be present. To run this, - uncomment this section and set a valid path for LOCAL_PROGRESSIVE. - - media.addItem - ( new Example - ( "Local Video" - , "Demonstrates playback of a local video file." - , function():MediaElement - { - return new VideoElement(new URLResource(LOCAL_PROGRESSIVE))); - } - ) - ); - */ - - // Composition Examples - // - - composition.addItem - ( new Example - ( "Serial Composition" - , "Demonstrates playback of a SerialElement that contains two videos (one progressive, one streaming), using the default layout settings. Note that the duration of the second video is not incorporated into the SerialElement until its playback begins (because we don't know the duration until it is loaded)." - , function():MediaElement - { - var resource:URLResource = new URLResource(REMOTE_PROGRESSIVE); - var resource2:URLResource = new URLResource(REMOTE_PROGRESSIVE2); - - var serial:SerialElement = new SerialElement(); - - var video1:VideoElement = new VideoElement(resource); - video1.defaultDuration = 32; - var video2:VideoElement = new VideoElement(resource2); - video2.defaultDuration = 27; - - serial.addChild(video1); - serial.addChild(video2); - - return serial; - } - ) - ); - - composition.addItem - ( new Example - ( "Serial Composition with Different Media Types" - , "Demonstrates different types of MediaElements in a serial composition. Includes a 3 Second image, 5 second subclip, and a 3 second SWF." - , function():MediaElement - { - var elem:SerialElement= new SerialElement(); - elem.addChild(new DurationElement(3, new ImageElement(new URLResource(REMOTE_IMAGE)))); - elem.addChild(new VideoElement(new StreamingURLResource(REMOTE_STREAM, StreamType.RECORDED, 0, 5))); - elem.addChild(new DurationElement(3,new SWFElement(new URLResource(REMOTE_SWF)))); - return elem; - } - ) - ); - - composition.addItem - ( new Example - ( "Parallel Composition" - , "Demonstrates playback of a ParallelElement that contains two videos (one progressive, one streaming), using the default layout settings. Note that only one video is shown. This is because both videos use the default layout settings, and thus overlap each other." - , function():MediaElement - { - var parallelElement:ParallelElement = new ParallelElement(); - parallelElement.addChild(new VideoElement(new URLResource(REMOTE_PROGRESSIVE))); - parallelElement.addChild(new VideoElement(new URLResource(REMOTE_STREAM))); - return parallelElement; - } - ) - ); - - composition.addItem - ( new Example - ( "Parallel Composition (Timed Banner)" - , "Demonstrates playback of a ParallelElement that contains a video and a banner. The banner only shows during seconds 10 to 20 of the video." - , function():MediaElement - { - // The display area for all media is 640x700. - var parallelElement:ParallelElement = new ParallelElement(); - var layout:LayoutMetadata = new LayoutMetadata(); - layout.horizontalAlign = HorizontalAlign.CENTER; - layout.verticalAlign = VerticalAlign.MIDDLE; - layout.width = 640 - layout.height = 700; - parallelElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - - // Create a SerialElement with two DurationElements. The first - // is a placeholder to delay the display of the second. The - // second represents the banner. - var serial:SerialElement = new SerialElement(); - serial.addChild(new DurationElement(10)); - serial.addChild(new DurationElement(10, new ImageElement(new URLResource(REMOTE_BANNER)))); - - // Place the banner at the top, centered horizontally. - layout = new LayoutMetadata(); - layout.top = 10; - layout.horizontalAlign = HorizontalAlign.CENTER; - serial.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - parallelElement.addChild(serial); - - // Place the video beneath. - var mediaElement2:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); - layout = new LayoutMetadata(); - layout.percentWidth = 100; - layout.top = 150; - layout.scaleMode = ScaleMode.LETTERBOX; - mediaElement2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - parallelElement.addChild(mediaElement2); - - return parallelElement; - } - ) - ); - - composition.addItem - ( new Example - ( "Serial Composition With Subclips" - , "Demonstrates playback of a SerialElement that contains one video chopped up into several subclips, each separated by the 5 second display of an image." - , function():MediaElement - { - var netLoader:NetLoader = new NetLoader(); - - var serialElement:SerialElement = new SerialElement(); - - var resource:StreamingURLResource = new StreamingURLResource(REMOTE_STREAM); - resource.clipEndTime = 15; - var videoElement:VideoElement = new VideoElement(resource, netLoader); - videoElement.defaultDuration = 15; - serialElement.addChild(videoElement); - - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1)))); - - resource = new StreamingURLResource(REMOTE_STREAM); - resource.clipStartTime = 15; - resource.clipEndTime = 22; - videoElement = new VideoElement(resource, netLoader); - videoElement.defaultDuration = 7; - serialElement.addChild(videoElement); - - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE2)))); - - resource = new StreamingURLResource(REMOTE_STREAM); - resource.clipStartTime = 22; - videoElement = new VideoElement(resource, netLoader); - videoElement.defaultDuration = 17; - serialElement.addChild(videoElement); - - return serialElement; - } - ) - ); - - composition.addItem - ( new Example - ( "Serial Composition With Preloaded Subclips" - , "Demonstrates playback of a SerialElement that contains multiple preloaded subclips. The advantage of preloaded subclips is that they are seekable even before the playhead first reaches the subclip." - , function():MediaElement - { - var netLoader:NetLoader = new NetLoader(); - - var serialElement:SerialElement = new SerialElement(); - - var resource:StreamingURLResource = new StreamingURLResource(REMOTE_STREAM); - resource.clipEndTime = 15; - var videoElement:VideoElement = new VideoElement(resource, netLoader); - videoElement.defaultDuration = 15; - serialElement.addChild(new PreloadingProxyElement(videoElement)); - - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1)))); - - resource = new StreamingURLResource(REMOTE_STREAM); - resource.clipStartTime = 15; - resource.clipEndTime = 22; - videoElement = new VideoElement(resource, netLoader); - videoElement.defaultDuration = 7; - serialElement.addChild(new PreloadingProxyElement(videoElement)); - - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE2)))); - - resource = new StreamingURLResource(REMOTE_STREAM); - resource.clipStartTime = 22; - videoElement = new VideoElement(resource, netLoader); - videoElement.defaultDuration = 17; - serialElement.addChild(new PreloadingProxyElement(videoElement)); - - return serialElement; - } - ) - ); - composition.addItem - ( new Example - ( "Serial Composition With Dynamic Streaming Subclips" - , "Demonstrates playback of a SerialElement that contains one dynamic streaming video chopped up into several subclips, each separated by the 5 second display of an image." - , function():MediaElement - { - var netLoader:NetLoader = new RTMPDynamicStreamingNetLoader(); - - var serialElement:SerialElement = new SerialElement(); - - var dsResource:DynamicStreamingResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); - for (var i:int = 0; i < 5; i++) - { - dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); - } - dsResource.clipEndTime = 10; - serialElement.addChild(new VideoElement(dsResource, netLoader)); - - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1)))); - - dsResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); - for (i = 0; i < 5; i++) - { - dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); - } - dsResource.clipStartTime = 150; - dsResource.clipEndTime = 172; - serialElement.addChild(new VideoElement(dsResource, netLoader)); - - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE2)))); - - dsResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); - for (i = 0; i < 5; i++) - { - dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); - } - dsResource.clipStartTime = 640; - serialElement.addChild(new VideoElement(dsResource, netLoader)); - - return new TraceListenerProxyElement(serialElement); - } - ) - ); - - composition.addItem - ( new Example - ( "BeaconElement for Analytics" - , "Demonstrates the use of BeaconElement to fire tracking events. Every few seconds, a \"ping\" is made. If you run this example while sniffing HTTP traffic, you can see the requests being made." - , function():MediaElement - { - var serialElement:SerialElement = new SerialElement(); - serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); - serialElement.addChild(new DurationElement(5)); - serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); - serialElement.addChild(new DurationElement(10)); - serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); - serialElement.addChild(new DurationElement(2)); - serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); - return serialElement; - } - ) - ); - - composition.addItem - ( new Example - ( "BeaconElement with a VideoElement" - , "Demonstrates the use of BeaconElement to fire tracking events in parallel with a VideoElement." - , function():MediaElement - { - var parallelElement:ParallelElement = new ParallelElement(); - parallelElement.addChild(new VideoElement(new URLResource(REMOTE_PROGRESSIVE))); - var serialElement:SerialElement = new SerialElement(); - serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); - serialElement.addChild(new DurationElement(5)); - serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); - serialElement.addChild(new DurationElement(10)); - serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); - serialElement.addChild(new DurationElement(2)); - serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); - parallelElement.addChild(serialElement); - return parallelElement; - } - ) - ); - - composition.addItem - ( new Example - ( "Text Sequencing" - , "Demonstrates the use of DurationElement to present a set of text elements in sequence." - , function():MediaElement - { - var serialElement:SerialElement = new SerialElement(); - serialElement.addChild(new DurationElement(3, new TextElement("War was Beginning."))); - serialElement.addChild(new DurationElement(3, new TextElement("Captain: What happen ?"))); - serialElement.addChild(new DurationElement(4, new TextElement("Mechanic: Somebody set up us the bomb."))); - serialElement.addChild(new DurationElement(3, new TextElement("Operator: We get signal."))); - serialElement.addChild(new DurationElement(3, new TextElement("Captain: What !"))); - serialElement.addChild(new DurationElement(3, new TextElement("Operator: Main screen turn on."))); - serialElement.addChild(new DurationElement(3, new TextElement("Captain: It's you !!"))); - serialElement.addChild(new DurationElement(3, new TextElement("CATS: How are you gentlemen !!"))); - serialElement.addChild(new DurationElement(5, new TextElement("CATS: All your base are belong to us."))); - serialElement.addChild(new DurationElement(5, new TextElement("CATS: You are on the way to destruction."))); - serialElement.addChild(new DurationElement(3, new TextElement("Captain: What you say !!"))); - serialElement.addChild(new DurationElement(4, new TextElement("CATS: You have no chance to survive make your time."))); - serialElement.addChild(new DurationElement(3, new TextElement("CATS: Ha ha ha ha ..."))); - serialElement.addChild(new DurationElement(3, new TextElement("Operator: Captain !!"))); - serialElement.addChild(new DurationElement(3, new TextElement("Captain: Take off every 'ZIG'!!"))); - serialElement.addChild(new DurationElement(3, new TextElement("Captain: You know what you doing."))); - serialElement.addChild(new DurationElement(3, new TextElement("Captain: Move 'ZIG'."))); - serialElement.addChild(new DurationElement(3, new TextElement("Captain: For great justice."))); - - return serialElement; - } - ) - ); - - composition.addItem - ( new Example - ( "Video with Recommendations Bumper" - , "Demonstrates how a recommendations bumper can be implemented. When the video finishes playback, a post-roll overlay is displayed. Clicking on this overlay will cause the player to 'jump' to a different example, similar to how some players can navigate to a different video based on user interaction." - , function():MediaElement - { - var recommendations:RecommendationsElement = new RecommendationsElement(); - var elem:SerialElement = new SerialElement(); - elem.addChild(new VideoElement(new URLResource(OSMF_ANIMATION))); - elem.addChild(recommendations); - - var layoutMetadata:LayoutMetadata = new LayoutMetadata(); - layoutMetadata.width = 640; - layoutMetadata.height = 360; - layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - layoutMetadata.scaleMode = ScaleMode.LETTERBOX; - - elem.metadata.addValue(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); - - return elem; - } - ) - ); - - composition.addItem - ( new Example - ( "Video with Timed Ad Insertion" - , "Demonstrates how pre-, post- and midroll ads can be added in such a way that the ad durations aren't included in the main timeline. Instead, they're shown in an overlay countdown timer." - , function():MediaElement - { - var elem:PreMidPostRollElement - = new PreMidPostRollElement - ( new VideoElement(new URLResource(OSMF_ANIMATION)) - , new VideoElement(new URLResource(REMOTE_PROGRESSIVE)) - , new VideoElement(new URLResource(OSMF_ANIMATION)) - , new VideoElement(new URLResource(REMOTE_PROGRESSIVE2)) - , new VideoElement(new URLResource(OSMF_ANIMATION)) - ); - - return elem; - } - ) - ); - - composition.addItem - ( new Example - ( "Synchronized Parallel Composition (Video Grid)" - , "Demonstrates playback of a ParallelElement that contains four videos, where all videos get paused when one of them is in a buffering state. Note the use of LayoutMetadata to show the videos in a grid." - , function():MediaElement - { - var parallelElement:SynchronizedParallelElement = new SynchronizedParallelElement(); - var layout:LayoutMetadata = new LayoutMetadata(); - layout.horizontalAlign = HorizontalAlign.CENTER; - layout.verticalAlign = VerticalAlign.MIDDLE; - parallelElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - - var mediaElement1:MediaElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); - layout = new LayoutMetadata(); - layout.left = 0; - layout.top = 0; - layout.percentWidth = 50; - layout.percentHeight = 50; - mediaElement1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - parallelElement.addChild(mediaElement1); - - var mediaElement2:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); - layout = new LayoutMetadata(); - layout.left = 0; - layout.bottom = 0; - layout.percentWidth = 50; - layout.percentHeight = 50; - mediaElement2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - parallelElement.addChild(mediaElement2); - - var mediaElement3:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); - layout = new LayoutMetadata(); - layout.right = 0; - layout.top = 0; - layout.percentWidth = 50; - layout.percentHeight = 50; - mediaElement3.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - parallelElement.addChild(mediaElement3); - - var mediaElement4:MediaElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE2)); - layout = new LayoutMetadata(); - layout.right = 0; - layout.bottom = 0; - layout.percentWidth = 50; - layout.percentHeight = 50; - mediaElement4.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - parallelElement.addChild(mediaElement4); - - return parallelElement; - } - ) - ); - - composition.addItem - ( new Example - ( "Poster Frame" - , "Demonstrates the use of a SerialElement to present a poster frame prior to playback. To see the poster frame, set Auto Play to false in the 'Play Options' dropdown. Note that we use a subclass of ImageElement which adds the PlayTrait to ensure that we can play through the image." - , function():MediaElement - { - var serialElement:SerialElement = new SerialElement(); - serialElement.addChild(new PosterFrameElement(new URLResource(REMOTE_IMAGE))); - serialElement.addChild(new VideoElement(new URLResource(REMOTE_STREAM))); - return serialElement; - } - ) - ); - - composition.addItem - ( new Example - ( "RTMP Poster Frame" - , "Demonstrates the use of a SerialElement to present a poster frame from an RTMP stream prior to playback. To see the poster frame, set Auto Play to false in the 'Play Options' dropdown. Note that we use a subclass of ImageElement which adds the PlayTrait to ensure that we can play through the image." - , function():MediaElement - { - var netLoader:NetLoader = new NetLoader(); - - var serialElement:SerialElement = new SerialElement(); - serialElement.addChild(new RTMPPosterFrameElement(new StreamingURLResource(REMOTE_STREAM), 5, netLoader)); - serialElement.addChild(new VideoElement(new URLResource(REMOTE_STREAM), netLoader)); - return serialElement; - } - ) - ); - - composition.addItem - ( new Example - ( "Poster Frame At End" - , "Demonstrates the use of a SerialElement to present a poster frame at the end of playback." - , function():MediaElement - { - var serialElement:SerialElement = new SerialElement(); - serialElement.addChild(new VideoElement(new URLResource(REMOTE_STREAM))); - serialElement.addChild(new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1))); - return serialElement; - } - ) - ); - - composition.addItem - ( new Example - ( "Slideshow" - , "Demonstrates the use of DurationElement to present a set of images in sequence." - , function():MediaElement - { - var serialElement:SerialElement = new SerialElement(); - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1)))); - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE2)))); - serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE3)))); - - return serialElement; - } - ) - ); - - // Proxy Examples - // - - proxies.addItem - ( new Example - ( "Unseekable ProxyElement (Streaming Video)" - , "Demonstrates the use of a custom ProxyElement to prevent the user from seeking another MediaElement, in this case a progressive VideoElement." - , function():MediaElement - { - return new UnseekableProxyElement(new VideoElement(new URLResource(REMOTE_STREAM))); - } - ) - ); - - proxies.addItem - ( new Example - ( "Switching ProxyElement (Two Videos)" - , "Demonstrates the use of a custom ProxyElement to provide a means to seamlessly switch between two MediaElements. In this case, we switch from one video to another every five seconds." - , function():MediaElement - { - var firstElement:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); - var secondElement:MediaElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); - return new SwitchingProxyElement(firstElement, secondElement, 5, 10); - } - ) - ); - - proxies.addItem - ( new Example - ( "Proxy-based Tracing (Dynamic Streaming Video)" - , "Demonstrates the use of a custom ListenerProxyElement to non-invasively listen in on the behavior of another MediaElement, in this case a VideoElement doing dynamic streaming. All playback events are sent to the trace console." - , function():MediaElement - { - var dsResource:DynamicStreamingResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); - for (var i:int = 0; i < 5; i++) - { - dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); - } - return new TraceListenerProxyElement(new VideoElement(dsResource)); - } - ) - ); - - proxies.addItem - ( new Example - ( "Proxy-based Tracing (SerialElement)" - , "Demonstrates the use of a custom ListenerProxyElement to non-invasively listen in on the behavior of another MediaElement, in this case a SerialElement containing two VideoElements. All playback events are sent to the trace console." - , function():MediaElement - { - var resource:URLResource = new URLResource(REMOTE_PROGRESSIVE); - var resource2:URLResource = new URLResource(REMOTE_PROGRESSIVE2); - - var serial:SerialElement = new SerialElement(); - - var video1:VideoElement = new VideoElement(resource); - video1.defaultDuration = 32; - var video2:VideoElement = new VideoElement(resource2); - video2.defaultDuration = 27; - - serial.addChild(video1); - serial.addChild(video2); - - return new TraceListenerProxyElement(serial); - } - ) - ); - - proxies.addItem - ( new Example - ( "Video URL Changer" - , "Demonstrates the use of a custom ProxyElement to perform preflight operations on a MediaElement in a non-invasive way. In this example, the URL of the video is changed during the load operation, so that instead of playing a streaming video, we play a progressive video." - , function():MediaElement - { - return new VideoProxyElement(new VideoElement(new URLResource(REMOTE_STREAM))); - } - ) - ); - - proxies.addItem - ( new Example - ( "Preflight Video Loader" - , "Demonstrates the use of a custom ProxyElement to perform preflight operations on a MediaElement in a non-invasive way. In this example, the custom ProxyElement performs some custom asynchronous logic after the video is loaded. (In this case, it simply runs a Timer for 2 seconds.) The proxy prevents the outside world from being aware that the video is loaded until that custom logic is completed." - , function():MediaElement - { - return new AsynchLoadingProxyElement(new VideoElement(new URLResource(REMOTE_STREAM))); - } - ) - ); - - // Layout Examples - // - - layout.addItem - ( new Example - ( "Parallel Composition (Adjacent)" - , "Demonstrates playback of a ParallelElement that contains two videos (one progressive, one streaming), with the videos laid out adjacently." - , function():MediaElement - { - var parallelElement:ParallelElement = new ParallelElement(); - var layout:LayoutMetadata = new LayoutMetadata(); - layout.layoutMode = LayoutMode.HORIZONTAL; - layout.horizontalAlign = HorizontalAlign.CENTER; - layout.verticalAlign = VerticalAlign.MIDDLE; - layout.width = 640 - layout.height = 352; - parallelElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - - var mediaElement1:MediaElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); - layout = new LayoutMetadata(); - layout.percentWidth = 50; - layout.percentHeight = 50; - layout.scaleMode = ScaleMode.LETTERBOX; - mediaElement1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - parallelElement.addChild(mediaElement1); - - var mediaElement2:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); - layout = new LayoutMetadata(); - layout.percentWidth = 50; - layout.percentHeight = 50; - layout.scaleMode = ScaleMode.LETTERBOX; - mediaElement2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - parallelElement.addChild(mediaElement2); - - return parallelElement; - } - , null - , "disable" - ) - ); - - layout.addItem - ( new Example - ( "Dynamic Layouts" - , "Demonstrates the use of the default OSMF layout renderer to dynamically change the spatial ordering of MediaElements within compositions." - , function():MediaElement - { - var parallelElement:ParallelElement = new ParallelElement(); - - var video1:VideoElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); - var video2:VideoElement = new VideoElement(new URLResource(REMOTE_STREAM)); - parallelElement.addChild(video1); - parallelElement.addChild(video2); - - var layoutVideo1:LayoutMetadata = new LayoutMetadata(); - layoutVideo1.percentWidth = 50; - layoutVideo1.percentHeight = 50; - video1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutVideo1); - - var layoutVideo2:LayoutMetadata = new LayoutMetadata(); - layoutVideo2.percentWidth = 50; - layoutVideo2.percentHeight = 50; - layoutVideo2.percentX = 50; - layoutVideo2.percentY = 25; - video2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutVideo2); - - var layoutParallelElement:LayoutMetadata = new LayoutMetadata(); - layoutParallelElement.width = 640; - layoutParallelElement.height = 358; - layoutParallelElement.horizontalAlign = HorizontalAlign.CENTER; - layoutParallelElement.verticalAlign = VerticalAlign.MIDDLE; - parallelElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutParallelElement); - - var delta:int = 1; - - timer.delay = 20; - timer.repeatCount = 0; - timer.addEventListener - ( TimerEvent.TIMER - , timerHandler = onTimer - ); - - function onTimer(event:Event):void - { - layoutVideo1.percentWidth += delta; - layoutVideo1.percentHeight += delta; - - layoutVideo2.percentY += delta / 2; - - if ( layoutVideo1.percentWidth < 25 - || layoutVideo1.percentWidth > 75 - ) - { - delta = -delta; - } - } - - timer.start(); - - return parallelElement; - } - , function():void - { - timer.stop(); - timer.reset(); - timer.removeEventListener - ( TimerEvent.TIMER - , timerHandler - ); - } - , "disable" - ) - ); - - layout.addItem - ( new Example - ( "Picture in Picture" - , "Demonstrates how to place two different videos in a composition, one large, and a small video in the corner." - , function():MediaElement - { - var elem:ParallelElement= new ParallelElement(); - var video1:VideoElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); - var video2:VideoElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE2)); - - var layout:LayoutMetadata = new LayoutMetadata(); - layout.percentWidth = 100; - layout.percentHeight = 100; - layout.index = 0; - layout.scaleMode = ScaleMode.LETTERBOX; - video1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - - layout = new LayoutMetadata(); - layout.percentWidth = 20; - layout.percentHeight = 20; - layout.index = 1; - layout.right = 15; - layout.top = 15; - layout.scaleMode = ScaleMode.LETTERBOX; - video2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); - - elem.addChild(video1); - elem.addChild(video2); - - return elem; - } - , null - , "disable" - ) - ); - - // Error Handling Examples - // - - errorHandling.addItem - ( new Example - ( "Invalid Progressive Video" - , "Demonstrates load failures and error handling for a progressive video with an invalid URL." - , function():MediaElement - { - return new VideoElement(new URLResource(REMOTE_INVALID_PROGRESSIVE)); - } - ) - ); - - errorHandling.addItem - ( new Example - ( "Invalid Streaming Video (Bad Server)" - , "Demonstrates load failures and error handling for a streaming video with an invalid server." - , function():MediaElement - { - return new VideoElement(new StreamingURLResource(REMOTE_INVALID_FMS_SERVER)); - } - ) - ); - - errorHandling.addItem - ( new Example - ( "Invalid Streaming Video (Bad Stream)" - , "Demonstrates load failures and error handling for a streaming video with an valid server but an invalid stream." - , function():MediaElement - { - return new VideoElement(new StreamingURLResource(REMOTE_INVALID_STREAM)); - } - ) - ); - - errorHandling.addItem - ( new Example - ( "Invalid Image" - , "Demonstrates load failures and error handling for an image with an invalid URL." - , function():MediaElement - { - return new ImageElement(new URLResource(REMOTE_INVALID_IMAGE)); - } - ) - ); - - errorHandling.addItem - ( new Example - ( "Invalid Progressive Audio" - , "Demonstrates load failures and error handling for a progressive audio file with an invalid URL." - , function():MediaElement - { - return new AudioElement(new URLResource(REMOTE_INVALID_MP3)); - } - ) - ); - - errorHandling.addItem - ( new Example - ( "Invalid Streaming Audio" - , "Demonstrates load failures and error handling for a streaming audio file with an invalid URL." - , function():MediaElement - { - return new AudioElement(new StreamingURLResource(REMOTE_INVALID_STREAM)); - } - ) - ); - - errorHandling.addItem - ( new Example - ( "Invalid MediaElement/MediaResource Pair" - , "Demonstrates load failures and error handling for when the resource passed to a MediaElement is of the wrong type. In this case, an MP3 resource is passed to a VideoElement." - , function():MediaElement - { - return new VideoElement(new URLResource(REMOTE_MP3)); - } - ) - ); - - errorHandling.addItem - ( new Example - ( "Invalid Serial Composition" - , "Demonstrates load failures and error handling for a SerialElement whose second element has an invalid URL." - , function():MediaElement - { - var serialElement:SerialElement = new SerialElement(); - serialElement.addChild(new VideoElement(new URLResource(REMOTE_PROGRESSIVE))); - serialElement.addChild(new VideoElement(new URLResource(REMOTE_INVALID_STREAM))); - return serialElement; - } - ) - ); - - examples.addItem(media); - examples.addItem(composition); - examples.addItem(proxies); - examples.addItem(layout); - examples.addItem(errorHandling); - - return examples; - } - - private static const BANNER_1:String = "http://www.iab.net/media/image/468x60.gif"; - private static const BANNER_2:String = "http://www.iab.net/media/image/234x60.gif"; - private static const BANNER_3:String = "http://www.iab.net/media/image/120x60.gif"; - private static const REMOTE_PROGRESSIVE:String = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; - private static const REMOTE_PROGRESSIVE2:String = "http://mediapm.edgesuite.net/strobe/content/test/elephants_dream_768x428_24_short.flv"; - private static const REMOTE_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - private static const REMOTE_AUDIO_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mp3:mediapm/strobe/content/test/train_1500"; - private static const REMOTE_LIVE_STREAM:String = "rtmp://cp34973.live.edgefcs.net/live/Flash_Live_Benchmark@632"; - private static const REMOTE_MBR_STREAM_HOST:String = "rtmp://cp67126.edgefcs.net/ondemand"; - private static const REMOTE_MP3:String = "http://mediapm.edgesuite.net/osmf/content/test/train_1500.mp3"; - private static const REMOTE_IMAGE:String = "http://mediapm.edgesuite.net/strobe/content/test/train.jpg"; - private static const REMOTE_BANNER:String = "http://mediapm.edgesuite.net/osmf/image/banner.jpg"; - private static const REMOTE_SLIDESHOW_IMAGE1:String = "http://mediapm.edgesuite.net/osmf/swf/OSMFPlayer/images/vegetation.jpg"; - private static const REMOTE_SLIDESHOW_IMAGE2:String = "http://mediapm.edgesuite.net/strobe/content/test/train.jpg"; - private static const REMOTE_SLIDESHOW_IMAGE3:String = "http://mediapm.edgesuite.net/osmf/image/flex_48x45.gif"; - private static const REMOTE_SWF:String = "http://mediapm.edgesuite.net/osmf/content/test/ten.swf"; - private static const REMOTE_INVALID_PROGRESSIVE:String = "http://mediapm.edgesuite.net/strobe/content/test/fail.flv"; - private static const REMOTE_INVALID_FMS_SERVER:String = "rtmp://cp67126.fail.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - private static const REMOTE_INVALID_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/fail/SpaceAloneHD_sounas_640_500_short"; - private static const REMOTE_INVALID_IMAGE:String = "http://mediapm.edgesuite.net/osmf/image/fail.png"; - private static const REMOTE_INVALID_MP3:String = "http://mediapm.edgesuite.net/osmf/content/test/fail.mp3"; - private static const LOCAL_PROGRESSIVE:String = "video.flv"; - private static const CHROMELESS_SWF_AS3:String = "http://mediapm.edgesuite.net/osmf/swf/ChromelessPlayer.swf"; - private static const CHROMELESS_SWF_FLEX:String = "http://mediapm.edgesuite.net/osmf/swf/ChromelessFlexPlayer.swf"; - private static const BEACON_URL:String = "http://mediapm.edgesuite.net/osmf/image/adobe-lq.png"; - private static const REMOTE_MANIFEST:String = "http://mediapm.edgesuite.net/osmf/content/test/manifest-files/progressive.f4m"; - private static const REMOTE_MBR_MANIFEST:String = "http://mediapm.edgesuite.net/osmf/content/test/manifest-files/dynamic_Streaming.f4m"; - private static const OSMF_ANIMATION:String = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; - - private static const MBR_STREAM_ITEMS:Array = - [ new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_768x428_24.0fps_408kbps.mp4", 408, 768, 428) - , new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_768x428_24.0fps_608kbps.mp4", 608, 768, 428) - , new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1024x522_24.0fps_908kbps.mp4", 908, 1024, 522) - , new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1024x522_24.0fps_1308kbps.mp4", 1308, 1024, 522) - , new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1280x720_24.0fps_1708kbps.mp4", 1708, 1280, 720) - ]; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples +{ + import flash.events.Event; + import flash.events.TimerEvent; + import flash.net.NetConnection; + import flash.net.NetStream; + import flash.utils.Timer; + + import mx.collections.ArrayCollection; + + import org.osmf.elements.AudioElement; + import org.osmf.elements.BeaconElement; + import org.osmf.elements.DurationElement; + import org.osmf.elements.F4MElement; + import org.osmf.elements.ImageElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.SWFElement; + import org.osmf.elements.SerialElement; + import org.osmf.elements.VideoElement; + import org.osmf.examples.ads.PreMidPostRollElement; + import org.osmf.examples.buffering.DualThresholdBufferingProxyElement; + import org.osmf.examples.buffering.SynchronizedParallelElement; + import org.osmf.examples.chromeless.ChromelessPlayerElement; + import org.osmf.examples.loaderproxy.AsynchLoadingProxyElement; + import org.osmf.examples.loaderproxy.VideoProxyElement; + import org.osmf.examples.netconnection.SimpleNetLoader; + import org.osmf.examples.posterframe.PosterFrameElement; + import org.osmf.examples.posterframe.RTMPPosterFrameElement; + import org.osmf.examples.recommendations.RecommendationsElement; + import org.osmf.examples.seeking.PreloadingProxyElement; + import org.osmf.examples.seeking.UnseekableProxyElement; + import org.osmf.examples.switchingproxy.SwitchingProxyElement; + import org.osmf.examples.text.TextElement; + import org.osmf.examples.traceproxy.TraceListenerProxyElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaElement; + import org.osmf.media.URLResource; + import org.osmf.net.DynamicStreamingItem; + import org.osmf.net.DynamicStreamingResource; + import org.osmf.net.NetLoader; + import org.osmf.net.StreamType; + import org.osmf.net.StreamingURLResource; + import org.osmf.net.rtmpstreaming.RTMPDynamicStreamingNetLoader; + import org.osmf.traits.BufferTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + + /** + * Central repository of all examples for this application. + **/ + public class AllExamples + { + /** + * All examples to be used in the player. + **/ + public static function get examples():ArrayCollection + { + var examples:ArrayCollection = new ArrayCollection(); + var mediaElement:MediaElement = null; + + var timer:Timer = new Timer(1000); + var timerHandler:Function; + + + var media:Category = new Category("Media"); + var composition:Category = new Category("Composition"); + var proxies:Category = new Category("Proxies"); + var layout:Category = new Category("Layout"); + var errorHandling:Category = new Category("Error Handling"); + + // Core Media Examples + // + + media.addItem + ( new Example + ( "Progressive Video" + , "Demonstrates playback of a progressive video using VideoElement and NetLoader." + , function():MediaElement + { + return new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); + } + ) + ); + + media.addItem + ( new Example + ( "Streaming Video" + , "Demonstrates playback of a streaming video using VideoElement and NetLoader." + , function():MediaElement + { + return new VideoElement(new URLResource(REMOTE_STREAM)); + } + ) + ); + + media.addItem + ( new Example + ( "Dynamic Streaming Video" + , "Demonstrates the use of dynamic streaming. The player will automatically switch between five variations of the same stream, each encoded at a different bitrate (from 408 Kbps to 1708 Kbps), based on the available bandwidth. Note that the switching behavior can be modified via custom switching rules." + , function():MediaElement + { + var dsResource:DynamicStreamingResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); + for (var i:int = 0; i < 5; i++) + { + dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); + } + return new VideoElement(dsResource); + } + , null + , "letterbox" + ) + ); + + media.addItem + ( new Example + ( "Live Streaming Video" + , "Demonstrates playback of a live video stream." + , function():MediaElement + { + return new VideoElement(new StreamingURLResource(REMOTE_LIVE_STREAM, StreamType.LIVE)); + } + ) + ); + + media.addItem + ( new Example + ( "Streaming Video With Dual-Threshold Buffer" + , "Demonstrates playback of a streaming video with a dual-threshold buffer. The buffer starts small, but increases once we've buffered enough data to enable playback. The larger buffer reduces the chance that a rebuffer will need to occur." + , function():MediaElement + { + var videoElement:VideoElement = new VideoElement(new URLResource(REMOTE_STREAM)); + return new DualThresholdBufferingProxyElement(2, 15, videoElement); + } + ) + ); + + media.addItem + ( new Example + ( "Progressive Video With Dynamic Buffer" + , "Demonstrates playback of a progressive video with a dynamic buffer. The size of the buffer grows slowly as the video plays, then shrinks back down again." + , function():MediaElement + { + var videoElement:VideoElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); + + // Trigger the timer every second. + timer.delay = 1000; + timer.repeatCount = 20; + timer.addEventListener(TimerEvent.TIMER, timerHandler = onTimer); + timer.start(); + + function onTimer(event:TimerEvent):void + { + // Only adjust the buffer while we're playing. + var playTrait:PlayTrait = videoElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + var bufferTrait:BufferTrait = videoElement.getTrait(MediaTraitType.BUFFER) as BufferTrait; + if (bufferTrait && !bufferTrait.buffering && playTrait && playTrait.playState == PlayState.PLAYING) + { + if (timer.currentCount <= 10) + { + bufferTrait.bufferTime += 1.0; + } + else + { + bufferTrait.bufferTime -= 1.0; + } + } + } + + return videoElement; + } + , function():void + { + timer.stop(); + timer.reset(); + timer.removeEventListener + ( TimerEvent.TIMER + , timerHandler + ); + } + ) + ); + + media.addItem + ( new Example + ( "Image" + , "Demonstrates display of an image using ImageElement and ImageLoader." + , function():MediaElement + { + return new ImageElement(new URLResource(REMOTE_IMAGE)); + } + ) + ); + + media.addItem + ( new Example + ( "Timed Image" + , "Demonstrates display of an image for a fixed amount of time." + , function():MediaElement + { + return new DurationElement(4, new ImageElement(new URLResource(REMOTE_IMAGE))); + } + ) + ); + + media.addItem + ( new Example + ( "SWF" + , "Demonstrates display of a SWF using SWFElement and SWFLoader." + , function():MediaElement + { + return new SWFElement(new URLResource(REMOTE_SWF) ); + } + ) + ); + + media.addItem + ( new Example + ( "Progressive Audio" + , "Demonstrates playback of a progressive audio file using AudioElement and SoundLoader." + , function():MediaElement + { + return new AudioElement(new URLResource(REMOTE_MP3)); + } + ) + ); + + media.addItem + ( new Example + ( "Streaming Audio" + , "Demonstrates playback of a streaming audio file using AudioElement and NetLoader." + , function():MediaElement + { + return new AudioElement(new StreamingURLResource(REMOTE_AUDIO_STREAM)); + } + ) + ); + + media.addItem + ( new Example + ( "Streaming Video with Connection-level Parameters" + , "Demonstrates how parameters can be passed to both the NetConnection.connect call, and NetStream.play()." + , function():MediaElement + { + var videoElement:VideoElement = new VideoElement(new URLResource(REMOTE_STREAM + "?param1=value1¶m2=value2")); + return videoElement; + } + ) + ); + + media.addItem + ( new Example + ( "Streaming Video As Subclip" + , "Demonstrates playback of a subclip of a streaming video using metadata to specify the start and end times." + , function():MediaElement + { + var resource:StreamingURLResource = new StreamingURLResource(REMOTE_STREAM); + resource.clipStartTime = 10; + resource.clipEndTime = 25; + return new VideoElement(resource); + } + ) + ); + + media.addItem + ( new Example + ( "Flash Media Manifest (F4M) with Progressive Video" + , "Demonstrates the use of a Flash Media Manifest file (F4M) for a progressive video." + , function():MediaElement + { + var elem:F4MElement = new F4MElement(); + elem.resource = new URLResource(REMOTE_MANIFEST); + return elem; + } + ) + ); + + media.addItem + ( new Example + ( "Flash Media Manifest (F4M) with Dynamic Streaming Video" + , "Demonstrates the use of a Flash Media Manifest file (F4M) for dynamic streaming video." + , function():MediaElement + { + var elem:F4MElement = new F4MElement(); + elem.resource = new URLResource(REMOTE_MBR_MANIFEST); + return elem; + } + ) + ); + + media.addItem + ( new Example + ( "Streaming Video With an Injected NetConnection" + , "Demonstrates playback of a video where the NetConnection and NetStream are specified externally, rather than created by the NetLoader. This approach is useful when you're integrating with an existing NetConnection framework. For simplicity, this example plays a progressive video, but the approach should also work for streaming video." + , function():MediaElement + { + var netConnection:NetConnection = new NetConnection(); + netConnection.connect(null); + var netStream:NetStream = new NetStream(netConnection); + return new VideoElement(new URLResource(REMOTE_PROGRESSIVE), new SimpleNetLoader(netConnection, netStream)); + } + ) + ); + + media.addItem + ( new Example + ( "Text" + , "Demonstrates a custom MediaElement that displays text." + , function():MediaElement + { + return new TextElement("Hello world!"); + } + ) + ); + + media.addItem + ( new Example + ( "Chromeless SWF (AS3)" + , "Demonstrates playback of a chromeless, AS3 SWF. The SWF exposes an API that a custom MediaElement uses to control the video." + , function():MediaElement + { + return new ChromelessPlayerElement(new URLResource(CHROMELESS_SWF_AS3)); + } + ) + ); + + media.addItem + ( new Example + ( "Chromeless SWF (Flex)" + , "Demonstrates playback of a chromeless, Flex-based SWF. The SWF exposes an API that a custom MediaElement uses to control the video. Note that the SWF also exposes some simple controls for playback (Play, Pause, Mute). These buttons are included to demonstrate how the loaded SWF and the player can stay in sync." + , function():MediaElement + { + return new ChromelessPlayerElement(new URLResource(CHROMELESS_SWF_FLEX)); + } + ) + ); + + /* This example requires a local video file to be present. To run this, + uncomment this section and set a valid path for LOCAL_PROGRESSIVE. + + media.addItem + ( new Example + ( "Local Video" + , "Demonstrates playback of a local video file." + , function():MediaElement + { + return new VideoElement(new URLResource(LOCAL_PROGRESSIVE))); + } + ) + ); + */ + + // Composition Examples + // + + composition.addItem + ( new Example + ( "Serial Composition" + , "Demonstrates playback of a SerialElement that contains two videos (one progressive, one streaming), using the default layout settings. Note that the duration of the second video is not incorporated into the SerialElement until its playback begins (because we don't know the duration until it is loaded)." + , function():MediaElement + { + var resource:URLResource = new URLResource(REMOTE_PROGRESSIVE); + var resource2:URLResource = new URLResource(REMOTE_PROGRESSIVE2); + + var serial:SerialElement = new SerialElement(); + + var video1:VideoElement = new VideoElement(resource); + video1.defaultDuration = 32; + var video2:VideoElement = new VideoElement(resource2); + video2.defaultDuration = 27; + + serial.addChild(video1); + serial.addChild(video2); + + return serial; + } + ) + ); + + composition.addItem + ( new Example + ( "Serial Composition with Different Media Types" + , "Demonstrates different types of MediaElements in a serial composition. Includes a 3 Second image, 5 second subclip, and a 3 second SWF." + , function():MediaElement + { + var elem:SerialElement= new SerialElement(); + elem.addChild(new DurationElement(3, new ImageElement(new URLResource(REMOTE_IMAGE)))); + elem.addChild(new VideoElement(new StreamingURLResource(REMOTE_STREAM, StreamType.RECORDED, 0, 5))); + elem.addChild(new DurationElement(3,new SWFElement(new URLResource(REMOTE_SWF)))); + return elem; + } + ) + ); + + composition.addItem + ( new Example + ( "Parallel Composition" + , "Demonstrates playback of a ParallelElement that contains two videos (one progressive, one streaming), using the default layout settings. Note that only one video is shown. This is because both videos use the default layout settings, and thus overlap each other." + , function():MediaElement + { + var parallelElement:ParallelElement = new ParallelElement(); + parallelElement.addChild(new VideoElement(new URLResource(REMOTE_PROGRESSIVE))); + parallelElement.addChild(new VideoElement(new URLResource(REMOTE_STREAM))); + return parallelElement; + } + ) + ); + + composition.addItem + ( new Example + ( "Parallel Composition (Timed Banner)" + , "Demonstrates playback of a ParallelElement that contains a video and a banner. The banner only shows during seconds 10 to 20 of the video." + , function():MediaElement + { + // The display area for all media is 640x700. + var parallelElement:ParallelElement = new ParallelElement(); + var layout:LayoutMetadata = new LayoutMetadata(); + layout.horizontalAlign = HorizontalAlign.CENTER; + layout.verticalAlign = VerticalAlign.MIDDLE; + layout.width = 640 + layout.height = 700; + parallelElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + + // Create a SerialElement with two DurationElements. The first + // is a placeholder to delay the display of the second. The + // second represents the banner. + var serial:SerialElement = new SerialElement(); + serial.addChild(new DurationElement(10)); + serial.addChild(new DurationElement(10, new ImageElement(new URLResource(REMOTE_BANNER)))); + + // Place the banner at the top, centered horizontally. + layout = new LayoutMetadata(); + layout.top = 10; + layout.horizontalAlign = HorizontalAlign.CENTER; + serial.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + parallelElement.addChild(serial); + + // Place the video beneath. + var mediaElement2:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); + layout = new LayoutMetadata(); + layout.percentWidth = 100; + layout.top = 150; + layout.scaleMode = ScaleMode.LETTERBOX; + mediaElement2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + parallelElement.addChild(mediaElement2); + + return parallelElement; + } + ) + ); + + composition.addItem + ( new Example + ( "Serial Composition With Subclips" + , "Demonstrates playback of a SerialElement that contains one video chopped up into several subclips, each separated by the 5 second display of an image." + , function():MediaElement + { + var netLoader:NetLoader = new NetLoader(); + + var serialElement:SerialElement = new SerialElement(); + + var resource:StreamingURLResource = new StreamingURLResource(REMOTE_STREAM); + resource.clipEndTime = 15; + var videoElement:VideoElement = new VideoElement(resource, netLoader); + videoElement.defaultDuration = 15; + serialElement.addChild(videoElement); + + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1)))); + + resource = new StreamingURLResource(REMOTE_STREAM); + resource.clipStartTime = 15; + resource.clipEndTime = 22; + videoElement = new VideoElement(resource, netLoader); + videoElement.defaultDuration = 7; + serialElement.addChild(videoElement); + + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE2)))); + + resource = new StreamingURLResource(REMOTE_STREAM); + resource.clipStartTime = 22; + videoElement = new VideoElement(resource, netLoader); + videoElement.defaultDuration = 17; + serialElement.addChild(videoElement); + + return serialElement; + } + ) + ); + + composition.addItem + ( new Example + ( "Serial Composition With Preloaded Subclips" + , "Demonstrates playback of a SerialElement that contains multiple preloaded subclips. The advantage of preloaded subclips is that they are seekable even before the playhead first reaches the subclip." + , function():MediaElement + { + var netLoader:NetLoader = new NetLoader(); + + var serialElement:SerialElement = new SerialElement(); + + var resource:StreamingURLResource = new StreamingURLResource(REMOTE_STREAM); + resource.clipEndTime = 15; + var videoElement:VideoElement = new VideoElement(resource, netLoader); + videoElement.defaultDuration = 15; + serialElement.addChild(new PreloadingProxyElement(videoElement)); + + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1)))); + + resource = new StreamingURLResource(REMOTE_STREAM); + resource.clipStartTime = 15; + resource.clipEndTime = 22; + videoElement = new VideoElement(resource, netLoader); + videoElement.defaultDuration = 7; + serialElement.addChild(new PreloadingProxyElement(videoElement)); + + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE2)))); + + resource = new StreamingURLResource(REMOTE_STREAM); + resource.clipStartTime = 22; + videoElement = new VideoElement(resource, netLoader); + videoElement.defaultDuration = 17; + serialElement.addChild(new PreloadingProxyElement(videoElement)); + + return serialElement; + } + ) + ); + composition.addItem + ( new Example + ( "Serial Composition With Dynamic Streaming Subclips" + , "Demonstrates playback of a SerialElement that contains one dynamic streaming video chopped up into several subclips, each separated by the 5 second display of an image." + , function():MediaElement + { + var netLoader:NetLoader = new RTMPDynamicStreamingNetLoader(); + + var serialElement:SerialElement = new SerialElement(); + + var dsResource:DynamicStreamingResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); + for (var i:int = 0; i < 5; i++) + { + dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); + } + dsResource.clipEndTime = 10; + serialElement.addChild(new VideoElement(dsResource, netLoader)); + + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1)))); + + dsResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); + for (i = 0; i < 5; i++) + { + dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); + } + dsResource.clipStartTime = 150; + dsResource.clipEndTime = 172; + serialElement.addChild(new VideoElement(dsResource, netLoader)); + + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE2)))); + + dsResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); + for (i = 0; i < 5; i++) + { + dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); + } + dsResource.clipStartTime = 640; + serialElement.addChild(new VideoElement(dsResource, netLoader)); + + return new TraceListenerProxyElement(serialElement); + } + ) + ); + + composition.addItem + ( new Example + ( "BeaconElement for Analytics" + , "Demonstrates the use of BeaconElement to fire tracking events. Every few seconds, a \"ping\" is made. If you run this example while sniffing HTTP traffic, you can see the requests being made." + , function():MediaElement + { + var serialElement:SerialElement = new SerialElement(); + serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); + serialElement.addChild(new DurationElement(5)); + serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); + serialElement.addChild(new DurationElement(10)); + serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); + serialElement.addChild(new DurationElement(2)); + serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); + return serialElement; + } + ) + ); + + composition.addItem + ( new Example + ( "BeaconElement with a VideoElement" + , "Demonstrates the use of BeaconElement to fire tracking events in parallel with a VideoElement." + , function():MediaElement + { + var parallelElement:ParallelElement = new ParallelElement(); + parallelElement.addChild(new VideoElement(new URLResource(REMOTE_PROGRESSIVE))); + var serialElement:SerialElement = new SerialElement(); + serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); + serialElement.addChild(new DurationElement(5)); + serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); + serialElement.addChild(new DurationElement(10)); + serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); + serialElement.addChild(new DurationElement(2)); + serialElement.addChild(new BeaconElement(BEACON_URL + "?random=" + Math.random())); + parallelElement.addChild(serialElement); + return parallelElement; + } + ) + ); + + composition.addItem + ( new Example + ( "Text Sequencing" + , "Demonstrates the use of DurationElement to present a set of text elements in sequence." + , function():MediaElement + { + var serialElement:SerialElement = new SerialElement(); + serialElement.addChild(new DurationElement(3, new TextElement("War was Beginning."))); + serialElement.addChild(new DurationElement(3, new TextElement("Captain: What happen ?"))); + serialElement.addChild(new DurationElement(4, new TextElement("Mechanic: Somebody set up us the bomb."))); + serialElement.addChild(new DurationElement(3, new TextElement("Operator: We get signal."))); + serialElement.addChild(new DurationElement(3, new TextElement("Captain: What !"))); + serialElement.addChild(new DurationElement(3, new TextElement("Operator: Main screen turn on."))); + serialElement.addChild(new DurationElement(3, new TextElement("Captain: It's you !!"))); + serialElement.addChild(new DurationElement(3, new TextElement("CATS: How are you gentlemen !!"))); + serialElement.addChild(new DurationElement(5, new TextElement("CATS: All your base are belong to us."))); + serialElement.addChild(new DurationElement(5, new TextElement("CATS: You are on the way to destruction."))); + serialElement.addChild(new DurationElement(3, new TextElement("Captain: What you say !!"))); + serialElement.addChild(new DurationElement(4, new TextElement("CATS: You have no chance to survive make your time."))); + serialElement.addChild(new DurationElement(3, new TextElement("CATS: Ha ha ha ha ..."))); + serialElement.addChild(new DurationElement(3, new TextElement("Operator: Captain !!"))); + serialElement.addChild(new DurationElement(3, new TextElement("Captain: Take off every 'ZIG'!!"))); + serialElement.addChild(new DurationElement(3, new TextElement("Captain: You know what you doing."))); + serialElement.addChild(new DurationElement(3, new TextElement("Captain: Move 'ZIG'."))); + serialElement.addChild(new DurationElement(3, new TextElement("Captain: For great justice."))); + + return serialElement; + } + ) + ); + + composition.addItem + ( new Example + ( "Video with Recommendations Bumper" + , "Demonstrates how a recommendations bumper can be implemented. When the video finishes playback, a post-roll overlay is displayed. Clicking on this overlay will cause the player to 'jump' to a different example, similar to how some players can navigate to a different video based on user interaction." + , function():MediaElement + { + var recommendations:RecommendationsElement = new RecommendationsElement(); + var elem:SerialElement = new SerialElement(); + elem.addChild(new VideoElement(new URLResource(OSMF_ANIMATION))); + elem.addChild(recommendations); + + var layoutMetadata:LayoutMetadata = new LayoutMetadata(); + layoutMetadata.width = 640; + layoutMetadata.height = 360; + layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + layoutMetadata.scaleMode = ScaleMode.LETTERBOX; + + elem.metadata.addValue(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); + + return elem; + } + ) + ); + + composition.addItem + ( new Example + ( "Video with Timed Ad Insertion" + , "Demonstrates how pre-, post- and midroll ads can be added in such a way that the ad durations aren't included in the main timeline. Instead, they're shown in an overlay countdown timer." + , function():MediaElement + { + var elem:PreMidPostRollElement + = new PreMidPostRollElement + ( new VideoElement(new URLResource(OSMF_ANIMATION)) + , new VideoElement(new URLResource(REMOTE_PROGRESSIVE)) + , new VideoElement(new URLResource(OSMF_ANIMATION)) + , new VideoElement(new URLResource(REMOTE_PROGRESSIVE2)) + , new VideoElement(new URLResource(OSMF_ANIMATION)) + ); + + return elem; + } + ) + ); + + composition.addItem + ( new Example + ( "Synchronized Parallel Composition (Video Grid)" + , "Demonstrates playback of a ParallelElement that contains four videos, where all videos get paused when one of them is in a buffering state. Note the use of LayoutMetadata to show the videos in a grid." + , function():MediaElement + { + var parallelElement:SynchronizedParallelElement = new SynchronizedParallelElement(); + var layout:LayoutMetadata = new LayoutMetadata(); + layout.horizontalAlign = HorizontalAlign.CENTER; + layout.verticalAlign = VerticalAlign.MIDDLE; + parallelElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + + var mediaElement1:MediaElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); + layout = new LayoutMetadata(); + layout.left = 0; + layout.top = 0; + layout.percentWidth = 50; + layout.percentHeight = 50; + mediaElement1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + parallelElement.addChild(mediaElement1); + + var mediaElement2:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); + layout = new LayoutMetadata(); + layout.left = 0; + layout.bottom = 0; + layout.percentWidth = 50; + layout.percentHeight = 50; + mediaElement2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + parallelElement.addChild(mediaElement2); + + var mediaElement3:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); + layout = new LayoutMetadata(); + layout.right = 0; + layout.top = 0; + layout.percentWidth = 50; + layout.percentHeight = 50; + mediaElement3.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + parallelElement.addChild(mediaElement3); + + var mediaElement4:MediaElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE2)); + layout = new LayoutMetadata(); + layout.right = 0; + layout.bottom = 0; + layout.percentWidth = 50; + layout.percentHeight = 50; + mediaElement4.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + parallelElement.addChild(mediaElement4); + + return parallelElement; + } + ) + ); + + composition.addItem + ( new Example + ( "Poster Frame" + , "Demonstrates the use of a SerialElement to present a poster frame prior to playback. To see the poster frame, set Auto Play to false in the 'Play Options' dropdown. Note that we use a subclass of ImageElement which adds the PlayTrait to ensure that we can play through the image." + , function():MediaElement + { + var serialElement:SerialElement = new SerialElement(); + serialElement.addChild(new PosterFrameElement(new URLResource(REMOTE_IMAGE))); + serialElement.addChild(new VideoElement(new URLResource(REMOTE_STREAM))); + return serialElement; + } + ) + ); + + composition.addItem + ( new Example + ( "RTMP Poster Frame" + , "Demonstrates the use of a SerialElement to present a poster frame from an RTMP stream prior to playback. To see the poster frame, set Auto Play to false in the 'Play Options' dropdown. Note that we use a subclass of ImageElement which adds the PlayTrait to ensure that we can play through the image." + , function():MediaElement + { + var netLoader:NetLoader = new NetLoader(); + + var serialElement:SerialElement = new SerialElement(); + serialElement.addChild(new RTMPPosterFrameElement(new StreamingURLResource(REMOTE_STREAM), 5, netLoader)); + serialElement.addChild(new VideoElement(new URLResource(REMOTE_STREAM), netLoader)); + return serialElement; + } + ) + ); + + composition.addItem + ( new Example + ( "Poster Frame At End" + , "Demonstrates the use of a SerialElement to present a poster frame at the end of playback." + , function():MediaElement + { + var serialElement:SerialElement = new SerialElement(); + serialElement.addChild(new VideoElement(new URLResource(REMOTE_STREAM))); + serialElement.addChild(new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1))); + return serialElement; + } + ) + ); + + composition.addItem + ( new Example + ( "Slideshow" + , "Demonstrates the use of DurationElement to present a set of images in sequence." + , function():MediaElement + { + var serialElement:SerialElement = new SerialElement(); + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE1)))); + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE2)))); + serialElement.addChild(new DurationElement(5, new ImageElement(new URLResource(REMOTE_SLIDESHOW_IMAGE3)))); + + return serialElement; + } + ) + ); + + // Proxy Examples + // + + proxies.addItem + ( new Example + ( "Unseekable ProxyElement (Streaming Video)" + , "Demonstrates the use of a custom ProxyElement to prevent the user from seeking another MediaElement, in this case a progressive VideoElement." + , function():MediaElement + { + return new UnseekableProxyElement(new VideoElement(new URLResource(REMOTE_STREAM))); + } + ) + ); + + proxies.addItem + ( new Example + ( "Switching ProxyElement (Two Videos)" + , "Demonstrates the use of a custom ProxyElement to provide a means to seamlessly switch between two MediaElements. In this case, we switch from one video to another every five seconds." + , function():MediaElement + { + var firstElement:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); + var secondElement:MediaElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); + return new SwitchingProxyElement(firstElement, secondElement, 5, 10); + } + ) + ); + + proxies.addItem + ( new Example + ( "Proxy-based Tracing (Dynamic Streaming Video)" + , "Demonstrates the use of a custom ListenerProxyElement to non-invasively listen in on the behavior of another MediaElement, in this case a VideoElement doing dynamic streaming. All playback events are sent to the trace console." + , function():MediaElement + { + var dsResource:DynamicStreamingResource = new DynamicStreamingResource(REMOTE_MBR_STREAM_HOST); + for (var i:int = 0; i < 5; i++) + { + dsResource.streamItems.push(MBR_STREAM_ITEMS[i]); + } + return new TraceListenerProxyElement(new VideoElement(dsResource)); + } + ) + ); + + proxies.addItem + ( new Example + ( "Proxy-based Tracing (SerialElement)" + , "Demonstrates the use of a custom ListenerProxyElement to non-invasively listen in on the behavior of another MediaElement, in this case a SerialElement containing two VideoElements. All playback events are sent to the trace console." + , function():MediaElement + { + var resource:URLResource = new URLResource(REMOTE_PROGRESSIVE); + var resource2:URLResource = new URLResource(REMOTE_PROGRESSIVE2); + + var serial:SerialElement = new SerialElement(); + + var video1:VideoElement = new VideoElement(resource); + video1.defaultDuration = 32; + var video2:VideoElement = new VideoElement(resource2); + video2.defaultDuration = 27; + + serial.addChild(video1); + serial.addChild(video2); + + return new TraceListenerProxyElement(serial); + } + ) + ); + + proxies.addItem + ( new Example + ( "Video URL Changer" + , "Demonstrates the use of a custom ProxyElement to perform preflight operations on a MediaElement in a non-invasive way. In this example, the URL of the video is changed during the load operation, so that instead of playing a streaming video, we play a progressive video." + , function():MediaElement + { + return new VideoProxyElement(new VideoElement(new URLResource(REMOTE_STREAM))); + } + ) + ); + + proxies.addItem + ( new Example + ( "Preflight Video Loader" + , "Demonstrates the use of a custom ProxyElement to perform preflight operations on a MediaElement in a non-invasive way. In this example, the custom ProxyElement performs some custom asynchronous logic after the video is loaded. (In this case, it simply runs a Timer for 2 seconds.) The proxy prevents the outside world from being aware that the video is loaded until that custom logic is completed." + , function():MediaElement + { + return new AsynchLoadingProxyElement(new VideoElement(new URLResource(REMOTE_STREAM))); + } + ) + ); + + // Layout Examples + // + + layout.addItem + ( new Example + ( "Parallel Composition (Adjacent)" + , "Demonstrates playback of a ParallelElement that contains two videos (one progressive, one streaming), with the videos laid out adjacently." + , function():MediaElement + { + var parallelElement:ParallelElement = new ParallelElement(); + var layout:LayoutMetadata = new LayoutMetadata(); + layout.layoutMode = LayoutMode.HORIZONTAL; + layout.horizontalAlign = HorizontalAlign.CENTER; + layout.verticalAlign = VerticalAlign.MIDDLE; + layout.width = 640 + layout.height = 352; + parallelElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + + var mediaElement1:MediaElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); + layout = new LayoutMetadata(); + layout.percentWidth = 50; + layout.percentHeight = 50; + layout.scaleMode = ScaleMode.LETTERBOX; + mediaElement1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + parallelElement.addChild(mediaElement1); + + var mediaElement2:MediaElement = new VideoElement(new URLResource(REMOTE_STREAM)); + layout = new LayoutMetadata(); + layout.percentWidth = 50; + layout.percentHeight = 50; + layout.scaleMode = ScaleMode.LETTERBOX; + mediaElement2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + parallelElement.addChild(mediaElement2); + + return parallelElement; + } + , null + , "disable" + ) + ); + + layout.addItem + ( new Example + ( "Dynamic Layouts" + , "Demonstrates the use of the default OSMF layout renderer to dynamically change the spatial ordering of MediaElements within compositions." + , function():MediaElement + { + var parallelElement:ParallelElement = new ParallelElement(); + + var video1:VideoElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); + var video2:VideoElement = new VideoElement(new URLResource(REMOTE_STREAM)); + parallelElement.addChild(video1); + parallelElement.addChild(video2); + + var layoutVideo1:LayoutMetadata = new LayoutMetadata(); + layoutVideo1.percentWidth = 50; + layoutVideo1.percentHeight = 50; + video1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutVideo1); + + var layoutVideo2:LayoutMetadata = new LayoutMetadata(); + layoutVideo2.percentWidth = 50; + layoutVideo2.percentHeight = 50; + layoutVideo2.percentX = 50; + layoutVideo2.percentY = 25; + video2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutVideo2); + + var layoutParallelElement:LayoutMetadata = new LayoutMetadata(); + layoutParallelElement.width = 640; + layoutParallelElement.height = 358; + layoutParallelElement.horizontalAlign = HorizontalAlign.CENTER; + layoutParallelElement.verticalAlign = VerticalAlign.MIDDLE; + parallelElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutParallelElement); + + var delta:int = 1; + + timer.delay = 20; + timer.repeatCount = 0; + timer.addEventListener + ( TimerEvent.TIMER + , timerHandler = onTimer + ); + + function onTimer(event:Event):void + { + layoutVideo1.percentWidth += delta; + layoutVideo1.percentHeight += delta; + + layoutVideo2.percentY += delta / 2; + + if ( layoutVideo1.percentWidth < 25 + || layoutVideo1.percentWidth > 75 + ) + { + delta = -delta; + } + } + + timer.start(); + + return parallelElement; + } + , function():void + { + timer.stop(); + timer.reset(); + timer.removeEventListener + ( TimerEvent.TIMER + , timerHandler + ); + } + , "disable" + ) + ); + + layout.addItem + ( new Example + ( "Picture in Picture" + , "Demonstrates how to place two different videos in a composition, one large, and a small video in the corner." + , function():MediaElement + { + var elem:ParallelElement= new ParallelElement(); + var video1:VideoElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE)); + var video2:VideoElement = new VideoElement(new URLResource(REMOTE_PROGRESSIVE2)); + + var layout:LayoutMetadata = new LayoutMetadata(); + layout.percentWidth = 100; + layout.percentHeight = 100; + layout.index = 0; + layout.scaleMode = ScaleMode.LETTERBOX; + video1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + + layout = new LayoutMetadata(); + layout.percentWidth = 20; + layout.percentHeight = 20; + layout.index = 1; + layout.right = 15; + layout.top = 15; + layout.scaleMode = ScaleMode.LETTERBOX; + video2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout); + + elem.addChild(video1); + elem.addChild(video2); + + return elem; + } + , null + , "disable" + ) + ); + + // Error Handling Examples + // + + errorHandling.addItem + ( new Example + ( "Invalid Progressive Video" + , "Demonstrates load failures and error handling for a progressive video with an invalid URL." + , function():MediaElement + { + return new VideoElement(new URLResource(REMOTE_INVALID_PROGRESSIVE)); + } + ) + ); + + errorHandling.addItem + ( new Example + ( "Invalid Streaming Video (Bad Server)" + , "Demonstrates load failures and error handling for a streaming video with an invalid server." + , function():MediaElement + { + return new VideoElement(new StreamingURLResource(REMOTE_INVALID_FMS_SERVER)); + } + ) + ); + + errorHandling.addItem + ( new Example + ( "Invalid Streaming Video (Bad Stream)" + , "Demonstrates load failures and error handling for a streaming video with an valid server but an invalid stream." + , function():MediaElement + { + return new VideoElement(new StreamingURLResource(REMOTE_INVALID_STREAM)); + } + ) + ); + + errorHandling.addItem + ( new Example + ( "Invalid Image" + , "Demonstrates load failures and error handling for an image with an invalid URL." + , function():MediaElement + { + return new ImageElement(new URLResource(REMOTE_INVALID_IMAGE)); + } + ) + ); + + errorHandling.addItem + ( new Example + ( "Invalid Progressive Audio" + , "Demonstrates load failures and error handling for a progressive audio file with an invalid URL." + , function():MediaElement + { + return new AudioElement(new URLResource(REMOTE_INVALID_MP3)); + } + ) + ); + + errorHandling.addItem + ( new Example + ( "Invalid Streaming Audio" + , "Demonstrates load failures and error handling for a streaming audio file with an invalid URL." + , function():MediaElement + { + return new AudioElement(new StreamingURLResource(REMOTE_INVALID_STREAM)); + } + ) + ); + + errorHandling.addItem + ( new Example + ( "Invalid MediaElement/MediaResource Pair" + , "Demonstrates load failures and error handling for when the resource passed to a MediaElement is of the wrong type. In this case, an MP3 resource is passed to a VideoElement." + , function():MediaElement + { + return new VideoElement(new URLResource(REMOTE_MP3)); + } + ) + ); + + errorHandling.addItem + ( new Example + ( "Invalid Serial Composition" + , "Demonstrates load failures and error handling for a SerialElement whose second element has an invalid URL." + , function():MediaElement + { + var serialElement:SerialElement = new SerialElement(); + serialElement.addChild(new VideoElement(new URLResource(REMOTE_PROGRESSIVE))); + serialElement.addChild(new VideoElement(new URLResource(REMOTE_INVALID_STREAM))); + return serialElement; + } + ) + ); + + examples.addItem(media); + examples.addItem(composition); + examples.addItem(proxies); + examples.addItem(layout); + examples.addItem(errorHandling); + + return examples; + } + + private static const BANNER_1:String = "http://www.iab.net/media/image/468x60.gif"; + private static const BANNER_2:String = "http://www.iab.net/media/image/234x60.gif"; + private static const BANNER_3:String = "http://www.iab.net/media/image/120x60.gif"; + private static const REMOTE_PROGRESSIVE:String = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; + private static const REMOTE_PROGRESSIVE2:String = "http://mediapm.edgesuite.net/strobe/content/test/elephants_dream_768x428_24_short.flv"; + private static const REMOTE_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + private static const REMOTE_AUDIO_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mp3:mediapm/strobe/content/test/train_1500"; + private static const REMOTE_LIVE_STREAM:String = "rtmp://cp34973.live.edgefcs.net/live/Flash_Live_Benchmark@632"; + private static const REMOTE_MBR_STREAM_HOST:String = "rtmp://cp67126.edgefcs.net/ondemand"; + private static const REMOTE_MP3:String = "http://mediapm.edgesuite.net/osmf/content/test/train_1500.mp3"; + private static const REMOTE_IMAGE:String = "http://mediapm.edgesuite.net/strobe/content/test/train.jpg"; + private static const REMOTE_BANNER:String = "http://mediapm.edgesuite.net/osmf/image/banner.jpg"; + private static const REMOTE_SLIDESHOW_IMAGE1:String = "http://mediapm.edgesuite.net/osmf/swf/OSMFPlayer/images/vegetation.jpg"; + private static const REMOTE_SLIDESHOW_IMAGE2:String = "http://mediapm.edgesuite.net/strobe/content/test/train.jpg"; + private static const REMOTE_SLIDESHOW_IMAGE3:String = "http://mediapm.edgesuite.net/osmf/image/flex_48x45.gif"; + private static const REMOTE_SWF:String = "http://mediapm.edgesuite.net/osmf/content/test/ten.swf"; + private static const REMOTE_INVALID_PROGRESSIVE:String = "http://mediapm.edgesuite.net/strobe/content/test/fail.flv"; + private static const REMOTE_INVALID_FMS_SERVER:String = "rtmp://cp67126.fail.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + private static const REMOTE_INVALID_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/fail/SpaceAloneHD_sounas_640_500_short"; + private static const REMOTE_INVALID_IMAGE:String = "http://mediapm.edgesuite.net/osmf/image/fail.png"; + private static const REMOTE_INVALID_MP3:String = "http://mediapm.edgesuite.net/osmf/content/test/fail.mp3"; + private static const LOCAL_PROGRESSIVE:String = "video.flv"; + private static const CHROMELESS_SWF_AS3:String = "http://mediapm.edgesuite.net/osmf/swf/ChromelessPlayer.swf"; + private static const CHROMELESS_SWF_FLEX:String = "http://mediapm.edgesuite.net/osmf/swf/ChromelessFlexPlayer.swf"; + private static const BEACON_URL:String = "http://mediapm.edgesuite.net/osmf/image/adobe-lq.png"; + private static const REMOTE_MANIFEST:String = "http://mediapm.edgesuite.net/osmf/content/test/manifest-files/progressive.f4m"; + private static const REMOTE_MBR_MANIFEST:String = "http://mediapm.edgesuite.net/osmf/content/test/manifest-files/dynamic_Streaming.f4m"; + private static const OSMF_ANIMATION:String = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; + + private static const MBR_STREAM_ITEMS:Array = + [ new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_768x428_24.0fps_408kbps.mp4", 408, 768, 428) + , new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_768x428_24.0fps_608kbps.mp4", 608, 768, 428) + , new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1024x522_24.0fps_908kbps.mp4", 908, 1024, 522) + , new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1024x522_24.0fps_1308kbps.mp4", 1308, 1024, 522) + , new DynamicStreamingItem("mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1280x720_24.0fps_1708kbps.mp4", 1708, 1280, 720) + ]; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/Category.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/Category.as index 9903cd1..2464388 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/Category.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/Category.as @@ -1,25 +1,25 @@ -package org.osmf.examples -{ - import mx.collections.ArrayCollection; - import mx.collections.ICollectionView; - - public class Category extends ArrayCollection - { - public function Category(name:String) - { - _name = name; - } - - public function get name():String - { - return _name; - } - - public function get children():ArrayCollection - { - return this; - } - - private var _name:String; - } +package org.osmf.examples +{ + import mx.collections.ArrayCollection; + import mx.collections.ICollectionView; + + public class Category extends ArrayCollection + { + public function Category(name:String) + { + _name = name; + } + + public function get name():String + { + return _name; + } + + public function get children():ArrayCollection + { + return this; + } + + private var _name:String; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/Example.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/Example.as index 47daeb5..5758538 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/Example.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/Example.as @@ -1,92 +1,92 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples -{ - import org.osmf.media.MediaElement; - - /** - * Encapsulation of an example MediaElement. - **/ - public class Example - { - /** - * Constructor. - **/ - public function Example(name:String, description:String, mediaElementCreatorFunc:Function, disposeFunc:Function = null, scaleModeOverride:String = null) - { - _name = name; - _description = description; - _mediaElementCreatorFunc = mediaElementCreatorFunc; - this.disposeFunc = disposeFunc; - _scaleModeOverride = scaleModeOverride; - } - - /** - * A human-readable name for the example. - **/ - public function get name():String - { - return _name; - } - - /** - * A description explaining what the example demonstrates. - **/ - public function get description():String - { - return _description; - } - - /** - * The MediaElement that this example demonstrates. - **/ - public function get mediaElement():MediaElement - { - return _mediaElementCreatorFunc.apply(this) as MediaElement; - } - - /** - * Optional override of the scale mode. - **/ - public function get scaleModeOverride():String - { - return _scaleModeOverride; - } - - /** - * To be invoked when the example should clean-up. - */ - public function dispose():void - { - if (disposeFunc != null) - { - disposeFunc(); - } - } - - private var _name:String; - private var _description:String; - private var _mediaElementCreatorFunc:Function; - private var disposeFunc:Function; - private var _scaleModeOverride:String; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples +{ + import org.osmf.media.MediaElement; + + /** + * Encapsulation of an example MediaElement. + **/ + public class Example + { + /** + * Constructor. + **/ + public function Example(name:String, description:String, mediaElementCreatorFunc:Function, disposeFunc:Function = null, scaleModeOverride:String = null) + { + _name = name; + _description = description; + _mediaElementCreatorFunc = mediaElementCreatorFunc; + this.disposeFunc = disposeFunc; + _scaleModeOverride = scaleModeOverride; + } + + /** + * A human-readable name for the example. + **/ + public function get name():String + { + return _name; + } + + /** + * A description explaining what the example demonstrates. + **/ + public function get description():String + { + return _description; + } + + /** + * The MediaElement that this example demonstrates. + **/ + public function get mediaElement():MediaElement + { + return _mediaElementCreatorFunc.apply(this) as MediaElement; + } + + /** + * Optional override of the scale mode. + **/ + public function get scaleModeOverride():String + { + return _scaleModeOverride; + } + + /** + * To be invoked when the example should clean-up. + */ + public function dispose():void + { + if (disposeFunc != null) + { + disposeFunc(); + } + } + + private var _name:String; + private var _description:String; + private var _mediaElementCreatorFunc:Function; + private var disposeFunc:Function; + private var _scaleModeOverride:String; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/AdProxy.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/AdProxy.as index 2c6eed5..d8da2b6 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/AdProxy.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/AdProxy.as @@ -1,172 +1,172 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.ads -{ - import flash.display.Sprite; - import flash.events.TimerEvent; - import flash.text.TextField; - import flash.text.TextFormat; - import flash.text.TextFormatAlign; - import flash.utils.Timer; - - import org.osmf.elements.ProxyElement; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.TimeTrait; - - public class AdProxy extends ProxyElement - { - public function AdProxy(proxiedElement:MediaElement=null) - { - displayObject = new Sprite(); - - var format:TextFormat = new TextFormat("Verdana", 30, 0xffffff); - format.align = TextFormatAlign.CENTER; - format.font = "Verdana"; - - label = new TextField(); - label.defaultTextFormat = format; - - displayObject.addChild(label); - outerViewable = new AdProxyDisplayObjectTrait(displayObject); - - proxiedElement.addEventListener(MediaElementEvent.TRAIT_ADD, onProxiedTraitsChange); - proxiedElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onProxiedTraitsChange); - - super(proxiedElement); - - var traitsToBlock:Vector. = new Vector.(); - traitsToBlock[0] = MediaTraitType.SEEK; - traitsToBlock[1] = MediaTraitType.TIME; - - blockedTraits = traitsToBlock; - - var timer:Timer = new Timer(300); - timer.addEventListener(TimerEvent.TIMER, onTimerTick); - timer.start(); - } - - private function onProxiedTraitsChange(event:MediaElementEvent):void - { - if (event.type == MediaElementEvent.TRAIT_ADD) - { - if (event.traitType == MediaTraitType.DISPLAY_OBJECT) - { - innerViewable = DisplayObjectTrait(proxiedElement.getTrait(event.traitType)); - if (_innerViewable) - { - addTrait(MediaTraitType.DISPLAY_OBJECT, outerViewable); - } - } - } - else - { - if (event.traitType == MediaTraitType.DISPLAY_OBJECT) - { - innerViewable = null; - removeTrait(MediaTraitType.DISPLAY_OBJECT); - } - } - } - - private function set innerViewable(value:DisplayObjectTrait):void - { - if (_innerViewable != value) - { - if (_innerViewable) - { - _innerViewable.removeEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, onInnerDisplayObjectChange); - _innerViewable.removeEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onInnerMediaSizeChange); - } - - _innerViewable = value; - - if (_innerViewable) - { - _innerViewable.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, onInnerDisplayObjectChange); - _innerViewable.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onInnerMediaSizeChange); - } - - updateView(); - } - } - - private function onInnerDisplayObjectChange(event:DisplayObjectEvent):void - { - updateView(); - } - - private function onInnerMediaSizeChange(event:DisplayObjectEvent):void - { - outerViewable.setSize(event.newWidth, event.newHeight); - - label.width = event.newWidth; - } - - private function updateView():void - { - if ( _innerViewable == null - || _innerViewable.displayObject == null - || displayObject.contains(_innerViewable.displayObject) == false - ) - { - if (displayObject.numChildren == 2) - { - displayObject.removeChildAt(0); - } - label.visible = false; - } - - if ( _innerViewable != null - && _innerViewable.displayObject != null - && displayObject.contains(_innerViewable.displayObject) == false - ) - { - displayObject.addChildAt(_innerViewable.displayObject, 0); - label.visible = true; - } - - } - - private function onTimerTick(event:TimerEvent):void - { - var labelText:String = ""; - if (proxiedElement != null) - { - var timeTrait:TimeTrait = proxiedElement.getTrait(MediaTraitType.TIME) as TimeTrait - if (timeTrait && timeTrait.duration && (timeTrait.duration - timeTrait.currentTime) > 0.9) - { - labelText = "[ Advertisement - Remaining Time: "+ Math.round(timeTrait.duration - timeTrait.currentTime) + " seconds... ]"; - } - } - label.text = labelText; - } - - private var _innerViewable:DisplayObjectTrait; - private var outerViewable:AdProxyDisplayObjectTrait; - private var displayObject:Sprite; - private var label:TextField; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.ads +{ + import flash.display.Sprite; + import flash.events.TimerEvent; + import flash.text.TextField; + import flash.text.TextFormat; + import flash.text.TextFormatAlign; + import flash.utils.Timer; + + import org.osmf.elements.ProxyElement; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.TimeTrait; + + public class AdProxy extends ProxyElement + { + public function AdProxy(proxiedElement:MediaElement=null) + { + displayObject = new Sprite(); + + var format:TextFormat = new TextFormat("Verdana", 30, 0xffffff); + format.align = TextFormatAlign.CENTER; + format.font = "Verdana"; + + label = new TextField(); + label.defaultTextFormat = format; + + displayObject.addChild(label); + outerViewable = new AdProxyDisplayObjectTrait(displayObject); + + proxiedElement.addEventListener(MediaElementEvent.TRAIT_ADD, onProxiedTraitsChange); + proxiedElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onProxiedTraitsChange); + + super(proxiedElement); + + var traitsToBlock:Vector. = new Vector.(); + traitsToBlock[0] = MediaTraitType.SEEK; + traitsToBlock[1] = MediaTraitType.TIME; + + blockedTraits = traitsToBlock; + + var timer:Timer = new Timer(300); + timer.addEventListener(TimerEvent.TIMER, onTimerTick); + timer.start(); + } + + private function onProxiedTraitsChange(event:MediaElementEvent):void + { + if (event.type == MediaElementEvent.TRAIT_ADD) + { + if (event.traitType == MediaTraitType.DISPLAY_OBJECT) + { + innerViewable = DisplayObjectTrait(proxiedElement.getTrait(event.traitType)); + if (_innerViewable) + { + addTrait(MediaTraitType.DISPLAY_OBJECT, outerViewable); + } + } + } + else + { + if (event.traitType == MediaTraitType.DISPLAY_OBJECT) + { + innerViewable = null; + removeTrait(MediaTraitType.DISPLAY_OBJECT); + } + } + } + + private function set innerViewable(value:DisplayObjectTrait):void + { + if (_innerViewable != value) + { + if (_innerViewable) + { + _innerViewable.removeEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, onInnerDisplayObjectChange); + _innerViewable.removeEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onInnerMediaSizeChange); + } + + _innerViewable = value; + + if (_innerViewable) + { + _innerViewable.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, onInnerDisplayObjectChange); + _innerViewable.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onInnerMediaSizeChange); + } + + updateView(); + } + } + + private function onInnerDisplayObjectChange(event:DisplayObjectEvent):void + { + updateView(); + } + + private function onInnerMediaSizeChange(event:DisplayObjectEvent):void + { + outerViewable.setSize(event.newWidth, event.newHeight); + + label.width = event.newWidth; + } + + private function updateView():void + { + if ( _innerViewable == null + || _innerViewable.displayObject == null + || displayObject.contains(_innerViewable.displayObject) == false + ) + { + if (displayObject.numChildren == 2) + { + displayObject.removeChildAt(0); + } + label.visible = false; + } + + if ( _innerViewable != null + && _innerViewable.displayObject != null + && displayObject.contains(_innerViewable.displayObject) == false + ) + { + displayObject.addChildAt(_innerViewable.displayObject, 0); + label.visible = true; + } + + } + + private function onTimerTick(event:TimerEvent):void + { + var labelText:String = ""; + if (proxiedElement != null) + { + var timeTrait:TimeTrait = proxiedElement.getTrait(MediaTraitType.TIME) as TimeTrait + if (timeTrait && timeTrait.duration && (timeTrait.duration - timeTrait.currentTime) > 0.9) + { + labelText = "[ Advertisement - Remaining Time: "+ Math.round(timeTrait.duration - timeTrait.currentTime) + " seconds... ]"; + } + } + label.text = labelText; + } + + private var _innerViewable:DisplayObjectTrait; + private var outerViewable:AdProxyDisplayObjectTrait; + private var displayObject:Sprite; + private var label:TextField; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/AdProxyDisplayObjectTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/AdProxyDisplayObjectTrait.as index 38205c8..6555e9a 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/AdProxyDisplayObjectTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/AdProxyDisplayObjectTrait.as @@ -1,40 +1,40 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.ads -{ - import flash.display.DisplayObject; - - import org.osmf.traits.DisplayObjectTrait; - - public class AdProxyDisplayObjectTrait extends DisplayObjectTrait - { - public function AdProxyDisplayObjectTrait(displayObject:DisplayObject, mediaWidth:Number=0, mediaHeight:Number=0) - { - super(displayObject, mediaWidth, mediaHeight); - } - - public function setSize(width:Number, height:Number):void - { - setMediaSize(width, height); - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.ads +{ + import flash.display.DisplayObject; + + import org.osmf.traits.DisplayObjectTrait; + + public class AdProxyDisplayObjectTrait extends DisplayObjectTrait + { + public function AdProxyDisplayObjectTrait(displayObject:DisplayObject, mediaWidth:Number=0, mediaHeight:Number=0) + { + super(displayObject, mediaWidth, mediaHeight); + } + + public function setSize(width:Number, height:Number):void + { + setMediaSize(width, height); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/PreMidPostRollElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/PreMidPostRollElement.as index 1651e95..54c2e86 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/PreMidPostRollElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/ads/PreMidPostRollElement.as @@ -1,59 +1,59 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.ads -{ - import org.osmf.elements.SerialElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - - public class PreMidPostRollElement extends SerialElement - { - public function PreMidPostRollElement - ( preRoll:MediaElement - , contentPart1:MediaElement - , midRoll:MediaElement - , contentPart2:MediaElement - , postRoll:MediaElement - ) - { - super(); - - addChild(new AdProxy(preRoll)); - addChild(contentPart1); - addChild(new AdProxy(midRoll)); - addChild(contentPart2); - addChild(new AdProxy(postRoll)); - - var layoutMetadata:LayoutMetadata = new LayoutMetadata(); - layoutMetadata.width = 640; - layoutMetadata.height = 360; - layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - layoutMetadata.scaleMode = ScaleMode.LETTERBOX; - - metadata.addValue(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.ads +{ + import org.osmf.elements.SerialElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaElement; + + public class PreMidPostRollElement extends SerialElement + { + public function PreMidPostRollElement + ( preRoll:MediaElement + , contentPart1:MediaElement + , midRoll:MediaElement + , contentPart2:MediaElement + , postRoll:MediaElement + ) + { + super(); + + addChild(new AdProxy(preRoll)); + addChild(contentPart1); + addChild(new AdProxy(midRoll)); + addChild(contentPart2); + addChild(new AdProxy(postRoll)); + + var layoutMetadata:LayoutMetadata = new LayoutMetadata(); + layoutMetadata.width = 640; + layoutMetadata.height = 360; + layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + layoutMetadata.scaleMode = ScaleMode.LETTERBOX; + + metadata.addValue(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/BufferingProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/BufferingProxyElement.as index 43146d4..dd0e2f3 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/BufferingProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/BufferingProxyElement.as @@ -1,55 +1,55 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.buffering -{ - import org.osmf.elements.ProxyElement; - import org.osmf.events.MediaElementEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.TraitEventDispatcher; - - /** - * Proxy class which sets the IBufferable.bufferTime property to - * an initial value when the IBufferable trait is available. - **/ - public class BufferingProxyElement extends ProxyElement - { - public function BufferingProxyElement(bufferTime:Number, wrappedElement:MediaElement) - { - super(wrappedElement); - - this.bufferTime = bufferTime; - wrappedElement.addEventListener(MediaElementEvent.TRAIT_ADD, processTraitAdd); - } - - private function processTraitAdd(traitType:MediaTraitType):void - { - if (traitType == MediaTraitType.BUFFERABLE) - { - var bufferable:IBufferable = getTrait(MediaTraitType.BUFFERABLE) as IBufferable; - bufferable.bufferTime = bufferTime; - } - } - - private var bufferTime:Number; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.buffering +{ + import org.osmf.elements.ProxyElement; + import org.osmf.events.MediaElementEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.TraitEventDispatcher; + + /** + * Proxy class which sets the IBufferable.bufferTime property to + * an initial value when the IBufferable trait is available. + **/ + public class BufferingProxyElement extends ProxyElement + { + public function BufferingProxyElement(bufferTime:Number, wrappedElement:MediaElement) + { + super(wrappedElement); + + this.bufferTime = bufferTime; + wrappedElement.addEventListener(MediaElementEvent.TRAIT_ADD, processTraitAdd); + } + + private function processTraitAdd(traitType:MediaTraitType):void + { + if (traitType == MediaTraitType.BUFFERABLE) + { + var bufferable:IBufferable = getTrait(MediaTraitType.BUFFERABLE) as IBufferable; + bufferable.bufferTime = bufferTime; + } + } + + private var bufferTime:Number; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/DualThresholdBufferingProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/DualThresholdBufferingProxyElement.as index a895ca6..f9e1907 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/DualThresholdBufferingProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/DualThresholdBufferingProxyElement.as @@ -1,106 +1,106 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.buffering -{ - import org.osmf.elements.ProxyElement; - import org.osmf.events.BufferEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.events.PlayEvent; - import org.osmf.events.SeekEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.BufferTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.TraitEventDispatcher; - - /** - * Proxy class which sets the IBufferable.bufferTime property to - * an initial value when the IBufferable trait is available, and - * an expanded value when the proxied MediaElement first exits - * the buffer state. - **/ - public class DualThresholdBufferingProxyElement extends ProxyElement - { - public function DualThresholdBufferingProxyElement(initialBufferTime:Number, expandedBufferTime:Number, wrappedElement:MediaElement) - { - super(wrappedElement); - - this.initialBufferTime = initialBufferTime; - this.expandedBufferTime = expandedBufferTime; - - var dispatcher:TraitEventDispatcher = new TraitEventDispatcher(); - dispatcher.media = wrappedElement; - - wrappedElement.addEventListener(MediaElementEvent.TRAIT_ADD, processTraitAdd); - dispatcher.addEventListener(BufferEvent.BUFFERING_CHANGE, processBufferingChange); - dispatcher.addEventListener(SeekEvent.SEEKING_CHANGE, processSeekingChange); - dispatcher.addEventListener(PlayEvent.PLAY_STATE_CHANGE, processPlayStateChange); - - } - - private function processTraitAdd(traitType:String):void - { - if (traitType == MediaTraitType.BUFFER) - { - // As soon as we can buffer, set the initial buffer time. - var bufferTrait:BufferTrait = getTrait(MediaTraitType.BUFFER) as BufferTrait; - bufferTrait.bufferTime = initialBufferTime; - } - } - - private function processBufferingChange(event:BufferEvent):void - { - // As soon as we stop buffering, make sure our buffer time is - // set to the maximum. - if (event.buffering == false) - { - var bufferTrait:BufferTrait = getTrait(MediaTraitType.BUFFER) as BufferTrait; - bufferTrait.bufferTime = expandedBufferTime; - } - } - - private function processSeekingChange(event:SeekEvent):void - { - // Whenever we seek, reset our buffer time to the minimum so that - // playback starts quickly after the seek. - if (event.seeking == true) - { - var bufferTrait:BufferTrait = getTrait(MediaTraitType.BUFFER) as BufferTrait; - bufferTrait.bufferTime = initialBufferTime; - } - } - - private function processPlayStateChange(event:PlayEvent):void - { - // Whenever we pause, reset our buffer time to the minimum so that - // playback starts quickly after the unpause. - if (event.playState == PlayState.PAUSED) - { - var bufferTrait:BufferTrait = getTrait(MediaTraitType.BUFFER) as BufferTrait; - bufferTrait.bufferTime = initialBufferTime; - } - } - - private var initialBufferTime:Number; - private var expandedBufferTime:Number; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.buffering +{ + import org.osmf.elements.ProxyElement; + import org.osmf.events.BufferEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.events.PlayEvent; + import org.osmf.events.SeekEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.BufferTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.TraitEventDispatcher; + + /** + * Proxy class which sets the IBufferable.bufferTime property to + * an initial value when the IBufferable trait is available, and + * an expanded value when the proxied MediaElement first exits + * the buffer state. + **/ + public class DualThresholdBufferingProxyElement extends ProxyElement + { + public function DualThresholdBufferingProxyElement(initialBufferTime:Number, expandedBufferTime:Number, wrappedElement:MediaElement) + { + super(wrappedElement); + + this.initialBufferTime = initialBufferTime; + this.expandedBufferTime = expandedBufferTime; + + var dispatcher:TraitEventDispatcher = new TraitEventDispatcher(); + dispatcher.media = wrappedElement; + + wrappedElement.addEventListener(MediaElementEvent.TRAIT_ADD, processTraitAdd); + dispatcher.addEventListener(BufferEvent.BUFFERING_CHANGE, processBufferingChange); + dispatcher.addEventListener(SeekEvent.SEEKING_CHANGE, processSeekingChange); + dispatcher.addEventListener(PlayEvent.PLAY_STATE_CHANGE, processPlayStateChange); + + } + + private function processTraitAdd(traitType:String):void + { + if (traitType == MediaTraitType.BUFFER) + { + // As soon as we can buffer, set the initial buffer time. + var bufferTrait:BufferTrait = getTrait(MediaTraitType.BUFFER) as BufferTrait; + bufferTrait.bufferTime = initialBufferTime; + } + } + + private function processBufferingChange(event:BufferEvent):void + { + // As soon as we stop buffering, make sure our buffer time is + // set to the maximum. + if (event.buffering == false) + { + var bufferTrait:BufferTrait = getTrait(MediaTraitType.BUFFER) as BufferTrait; + bufferTrait.bufferTime = expandedBufferTime; + } + } + + private function processSeekingChange(event:SeekEvent):void + { + // Whenever we seek, reset our buffer time to the minimum so that + // playback starts quickly after the seek. + if (event.seeking == true) + { + var bufferTrait:BufferTrait = getTrait(MediaTraitType.BUFFER) as BufferTrait; + bufferTrait.bufferTime = initialBufferTime; + } + } + + private function processPlayStateChange(event:PlayEvent):void + { + // Whenever we pause, reset our buffer time to the minimum so that + // playback starts quickly after the unpause. + if (event.playState == PlayState.PAUSED) + { + var bufferTrait:BufferTrait = getTrait(MediaTraitType.BUFFER) as BufferTrait; + bufferTrait.bufferTime = initialBufferTime; + } + } + + private var initialBufferTime:Number; + private var expandedBufferTime:Number; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/SynchronizedParallelElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/SynchronizedParallelElement.as index a190899..a2a4ca2 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/SynchronizedParallelElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/buffering/SynchronizedParallelElement.as @@ -1,124 +1,124 @@ -package org.osmf.examples.buffering -{ - import flash.events.TimerEvent; - import flash.utils.Timer; - - import org.osmf.elements.ParallelElement; - import org.osmf.events.BufferEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.traits.BufferTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - - /** - * ParallelElement which attempts to synchronize its children by pausing - * any time one child is buffering. - * - * Note that there's a bug (FM-1044) where the entire ParallelElement will - * pause when the shortest element reaches its duration. - **/ - public class SynchronizedParallelElement extends ParallelElement - { - public function SynchronizedParallelElement() - { - addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); - - // Bufferable's bufferLength must be polled for. Setup a - // timer to do so: - bufferLengthPoller = new Timer(500, 0); - bufferLengthPoller.addEventListener(TimerEvent.TIMER, onBufferLengthPoll); - - super(); - } - - // Internals - // - - private var bufferable:BufferTrait; - private var playable:PlayTrait; - private var paused:Boolean; - private var bufferLengthPoller:Timer; - - private function onTraitAdd(event:MediaElementEvent):void - { - // Watch for the element to become bufferable and playable: - switch (event.traitType) - { - case MediaTraitType.BUFFER: - bufferable = BufferTrait(getTrait(event.traitType)); - bufferable.addEventListener(BufferEvent.BUFFER_TIME_CHANGE, updatePlayState); - bufferLengthPoller.start(); - updatePlayState(); - break; - - case MediaTraitType.PLAY: - playable = PlayTrait(getTrait(event.traitType)); - updatePlayState(); - break; - } - } - - private function onTraitRemove(event:MediaElementEvent):void - { - switch (event.traitType) - { - case MediaTraitType.BUFFER: - bufferLengthPoller.stop(); - bufferable.removeEventListener(BufferEvent.BUFFER_TIME_CHANGE, updatePlayState); - bufferable = null; - updatePlayState(); - break; - - case MediaTraitType.PLAY: - playable = null; - updatePlayState(); - break; - } - } - - private function updatePlayState(..._):void - { - if (playable && playable.canPause && bufferable) - { - if ( paused == true - && playable.playState == PlayState.PAUSED - && bufferable.bufferLength >= bufferable.bufferTime - ) - { - // We have paused the content earlier on. Buffering - // has seized though, so we can resume playback: - paused = false; - playable.play(); - } - else if - ( paused == false - && bufferable.bufferLength < bufferable.bufferTime - ) - { - // At least part of the content is in a buffering - // state. Pause the parallel element as a whole, - // if it isn't already: - paused = true; - if (playable.playState != PlayState.PAUSED) - { - playable.pause(); - } - } - } - } - - private function onBufferLengthPoll(event:TimerEvent):void - { - if (playable && playable.canPause && bufferable) - { - // Check if the element is in a buffering state, - // and update the playstate accordingly: - updatePlayState(); - } - } - } +package org.osmf.examples.buffering +{ + import flash.events.TimerEvent; + import flash.utils.Timer; + + import org.osmf.elements.ParallelElement; + import org.osmf.events.BufferEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.traits.BufferTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + + /** + * ParallelElement which attempts to synchronize its children by pausing + * any time one child is buffering. + * + * Note that there's a bug (FM-1044) where the entire ParallelElement will + * pause when the shortest element reaches its duration. + **/ + public class SynchronizedParallelElement extends ParallelElement + { + public function SynchronizedParallelElement() + { + addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); + + // Bufferable's bufferLength must be polled for. Setup a + // timer to do so: + bufferLengthPoller = new Timer(500, 0); + bufferLengthPoller.addEventListener(TimerEvent.TIMER, onBufferLengthPoll); + + super(); + } + + // Internals + // + + private var bufferable:BufferTrait; + private var playable:PlayTrait; + private var paused:Boolean; + private var bufferLengthPoller:Timer; + + private function onTraitAdd(event:MediaElementEvent):void + { + // Watch for the element to become bufferable and playable: + switch (event.traitType) + { + case MediaTraitType.BUFFER: + bufferable = BufferTrait(getTrait(event.traitType)); + bufferable.addEventListener(BufferEvent.BUFFER_TIME_CHANGE, updatePlayState); + bufferLengthPoller.start(); + updatePlayState(); + break; + + case MediaTraitType.PLAY: + playable = PlayTrait(getTrait(event.traitType)); + updatePlayState(); + break; + } + } + + private function onTraitRemove(event:MediaElementEvent):void + { + switch (event.traitType) + { + case MediaTraitType.BUFFER: + bufferLengthPoller.stop(); + bufferable.removeEventListener(BufferEvent.BUFFER_TIME_CHANGE, updatePlayState); + bufferable = null; + updatePlayState(); + break; + + case MediaTraitType.PLAY: + playable = null; + updatePlayState(); + break; + } + } + + private function updatePlayState(..._):void + { + if (playable && playable.canPause && bufferable) + { + if ( paused == true + && playable.playState == PlayState.PAUSED + && bufferable.bufferLength >= bufferable.bufferTime + ) + { + // We have paused the content earlier on. Buffering + // has seized though, so we can resume playback: + paused = false; + playable.play(); + } + else if + ( paused == false + && bufferable.bufferLength < bufferable.bufferTime + ) + { + // At least part of the content is in a buffering + // state. Pause the parallel element as a whole, + // if it isn't already: + paused = true; + if (playable.playState != PlayState.PAUSED) + { + playable.pause(); + } + } + } + } + + private function onBufferLengthPoll(event:TimerEvent):void + { + if (playable && playable.canPause && bufferable) + { + // Check if the element is in a buffering state, + // and update the playstate accordingly: + updatePlayState(); + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/ChromelessPlayerElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/ChromelessPlayerElement.as index b714781..f538cbe 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/ChromelessPlayerElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/ChromelessPlayerElement.as @@ -1,117 +1,117 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.chromeless -{ - import flash.display.DisplayObject; - import flash.display.Loader; - import flash.events.Event; - - import org.osmf.elements.SWFElement; - import org.osmf.elements.SWFLoader; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.media.URLResource; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.MediaTraitType; - - /** - * SWFElement which can control the SWF it wraps via a custom SWF API - * that maps to the traits API. - **/ - public class ChromelessPlayerElement extends SWFElement - { - public function ChromelessPlayerElement(resource:URLResource=null, loader:SWFLoader=null) - { - super(resource, loader) - } - - override protected function processReadyState():void - { - super.processReadyState(); - - // Flex SWFs load differently from pure AS3 SWFs. For the former, - // we need to wait until the applicationComplete event is - // dispatched before we can access the SWF's API. - if ( swfRoot.hasOwnProperty("application") - && Object(swfRoot).application == null - ) - { - swfRoot.addEventListener("applicationComplete", finishProcessReadyState, false, 0, true); - } - else - { - finishProcessReadyState(); - } - } - - private function finishProcessReadyState(event:Event=null):void - { - // Flex SWFs expose their API through the root "application" - // property, whereas pure AS3 SWFs expose their API directly. - var theSwfRoot:DisplayObject = swfRoot.hasOwnProperty("application") ? Object(swfRoot).application : swfRoot; - - // Make sure the SWF has the expected API object. - var isValidSWF:Boolean = theSwfRoot.hasOwnProperty("videoPlayer"); - if (isValidSWF) - { - addTrait(MediaTraitType.PLAY, new SWFPlayTrait(theSwfRoot)); - addTrait(MediaTraitType.AUDIO, new SWFAudioTrait(theSwfRoot)); - addTrait(MediaTraitType.TIME, new SWFTimeTrait(theSwfRoot)); - - if ( swfRoot.hasOwnProperty("application") - && Object(swfRoot).application != null - ) - { - // Re-dispatch our dimensions: - var displayObjectTrait:DisplayObjectTrait= getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; - displayObjectTrait.dispatchEvent - ( new DisplayObjectEvent - ( DisplayObjectEvent.MEDIA_SIZE_CHANGE - , false - , false - , null - , null - , 0 - , 0 - , displayObjectTrait.mediaWidth - , displayObjectTrait.mediaHeight - ) - ); - } - } - } - - private function get swfRoot():DisplayObject - { - var displayObjectTrait:DisplayObjectTrait = getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; - return displayObjectTrait != null ? Loader(displayObjectTrait.displayObject).content : null; - } - - override protected function processUnloadingState():void - { - super.processUnloadingState(); - - removeTrait(MediaTraitType.PLAY); - removeTrait(MediaTraitType.AUDIO); - removeTrait(MediaTraitType.TIME); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.chromeless +{ + import flash.display.DisplayObject; + import flash.display.Loader; + import flash.events.Event; + + import org.osmf.elements.SWFElement; + import org.osmf.elements.SWFLoader; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.media.URLResource; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.MediaTraitType; + + /** + * SWFElement which can control the SWF it wraps via a custom SWF API + * that maps to the traits API. + **/ + public class ChromelessPlayerElement extends SWFElement + { + public function ChromelessPlayerElement(resource:URLResource=null, loader:SWFLoader=null) + { + super(resource, loader) + } + + override protected function processReadyState():void + { + super.processReadyState(); + + // Flex SWFs load differently from pure AS3 SWFs. For the former, + // we need to wait until the applicationComplete event is + // dispatched before we can access the SWF's API. + if ( swfRoot.hasOwnProperty("application") + && Object(swfRoot).application == null + ) + { + swfRoot.addEventListener("applicationComplete", finishProcessReadyState, false, 0, true); + } + else + { + finishProcessReadyState(); + } + } + + private function finishProcessReadyState(event:Event=null):void + { + // Flex SWFs expose their API through the root "application" + // property, whereas pure AS3 SWFs expose their API directly. + var theSwfRoot:DisplayObject = swfRoot.hasOwnProperty("application") ? Object(swfRoot).application : swfRoot; + + // Make sure the SWF has the expected API object. + var isValidSWF:Boolean = theSwfRoot.hasOwnProperty("videoPlayer"); + if (isValidSWF) + { + addTrait(MediaTraitType.PLAY, new SWFPlayTrait(theSwfRoot)); + addTrait(MediaTraitType.AUDIO, new SWFAudioTrait(theSwfRoot)); + addTrait(MediaTraitType.TIME, new SWFTimeTrait(theSwfRoot)); + + if ( swfRoot.hasOwnProperty("application") + && Object(swfRoot).application != null + ) + { + // Re-dispatch our dimensions: + var displayObjectTrait:DisplayObjectTrait= getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; + displayObjectTrait.dispatchEvent + ( new DisplayObjectEvent + ( DisplayObjectEvent.MEDIA_SIZE_CHANGE + , false + , false + , null + , null + , 0 + , 0 + , displayObjectTrait.mediaWidth + , displayObjectTrait.mediaHeight + ) + ); + } + } + } + + private function get swfRoot():DisplayObject + { + var displayObjectTrait:DisplayObjectTrait = getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; + return displayObjectTrait != null ? Loader(displayObjectTrait.displayObject).content : null; + } + + override protected function processUnloadingState():void + { + super.processUnloadingState(); + + removeTrait(MediaTraitType.PLAY); + removeTrait(MediaTraitType.AUDIO); + removeTrait(MediaTraitType.TIME); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFAudioTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFAudioTrait.as index a9ad8d3..2346a06 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFAudioTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFAudioTrait.as @@ -1,80 +1,80 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.chromeless -{ - import flash.display.DisplayObject; - import flash.events.Event; - - import org.osmf.traits.AudioTrait; - - internal class SWFAudioTrait extends AudioTrait - { - public function SWFAudioTrait(swfRoot:DisplayObject) - { - this.swfRoot = swfRoot; - - // Keep in sync with the state of the SWF. - Object(swfRoot).videoPlayer.addEventListener("isMutedChange", onMutedChange); - Object(swfRoot).videoPlayer.addEventListener("volumeChange", onVolumeChange); - onMutedChange(null); - onVolumeChange(null); - } - - override protected function volumeChangeStart(newVolume:Number):void - { - Object(swfRoot).videoPlayer.setVolume(newVolume); - } - - override protected function mutedChangeStart(newMuted:Boolean):void - { - if (Object(swfRoot).videoPlayer.isMuted != newMuted) - { - Object(swfRoot).videoPlayer.toggleMute(); - } - } - - override protected function panChangeStart(newPan:Number):void - { - // No op. - } - - private function onMutedChange(event:Event):void - { - // Stay in sync with the state of the SWF. - if (Object(swfRoot).videoPlayer.isMuted != muted) - { - muted = !muted; - } - } - - private function onVolumeChange(event:Event):void - { - // Stay in sync with the state of the SWF. - if (Object(swfRoot).videoPlayer.getVolume() != volume) - { - volume = Object(swfRoot).videoPlayer.getVolume(); - } - } - - private var swfRoot:DisplayObject; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.chromeless +{ + import flash.display.DisplayObject; + import flash.events.Event; + + import org.osmf.traits.AudioTrait; + + internal class SWFAudioTrait extends AudioTrait + { + public function SWFAudioTrait(swfRoot:DisplayObject) + { + this.swfRoot = swfRoot; + + // Keep in sync with the state of the SWF. + Object(swfRoot).videoPlayer.addEventListener("isMutedChange", onMutedChange); + Object(swfRoot).videoPlayer.addEventListener("volumeChange", onVolumeChange); + onMutedChange(null); + onVolumeChange(null); + } + + override protected function volumeChangeStart(newVolume:Number):void + { + Object(swfRoot).videoPlayer.setVolume(newVolume); + } + + override protected function mutedChangeStart(newMuted:Boolean):void + { + if (Object(swfRoot).videoPlayer.isMuted != newMuted) + { + Object(swfRoot).videoPlayer.toggleMute(); + } + } + + override protected function panChangeStart(newPan:Number):void + { + // No op. + } + + private function onMutedChange(event:Event):void + { + // Stay in sync with the state of the SWF. + if (Object(swfRoot).videoPlayer.isMuted != muted) + { + muted = !muted; + } + } + + private function onVolumeChange(event:Event):void + { + // Stay in sync with the state of the SWF. + if (Object(swfRoot).videoPlayer.getVolume() != volume) + { + volume = Object(swfRoot).videoPlayer.getVolume(); + } + } + + private var swfRoot:DisplayObject; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFPlayTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFPlayTrait.as index ffda228..bb1de04 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFPlayTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFPlayTrait.as @@ -1,70 +1,70 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.chromeless -{ - import flash.display.DisplayObject; - import flash.events.Event; - - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - - internal class SWFPlayTrait extends PlayTrait - { - public function SWFPlayTrait(swfRoot:DisplayObject) - { - super(); - - this.swfRoot = swfRoot; - - // Keep in sync with the state of the SWF. - Object(swfRoot).videoPlayer.addEventListener("isPlayingChange", onPlayingChange); - onPlayingChange(null); - } - - override protected function playStateChangeStart(playState:String):void - { - if (playState == PlayState.PLAYING && Object(swfRoot).videoPlayer.isPlaying == false) - { - Object(swfRoot).videoPlayer.playVideo(); - } - else if (playState == PlayState.PAUSED && Object(swfRoot).videoPlayer.isPlaying) - { - Object(swfRoot).videoPlayer.pauseVideo(); - } - } - - private function onPlayingChange(event:Event):void - { - // Stay in sync with the state of the SWF. - if (Object(swfRoot).videoPlayer.isPlaying) - { - play(); - } - else - { - pause(); - } - } - - private var swfRoot:DisplayObject; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.chromeless +{ + import flash.display.DisplayObject; + import flash.events.Event; + + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + + internal class SWFPlayTrait extends PlayTrait + { + public function SWFPlayTrait(swfRoot:DisplayObject) + { + super(); + + this.swfRoot = swfRoot; + + // Keep in sync with the state of the SWF. + Object(swfRoot).videoPlayer.addEventListener("isPlayingChange", onPlayingChange); + onPlayingChange(null); + } + + override protected function playStateChangeStart(playState:String):void + { + if (playState == PlayState.PLAYING && Object(swfRoot).videoPlayer.isPlaying == false) + { + Object(swfRoot).videoPlayer.playVideo(); + } + else if (playState == PlayState.PAUSED && Object(swfRoot).videoPlayer.isPlaying) + { + Object(swfRoot).videoPlayer.pauseVideo(); + } + } + + private function onPlayingChange(event:Event):void + { + // Stay in sync with the state of the SWF. + if (Object(swfRoot).videoPlayer.isPlaying) + { + play(); + } + else + { + pause(); + } + } + + private var swfRoot:DisplayObject; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFTimeTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFTimeTrait.as index 9275d25..360c4d4 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFTimeTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/chromeless/SWFTimeTrait.as @@ -1,66 +1,66 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.chromeless -{ - import flash.display.DisplayObject; - import flash.events.Event; - - import org.osmf.traits.TimeTrait; - - internal class SWFTimeTrait extends TimeTrait - { - public function SWFTimeTrait(swfRoot:DisplayObject) - { - super(); - - this.swfRoot = swfRoot; - - // Keep in sync with the state of the SWF. - Object(swfRoot).videoPlayer.addEventListener("playheadChange", onPlayheadChange); - Object(swfRoot).videoPlayer.addEventListener("durationChange", onDurationChange); - - onPlayheadChange(null); - onDurationChange(null); - } - - private function onPlayheadChange(event:Event):void - { - // Stay in sync with the state of the SWF. - var newCurrentTime:Number = Object(swfRoot).videoPlayer.playhead; - if (newCurrentTime != currentTime) - { - setCurrentTime(newCurrentTime); - } - } - - private function onDurationChange(event:Event):void - { - var newDuration:Number = Object(swfRoot).videoPlayer.duration; - if (newDuration != duration) - { - setDuration(newDuration); - } - } - - private var swfRoot:DisplayObject; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.chromeless +{ + import flash.display.DisplayObject; + import flash.events.Event; + + import org.osmf.traits.TimeTrait; + + internal class SWFTimeTrait extends TimeTrait + { + public function SWFTimeTrait(swfRoot:DisplayObject) + { + super(); + + this.swfRoot = swfRoot; + + // Keep in sync with the state of the SWF. + Object(swfRoot).videoPlayer.addEventListener("playheadChange", onPlayheadChange); + Object(swfRoot).videoPlayer.addEventListener("durationChange", onDurationChange); + + onPlayheadChange(null); + onDurationChange(null); + } + + private function onPlayheadChange(event:Event):void + { + // Stay in sync with the state of the SWF. + var newCurrentTime:Number = Object(swfRoot).videoPlayer.playhead; + if (newCurrentTime != currentTime) + { + setCurrentTime(newCurrentTime); + } + } + + private function onDurationChange(event:Event):void + { + var newDuration:Number = Object(swfRoot).videoPlayer.duration; + if (newDuration != duration) + { + setDuration(newDuration); + } + } + + private var swfRoot:DisplayObject; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/AsynchLoadingProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/AsynchLoadingProxyElement.as index c2215ca..167dea2 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/AsynchLoadingProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/AsynchLoadingProxyElement.as @@ -1,143 +1,143 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.loaderproxy -{ - import __AS3__.vec.Vector; - - import org.osmf.elements.ProxyElement; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - - /** - * A ProxyElement which allows for custom load logic to be layered on top - * of the MediaElement that's being proxied. For instance, if you need to - * make some asynchronous HTTP calls *after* the video is loaded but *before* - * the client can begin interacting with the video, this class provides - * a pattern for doing so. - **/ - public class AsynchLoadingProxyElement extends ProxyElement - { - /** - * Constructor. - * - * @param proxiedElement The MediaElement to proxy. - **/ - public function AsynchLoadingProxyElement(proxiedElement:MediaElement) - { - super(proxiedElement); - } - - /** - * Override this method to define a custom asynchronous load trait. - **/ - protected function createAsynchLoadingProxyLoadTrait():LoadTrait - { - return new AsynchLoadingProxyLoadTrait(super.getTrait(MediaTraitType.LOAD) as LoadTrait); - } - - // Internals - // - - /** - * @private - **/ - override protected function setupTraits():void - { - super.setupTraits(); - - // First, block all traits but the LOAD trait from being exposed - // to clients. The reason for this is that the proxied element - // will complete its load before we're ready to expose its state - // to the outside world, so we block all the other traits so that - // we can expose them when we're truly ready. - var traitsToBlock:Vector. = new Vector.(); - traitsToBlock.push(MediaTraitType.AUDIO); - traitsToBlock.push(MediaTraitType.BUFFER); - traitsToBlock.push(MediaTraitType.DISPLAY_OBJECT); - traitsToBlock.push(MediaTraitType.DRM); - traitsToBlock.push(MediaTraitType.DVR); - traitsToBlock.push(MediaTraitType.DYNAMIC_STREAM); - traitsToBlock.push(MediaTraitType.PLAY); - traitsToBlock.push(MediaTraitType.SEEK); - traitsToBlock.push(MediaTraitType.TIME); - super.blockedTraits = traitsToBlock; - } - - /** - * @private - **/ - override public function set proxiedElement(value:MediaElement):void - { - super.proxiedElement = value; - - if (value != null) - { - if (value.hasTrait(MediaTraitType.LOAD)) - { - processNewLoadTrait(); - } - else - { - // Wait for the LoadTrait to be added. - value.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - } - } - - private function onTraitAdd(event:MediaElementEvent):void - { - if (event.traitType == MediaTraitType.LOAD) - { - proxiedElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - - processNewLoadTrait(); - } - } - - private function processNewLoadTrait():void - { - // Override the LoadTrait with our own custom trait, which provides - // hooks for executing asynchronous logic in conjunction with the - // load of the proxied element. - var asynchLoadTrait:LoadTrait = createAsynchLoadingProxyLoadTrait(); - addTrait(MediaTraitType.LOAD, asynchLoadTrait); - - // Make sure we're informed when the custom load trait signals that - // it's ready, so that we can unblock the other traits. - asynchLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - } - - private function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - // We're now ready to expose the proxied element to the outside - // world, so we unblock all traits. - super.blockedTraits = new Vector.(); - } - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.loaderproxy +{ + import __AS3__.vec.Vector; + + import org.osmf.elements.ProxyElement; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + + /** + * A ProxyElement which allows for custom load logic to be layered on top + * of the MediaElement that's being proxied. For instance, if you need to + * make some asynchronous HTTP calls *after* the video is loaded but *before* + * the client can begin interacting with the video, this class provides + * a pattern for doing so. + **/ + public class AsynchLoadingProxyElement extends ProxyElement + { + /** + * Constructor. + * + * @param proxiedElement The MediaElement to proxy. + **/ + public function AsynchLoadingProxyElement(proxiedElement:MediaElement) + { + super(proxiedElement); + } + + /** + * Override this method to define a custom asynchronous load trait. + **/ + protected function createAsynchLoadingProxyLoadTrait():LoadTrait + { + return new AsynchLoadingProxyLoadTrait(super.getTrait(MediaTraitType.LOAD) as LoadTrait); + } + + // Internals + // + + /** + * @private + **/ + override protected function setupTraits():void + { + super.setupTraits(); + + // First, block all traits but the LOAD trait from being exposed + // to clients. The reason for this is that the proxied element + // will complete its load before we're ready to expose its state + // to the outside world, so we block all the other traits so that + // we can expose them when we're truly ready. + var traitsToBlock:Vector. = new Vector.(); + traitsToBlock.push(MediaTraitType.AUDIO); + traitsToBlock.push(MediaTraitType.BUFFER); + traitsToBlock.push(MediaTraitType.DISPLAY_OBJECT); + traitsToBlock.push(MediaTraitType.DRM); + traitsToBlock.push(MediaTraitType.DVR); + traitsToBlock.push(MediaTraitType.DYNAMIC_STREAM); + traitsToBlock.push(MediaTraitType.PLAY); + traitsToBlock.push(MediaTraitType.SEEK); + traitsToBlock.push(MediaTraitType.TIME); + super.blockedTraits = traitsToBlock; + } + + /** + * @private + **/ + override public function set proxiedElement(value:MediaElement):void + { + super.proxiedElement = value; + + if (value != null) + { + if (value.hasTrait(MediaTraitType.LOAD)) + { + processNewLoadTrait(); + } + else + { + // Wait for the LoadTrait to be added. + value.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + } + } + + private function onTraitAdd(event:MediaElementEvent):void + { + if (event.traitType == MediaTraitType.LOAD) + { + proxiedElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + + processNewLoadTrait(); + } + } + + private function processNewLoadTrait():void + { + // Override the LoadTrait with our own custom trait, which provides + // hooks for executing asynchronous logic in conjunction with the + // load of the proxied element. + var asynchLoadTrait:LoadTrait = createAsynchLoadingProxyLoadTrait(); + addTrait(MediaTraitType.LOAD, asynchLoadTrait); + + // Make sure we're informed when the custom load trait signals that + // it's ready, so that we can unblock the other traits. + asynchLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + } + + private function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + // We're now ready to expose the proxied element to the outside + // world, so we unblock all traits. + super.blockedTraits = new Vector.(); + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/AsynchLoadingProxyLoadTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/AsynchLoadingProxyLoadTrait.as index b6cc3a3..a0d635c 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/AsynchLoadingProxyLoadTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/AsynchLoadingProxyLoadTrait.as @@ -1,166 +1,166 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.loaderproxy -{ - import flash.events.Event; - import flash.events.TimerEvent; - import flash.utils.Timer; - - import org.osmf.events.LoadEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - - /** - * A proxy for a LoadTrait. Delays exposing the READY state for 2 seconds - * after the proxied LoadTrait is READY. - **/ - public class AsynchLoadingProxyLoadTrait extends LoadTrait - { - /** - * Constructor. - * - * @param proxiedLoadTrait The LoadTrait to proxy. - **/ - public function AsynchLoadingProxyLoadTrait(proxiedLoadTrait:LoadTrait) - { - super(null, null); - - this.proxiedLoadTrait = proxiedLoadTrait; - proxiedLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - proxiedLoadTrait.addEventListener(LoadEvent.BYTES_TOTAL_CHANGE, onBytesTotalChange); - - calculatedLoadState = proxiedLoadTrait.loadState; - } - - /** - * @private - **/ - override public function get resource():MediaResourceBase - { - return proxiedLoadTrait.resource; - } - - /** - * @private - **/ - override public function get loadState():String - { - // Return our own calculated load state, not the base load state. - return calculatedLoadState; - } - - /** - * @private - **/ - override public function load():void - { - proxiedLoadTrait.load(); - } - - /** - * @private - **/ - override public function unload():void - { - proxiedLoadTrait.unload(); - } - - /** - * @private - **/ - override public function get bytesLoaded():Number - { - return proxiedLoadTrait.bytesLoaded; - } - - /** - * @private - **/ - override public function get bytesTotal():Number - { - return proxiedLoadTrait.bytesTotal; - } - - /** - * Calculated version of the LoadState for this LoadTrait. Distinct - * from the proxied loadState property, which is not exposed to the - * client. - **/ - protected var calculatedLoadState:String; - - /** - * Override this method to define custom load logic that should occur - * during the load operation, but before the READY state is signaled - * to clients. When the custom load logic has finished, set the - * calculatedLoadState to LoadState.READY and dispatch the - * eventToDispatch event. - **/ - protected function doCustomLoadLogic(eventToDispatch:Event):void - { - // For demonstration purposes, we just let a Timer run for a - // few seconds, then signal that we're done. In a more realistic - // scenario, there might be some number of asynchronous calls - // going on. - var timer:Timer = new Timer(2000, 1); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(timerEvent:TimerEvent):void - { - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - // When all of the custom load logic is complete, we update - // our load state and inform the outside world. - calculatedLoadState = LoadState.READY; - dispatchEvent(eventToDispatch); - } - } - - // Internals - // - - private function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - // Although the proxied element is now ready, we don't want - // to expose the READY state to the outside world because we - // want to be able to perform our own custom load logic first. - doCustomLoadLogic(event.clone()); - } - else - { - // Expose the proxied element's state to the outside world. - calculatedLoadState = event.loadState; - dispatchEvent(event.clone()); - } - } - - private function onBytesTotalChange(event:LoadEvent):void - { - dispatchEvent(event.clone()); - } - - private var proxiedLoadTrait:LoadTrait; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.loaderproxy +{ + import flash.events.Event; + import flash.events.TimerEvent; + import flash.utils.Timer; + + import org.osmf.events.LoadEvent; + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + + /** + * A proxy for a LoadTrait. Delays exposing the READY state for 2 seconds + * after the proxied LoadTrait is READY. + **/ + public class AsynchLoadingProxyLoadTrait extends LoadTrait + { + /** + * Constructor. + * + * @param proxiedLoadTrait The LoadTrait to proxy. + **/ + public function AsynchLoadingProxyLoadTrait(proxiedLoadTrait:LoadTrait) + { + super(null, null); + + this.proxiedLoadTrait = proxiedLoadTrait; + proxiedLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + proxiedLoadTrait.addEventListener(LoadEvent.BYTES_TOTAL_CHANGE, onBytesTotalChange); + + calculatedLoadState = proxiedLoadTrait.loadState; + } + + /** + * @private + **/ + override public function get resource():MediaResourceBase + { + return proxiedLoadTrait.resource; + } + + /** + * @private + **/ + override public function get loadState():String + { + // Return our own calculated load state, not the base load state. + return calculatedLoadState; + } + + /** + * @private + **/ + override public function load():void + { + proxiedLoadTrait.load(); + } + + /** + * @private + **/ + override public function unload():void + { + proxiedLoadTrait.unload(); + } + + /** + * @private + **/ + override public function get bytesLoaded():Number + { + return proxiedLoadTrait.bytesLoaded; + } + + /** + * @private + **/ + override public function get bytesTotal():Number + { + return proxiedLoadTrait.bytesTotal; + } + + /** + * Calculated version of the LoadState for this LoadTrait. Distinct + * from the proxied loadState property, which is not exposed to the + * client. + **/ + protected var calculatedLoadState:String; + + /** + * Override this method to define custom load logic that should occur + * during the load operation, but before the READY state is signaled + * to clients. When the custom load logic has finished, set the + * calculatedLoadState to LoadState.READY and dispatch the + * eventToDispatch event. + **/ + protected function doCustomLoadLogic(eventToDispatch:Event):void + { + // For demonstration purposes, we just let a Timer run for a + // few seconds, then signal that we're done. In a more realistic + // scenario, there might be some number of asynchronous calls + // going on. + var timer:Timer = new Timer(2000, 1); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + + function onTimer(timerEvent:TimerEvent):void + { + timer.removeEventListener(TimerEvent.TIMER, onTimer); + + // When all of the custom load logic is complete, we update + // our load state and inform the outside world. + calculatedLoadState = LoadState.READY; + dispatchEvent(eventToDispatch); + } + } + + // Internals + // + + private function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + // Although the proxied element is now ready, we don't want + // to expose the READY state to the outside world because we + // want to be able to perform our own custom load logic first. + doCustomLoadLogic(event.clone()); + } + else + { + // Expose the proxied element's state to the outside world. + calculatedLoadState = event.loadState; + dispatchEvent(event.clone()); + } + } + + private function onBytesTotalChange(event:LoadEvent):void + { + dispatchEvent(event.clone()); + } + + private var proxiedLoadTrait:LoadTrait; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/NonResizingProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/NonResizingProxyElement.as index 90d59bc..57e349e 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/NonResizingProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/NonResizingProxyElement.as @@ -1,117 +1,117 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.loaderproxy -{ - import org.osmf.elements.ProxyElement; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.MediaTraitType; - - /** - * ProxyElement which accepts the first mediaSizeChange event, but prevents - * any subsequent ones from being propagated up. Can be useful as a workaround - * for media that has improperly-specified metadata. - **/ - public class NonResizingProxyElement extends ProxyElement - { - /** - * Constructor. - **/ - public function NonResizingProxyElement(proxiedElement:MediaElement) - { - super(proxiedElement); - } - - /** - * @private - **/ - override public function set proxiedElement(value:MediaElement):void - { - super.proxiedElement = value; - - initialSizeSet = false; - - if (value != null) - { - value.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - value.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); - - processDisplayObjectTrait(value); - } - } - - // Internals - // - - private function onTraitAdd(event:MediaElementEvent):void - { - if (event.traitType == MediaTraitType.DISPLAY_OBJECT) - { - processDisplayObjectTrait(event.target as MediaElement); - } - } - - private function onTraitRemove(event:MediaElementEvent):void - { - if (event.traitType == MediaTraitType.DISPLAY_OBJECT) - { - processDisplayObjectTrait(event.target as MediaElement, true); - } - } - - private function processDisplayObjectTrait(media:MediaElement, remove:Boolean=false):void - { - var displayObjectTrait:DisplayObjectTrait = media.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; - if (displayObjectTrait != null) - { - if (remove) - { - displayObjectTrait.removeEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange); - } - else - { - // Add the listener with a high priority, so that we can - // process the event first. - displayObjectTrait.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange, false, int.MAX_VALUE); - } - } - } - - private function onMediaSizeChange(event:DisplayObjectEvent):void - { - if (initialSizeSet == false && event.newWidth > 0) - { - // This is the initial size, let it propagate. - initialSizeSet = true; - } - else - { - // Initial size already set, prevent this event from propagating. - event.stopImmediatePropagation(); - } - } - - private var initialSizeSet:Boolean; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.loaderproxy +{ + import org.osmf.elements.ProxyElement; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.MediaTraitType; + + /** + * ProxyElement which accepts the first mediaSizeChange event, but prevents + * any subsequent ones from being propagated up. Can be useful as a workaround + * for media that has improperly-specified metadata. + **/ + public class NonResizingProxyElement extends ProxyElement + { + /** + * Constructor. + **/ + public function NonResizingProxyElement(proxiedElement:MediaElement) + { + super(proxiedElement); + } + + /** + * @private + **/ + override public function set proxiedElement(value:MediaElement):void + { + super.proxiedElement = value; + + initialSizeSet = false; + + if (value != null) + { + value.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + value.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); + + processDisplayObjectTrait(value); + } + } + + // Internals + // + + private function onTraitAdd(event:MediaElementEvent):void + { + if (event.traitType == MediaTraitType.DISPLAY_OBJECT) + { + processDisplayObjectTrait(event.target as MediaElement); + } + } + + private function onTraitRemove(event:MediaElementEvent):void + { + if (event.traitType == MediaTraitType.DISPLAY_OBJECT) + { + processDisplayObjectTrait(event.target as MediaElement, true); + } + } + + private function processDisplayObjectTrait(media:MediaElement, remove:Boolean=false):void + { + var displayObjectTrait:DisplayObjectTrait = media.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; + if (displayObjectTrait != null) + { + if (remove) + { + displayObjectTrait.removeEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange); + } + else + { + // Add the listener with a high priority, so that we can + // process the event first. + displayObjectTrait.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange, false, int.MAX_VALUE); + } + } + } + + private function onMediaSizeChange(event:DisplayObjectEvent):void + { + if (initialSizeSet == false && event.newWidth > 0) + { + // This is the initial size, let it propagate. + initialSizeSet = true; + } + else + { + // Initial size already set, prevent this event from propagating. + event.stopImmediatePropagation(); + } + } + + private var initialSizeSet:Boolean; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/UseInstanceProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/UseInstanceProxyElement.as index fa127e2..ff1a6ea 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/UseInstanceProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/UseInstanceProxyElement.as @@ -1,92 +1,92 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.loaderproxy -{ - import org.osmf.elements.ProxyElement; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.net.StreamingURLResource; - - /** - * A ProxyElement which ensures that the resource is a StreamingURLResource - * with urlIncludesFMSApplicationInstance set to true. - * - * Some CDNs require this parameter to be set to true, others don't. For - * those that do, customers aren't always aware of this requirement and as - * a result end up getting "stream not found" errors. This class could be - * used in the plugin for a CDN that requires the parameter to be set to - * true. It ensures that the proxiedElement's resource has the parameter - * set to true, even if the resource wasn't initialized that way. - **/ - public class UseInstanceProxyElement extends ProxyElement - { - /** - * Constructor. - **/ - public function UseInstanceProxyElement(proxiedElement:MediaElement) - { - super(proxiedElement); - - // For elements that already have a resource, make sure we rewrite it. - // (Note that this won't have much effect if the proxied element is - // already loaded. There's little we can do in that case.) - if (proxiedElement.resource != null) - { - this.resource = proxiedElement.resource; - } - } - - /** - * @private - **/ - override public function set resource(value:MediaResourceBase):void - { - if (value != null && value is URLResource) - { - if (value is StreamingURLResource) - { - // Set the use-instance param to true. - StreamingURLResource(value).urlIncludesFMSApplicationInstance = true; - } - else - { - var urlResource:URLResource = value as URLResource; - - // Create a copy of the resource, with the use-instance param set to true. - var streamingResource:StreamingURLResource = new StreamingURLResource(urlResource.url); - streamingResource.mediaType = urlResource.mediaType; - streamingResource.mimeType = urlResource.mimeType; - streamingResource.urlIncludesFMSApplicationInstance = true; - for each (var nsurl:String in urlResource.metadataNamespaceURLs) - { - streamingResource.addMetadataValue(nsurl, urlResource.getMetadataValue(nsurl)); - } - - value = streamingResource; - } - } - - super.resource = value; - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.loaderproxy +{ + import org.osmf.elements.ProxyElement; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.net.StreamingURLResource; + + /** + * A ProxyElement which ensures that the resource is a StreamingURLResource + * with urlIncludesFMSApplicationInstance set to true. + * + * Some CDNs require this parameter to be set to true, others don't. For + * those that do, customers aren't always aware of this requirement and as + * a result end up getting "stream not found" errors. This class could be + * used in the plugin for a CDN that requires the parameter to be set to + * true. It ensures that the proxiedElement's resource has the parameter + * set to true, even if the resource wasn't initialized that way. + **/ + public class UseInstanceProxyElement extends ProxyElement + { + /** + * Constructor. + **/ + public function UseInstanceProxyElement(proxiedElement:MediaElement) + { + super(proxiedElement); + + // For elements that already have a resource, make sure we rewrite it. + // (Note that this won't have much effect if the proxied element is + // already loaded. There's little we can do in that case.) + if (proxiedElement.resource != null) + { + this.resource = proxiedElement.resource; + } + } + + /** + * @private + **/ + override public function set resource(value:MediaResourceBase):void + { + if (value != null && value is URLResource) + { + if (value is StreamingURLResource) + { + // Set the use-instance param to true. + StreamingURLResource(value).urlIncludesFMSApplicationInstance = true; + } + else + { + var urlResource:URLResource = value as URLResource; + + // Create a copy of the resource, with the use-instance param set to true. + var streamingResource:StreamingURLResource = new StreamingURLResource(urlResource.url); + streamingResource.mediaType = urlResource.mediaType; + streamingResource.mimeType = urlResource.mimeType; + streamingResource.urlIncludesFMSApplicationInstance = true; + for each (var nsurl:String in urlResource.metadataNamespaceURLs) + { + streamingResource.addMetadataValue(nsurl, urlResource.getMetadataValue(nsurl)); + } + + value = streamingResource; + } + } + + super.resource = value; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyElement.as index 71b00db..c90ef70 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyElement.as @@ -1,94 +1,94 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.loaderproxy -{ - import org.osmf.elements.ProxyElement; - import org.osmf.events.LoadEvent; - import org.osmf.media.MediaElement; - import org.osmf.media.URLResource; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - - /** - * VideoProxyElement acts as a proxy for a VideoElement, and changes the - * URL of the video (to a hardcoded value) when the video is loaded. The - * point of this example is to demonstrate how to decorate a MediaElement - * with a proxy that can do preflight operations. - **/ - public class VideoProxyElement extends ProxyElement - { - public function VideoProxyElement(wrappedElement:MediaElement) - { - super(wrappedElement); - } - - override protected function setupTraits():void - { - super.setupTraits(); - - // Override the LoadTrait trait with our own custom trait, - // which simply replaces the URL. - // - - loadTrait = new VideoProxyLoadTrait(new VideoProxyLoader(), resource); - - // Use a higher priority so that we can handle the event before - // clients of the VideoProxyElement. This ensures we can expose - // a consistent state to clients. - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onLoadStateChange - , false, int.MAX_VALUE - ); - - addTrait(MediaTraitType.LOAD, loadTrait); - } - - private function onLoadStateChange(event:LoadEvent):void - { - //event.stopPropagation(); - - if (event.loadState == LoadState.READY) - { - // Replace the resource with the new URL. - proxiedElement.resource = new URLResource(loadTrait.url); - - // Our work is done, remove the custom LoadTrait. This will - // expose the base LoadTrait, which we can then use to do - // the actual load. - removeTrait(MediaTraitType.LOAD); - - // Tell the base trait to load (if it hasn't already). - var baseLoadTrait:LoadTrait = getTrait(MediaTraitType.LOAD) as LoadTrait; - if (baseLoadTrait.loadState != LoadState.READY) - { - baseLoadTrait.load(); - } - - loadTrait = null; - } - } - - private var loadTrait:VideoProxyLoadTrait; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.loaderproxy +{ + import org.osmf.elements.ProxyElement; + import org.osmf.events.LoadEvent; + import org.osmf.media.MediaElement; + import org.osmf.media.URLResource; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + + /** + * VideoProxyElement acts as a proxy for a VideoElement, and changes the + * URL of the video (to a hardcoded value) when the video is loaded. The + * point of this example is to demonstrate how to decorate a MediaElement + * with a proxy that can do preflight operations. + **/ + public class VideoProxyElement extends ProxyElement + { + public function VideoProxyElement(wrappedElement:MediaElement) + { + super(wrappedElement); + } + + override protected function setupTraits():void + { + super.setupTraits(); + + // Override the LoadTrait trait with our own custom trait, + // which simply replaces the URL. + // + + loadTrait = new VideoProxyLoadTrait(new VideoProxyLoader(), resource); + + // Use a higher priority so that we can handle the event before + // clients of the VideoProxyElement. This ensures we can expose + // a consistent state to clients. + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onLoadStateChange + , false, int.MAX_VALUE + ); + + addTrait(MediaTraitType.LOAD, loadTrait); + } + + private function onLoadStateChange(event:LoadEvent):void + { + //event.stopPropagation(); + + if (event.loadState == LoadState.READY) + { + // Replace the resource with the new URL. + proxiedElement.resource = new URLResource(loadTrait.url); + + // Our work is done, remove the custom LoadTrait. This will + // expose the base LoadTrait, which we can then use to do + // the actual load. + removeTrait(MediaTraitType.LOAD); + + // Tell the base trait to load (if it hasn't already). + var baseLoadTrait:LoadTrait = getTrait(MediaTraitType.LOAD) as LoadTrait; + if (baseLoadTrait.loadState != LoadState.READY) + { + baseLoadTrait.load(); + } + + loadTrait = null; + } + } + + private var loadTrait:VideoProxyLoadTrait; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyLoadTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyLoadTrait.as index 19f9b14..ed7fd84 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyLoadTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyLoadTrait.as @@ -1,51 +1,51 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.loaderproxy -{ - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - - /** - * LoadTrait for the VideoProxyElement. Holds the URL that will - * be applied to the proxied VideoElement. - **/ - internal class VideoProxyLoadTrait extends LoadTrait - { - public function VideoProxyLoadTrait(loader:LoaderBase, resource:MediaResourceBase) - { - super(loader, resource); - } - - public function get url():String - { - return _url; - } - - public function set url(value:String):void - { - _url = value; - } - - private var _url:String; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.loaderproxy +{ + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + + /** + * LoadTrait for the VideoProxyElement. Holds the URL that will + * be applied to the proxied VideoElement. + **/ + internal class VideoProxyLoadTrait extends LoadTrait + { + public function VideoProxyLoadTrait(loader:LoaderBase, resource:MediaResourceBase) + { + super(loader, resource); + } + + public function get url():String + { + return _url; + } + + public function set url(value:String):void + { + _url = value; + } + + private var _url:String; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyLoader.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyLoader.as index f558a02..5925aa7 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyLoader.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/loaderproxy/VideoProxyLoader.as @@ -1,56 +1,56 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.loaderproxy -{ - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - - /** - * Loader for the VideoProxyElement. The load operation simply generates - * the new URL to apply. - **/ - public class VideoProxyLoader extends LoaderBase - { - /** - * @private - **/ - override public function canHandleResource(resource:MediaResourceBase):Boolean - { - // Always true, for simplicity. - return true; - } - - override protected function executeLoad(loadTrait:LoadTrait):void - { - // Here's a new URL, this will replace the previous URL. - // Note that this class could do other preflight activities - // (we just rewrite the URL as an example). - var url:String = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; - - var vpLoadTrait:VideoProxyLoadTrait = loadTrait as VideoProxyLoadTrait; - vpLoadTrait.url = url; - updateLoadTrait(loadTrait, LoadState.READY); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.loaderproxy +{ + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + + /** + * Loader for the VideoProxyElement. The load operation simply generates + * the new URL to apply. + **/ + public class VideoProxyLoader extends LoaderBase + { + /** + * @private + **/ + override public function canHandleResource(resource:MediaResourceBase):Boolean + { + // Always true, for simplicity. + return true; + } + + override protected function executeLoad(loadTrait:LoadTrait):void + { + // Here's a new URL, this will replace the previous URL. + // Note that this class could do other preflight activities + // (we just rewrite the URL as an example). + var url:String = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; + + var vpLoadTrait:VideoProxyLoadTrait = loadTrait as VideoProxyLoadTrait; + vpLoadTrait.url = url; + updateLoadTrait(loadTrait, LoadState.READY); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/netconnection/SimpleNetConnectionFactory.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/netconnection/SimpleNetConnectionFactory.as index 1a97686..8aff376 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/netconnection/SimpleNetConnectionFactory.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/netconnection/SimpleNetConnectionFactory.as @@ -1,71 +1,71 @@ -/***************************************************** - * - * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. - * - ***************************************************** - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems - * Incorporated. All Rights Reserved. - * - *****************************************************/ -package org.osmf.examples.netconnection -{ - import flash.errors.IllegalOperationError; - import flash.net.NetConnection; - - import org.osmf.events.NetConnectionFactoryEvent; - import org.osmf.media.URLResource; - import org.osmf.net.NetConnectionFactoryBase; - - /** - * NetConnectionFactory which always returns the NetConnection it - * is constructed with. - **/ - public class SimpleNetConnectionFactory extends NetConnectionFactoryBase - { - /** - * Constructor. - * - * @param netConnection The NetConnection to always return. - **/ - public function SimpleNetConnectionFactory(netConnection:NetConnection) - { - super(); - - this.netConnection = netConnection; - - if (netConnection == null) - { - throw new IllegalOperationError(); - } - } - - /** - * @private - **/ - override public function create(resource:URLResource):void - { - dispatchEvent - ( new NetConnectionFactoryEvent - ( NetConnectionFactoryEvent.CREATION_COMPLETE - , false - , false - , netConnection - ) - ); - } - - private var netConnection:NetConnection; - } +/***************************************************** + * + * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.examples.netconnection +{ + import flash.errors.IllegalOperationError; + import flash.net.NetConnection; + + import org.osmf.events.NetConnectionFactoryEvent; + import org.osmf.media.URLResource; + import org.osmf.net.NetConnectionFactoryBase; + + /** + * NetConnectionFactory which always returns the NetConnection it + * is constructed with. + **/ + public class SimpleNetConnectionFactory extends NetConnectionFactoryBase + { + /** + * Constructor. + * + * @param netConnection The NetConnection to always return. + **/ + public function SimpleNetConnectionFactory(netConnection:NetConnection) + { + super(); + + this.netConnection = netConnection; + + if (netConnection == null) + { + throw new IllegalOperationError(); + } + } + + /** + * @private + **/ + override public function create(resource:URLResource):void + { + dispatchEvent + ( new NetConnectionFactoryEvent + ( NetConnectionFactoryEvent.CREATION_COMPLETE + , false + , false + , netConnection + ) + ); + } + + private var netConnection:NetConnection; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/netconnection/SimpleNetLoader.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/netconnection/SimpleNetLoader.as index 8f5a1e4..9e937f9 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/netconnection/SimpleNetLoader.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/netconnection/SimpleNetLoader.as @@ -1,62 +1,62 @@ -/***************************************************** - * - * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. - * - ***************************************************** - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems - * Incorporated. All Rights Reserved. - * - *****************************************************/ -package org.osmf.examples.netconnection -{ - import flash.errors.IllegalOperationError; - import flash.net.NetConnection; - import flash.net.NetStream; - - import org.osmf.media.URLResource; - import org.osmf.net.NetLoader; - - /** - * A NetLoader subclass that allows you to pass in an active NetConnection - * and/or NetStream. Useful for integrating with existing connection - * frameworks or logic. This example is somewhat over-simplified, in that - * it always uses the same NetConnection or NetStream. - **/ - public class SimpleNetLoader extends NetLoader - { - /** - * Constructor. - * - * @param netConnection The NetConnection to use for any request. - * @param netStream The NetStream to use for any request. - **/ - public function SimpleNetLoader(netConnection:NetConnection, netStream:NetStream) - { - super(new SimpleNetConnectionFactory(netConnection)); - - this.netStream = netStream; - } - - /** - * @private - **/ - override protected function createNetStream(connection:NetConnection, resource:URLResource):NetStream - { - return netStream != null ? netStream : new NetStream(connection);; - } - - private var netStream:NetStream; - } +/***************************************************** + * + * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.examples.netconnection +{ + import flash.errors.IllegalOperationError; + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.osmf.media.URLResource; + import org.osmf.net.NetLoader; + + /** + * A NetLoader subclass that allows you to pass in an active NetConnection + * and/or NetStream. Useful for integrating with existing connection + * frameworks or logic. This example is somewhat over-simplified, in that + * it always uses the same NetConnection or NetStream. + **/ + public class SimpleNetLoader extends NetLoader + { + /** + * Constructor. + * + * @param netConnection The NetConnection to use for any request. + * @param netStream The NetStream to use for any request. + **/ + public function SimpleNetLoader(netConnection:NetConnection, netStream:NetStream) + { + super(new SimpleNetConnectionFactory(netConnection)); + + this.netStream = netStream; + } + + /** + * @private + **/ + override protected function createNetStream(connection:NetConnection, resource:URLResource):NetStream + { + return netStream != null ? netStream : new NetStream(connection);; + } + + private var netStream:NetStream; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/PosterFrameElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/PosterFrameElement.as index ff04b9c..2329db2 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/PosterFrameElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/PosterFrameElement.as @@ -1,60 +1,60 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.posterframe -{ - import org.osmf.elements.ImageElement; - import org.osmf.elements.ImageLoader; - import org.osmf.media.URLResource; - import org.osmf.traits.MediaTraitType; - - /** - * A PosterFrameElement is a playable Image Element. Making it playable - * ensures it shows up as a poster frame. - **/ - public class PosterFrameElement extends ImageElement - { - public function PosterFrameElement(resource:URLResource=null, loader:ImageLoader=null) - { - super(resource, loader); - } - - /** - * @private - **/ - override protected function processReadyState():void - { - super.processReadyState(); - - addTrait(MediaTraitType.PLAY, new PosterFramePlayTrait()); - } - - /** - * @private - */ - override protected function processUnloadingState():void - { - super.processUnloadingState(); - - removeTrait(MediaTraitType.PLAY); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.posterframe +{ + import org.osmf.elements.ImageElement; + import org.osmf.elements.ImageLoader; + import org.osmf.media.URLResource; + import org.osmf.traits.MediaTraitType; + + /** + * A PosterFrameElement is a playable Image Element. Making it playable + * ensures it shows up as a poster frame. + **/ + public class PosterFrameElement extends ImageElement + { + public function PosterFrameElement(resource:URLResource=null, loader:ImageLoader=null) + { + super(resource, loader); + } + + /** + * @private + **/ + override protected function processReadyState():void + { + super.processReadyState(); + + addTrait(MediaTraitType.PLAY, new PosterFramePlayTrait()); + } + + /** + * @private + */ + override protected function processUnloadingState():void + { + super.processUnloadingState(); + + removeTrait(MediaTraitType.PLAY); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/PosterFramePlayTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/PosterFramePlayTrait.as index aed71a5..40f9aca 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/PosterFramePlayTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/PosterFramePlayTrait.as @@ -1,52 +1,52 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.posterframe -{ - import org.osmf.media.MediaElement; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - - internal class PosterFramePlayTrait extends PlayTrait - { - public function PosterFramePlayTrait() - { - super(); - } - - override public function get canPause():Boolean - { - return false; - } - - override protected function playStateChangeEnd():void - { - super.playStateChangeEnd(); - - if (playState == PlayState.PLAYING) - { - // When the play() is finished, we reset our state to "not playing", - // since this trait has completed its work. - stop(); - } - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.posterframe +{ + import org.osmf.media.MediaElement; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + + internal class PosterFramePlayTrait extends PlayTrait + { + public function PosterFramePlayTrait() + { + super(); + } + + override public function get canPause():Boolean + { + return false; + } + + override protected function playStateChangeEnd():void + { + super.playStateChangeEnd(); + + if (playState == PlayState.PLAYING) + { + // When the play() is finished, we reset our state to "not playing", + // since this trait has completed its work. + stop(); + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/RTMPPosterFrameElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/RTMPPosterFrameElement.as index 3cfcc72..39af0af 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/RTMPPosterFrameElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/posterframe/RTMPPosterFrameElement.as @@ -1,118 +1,118 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.posterframe -{ - import org.osmf.elements.ProxyElement; - import org.osmf.elements.VideoElement; - import org.osmf.events.MediaElementEvent; - import org.osmf.media.MediaElement; - import org.osmf.net.NetLoader; - import org.osmf.net.StreamingURLResource; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - - /** - * An RTMPPosterFrameElement is a proxy that wraps up a VideoElement that only - * shows a single frame. - **/ - public class RTMPPosterFrameElement extends ProxyElement - { - public function RTMPPosterFrameElement(resource:StreamingURLResource, posterFrameTime:Number, netLoader:NetLoader) - { - super(); - - // Treat this as a zero-length subclip. - resource.clipStartTime = posterFrameTime; - resource.clipEndTime = posterFrameTime; - - proxiedElement = new VideoElement(resource, netLoader); - } - - /** - * @private - **/ - override protected function setupTraits():void - { - super.setupTraits(); - - // Block all traits other than LOAD (so we can load the base - // VideoElement), DISPLAY_OBJECT (so we can display its view), - // and PLAY (which we'll override). This makes this element - // the functional equivalent of a playable ImageElement. - var traitsToBlock:Vector. = new Vector.(); - traitsToBlock.push(MediaTraitType.AUDIO); - traitsToBlock.push(MediaTraitType.BUFFER); - traitsToBlock.push(MediaTraitType.DRM); - traitsToBlock.push(MediaTraitType.DVR); - traitsToBlock.push(MediaTraitType.DYNAMIC_STREAM); - traitsToBlock.push(MediaTraitType.SEEK); - traitsToBlock.push(MediaTraitType.TIME); - super.blockedTraits = traitsToBlock; - - // To ensure that the user can complete playback of this item - // (and can't interact with the VideoElement), we add a dummy - // PlayTrait trait. - addTrait(MediaTraitType.PLAY, new PosterFramePlayTrait()); - } - - /** - * @private - **/ - override public function set proxiedElement(value:MediaElement):void - { - super.proxiedElement = value; - - if (value != null) - { - if (value.hasTrait(MediaTraitType.PLAY)) - { - processPlayTrait(); - } - else - { - // Wait for the PlayTrait to be added. - value.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - } - } - - private function onTraitAdd(event:MediaElementEvent):void - { - if (event.traitType == MediaTraitType.PLAY) - { - proxiedElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - - processPlayTrait(); - } - } - - private function processPlayTrait():void - { - // Calling play() on the proxied VideoElement's trait will - // cause the poster frame to be displayed. But because the - // base play trait is overridden, no events are dispatched - // to the client. - var playTrait:PlayTrait = proxiedElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - playTrait.play(); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.posterframe +{ + import org.osmf.elements.ProxyElement; + import org.osmf.elements.VideoElement; + import org.osmf.events.MediaElementEvent; + import org.osmf.media.MediaElement; + import org.osmf.net.NetLoader; + import org.osmf.net.StreamingURLResource; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + + /** + * An RTMPPosterFrameElement is a proxy that wraps up a VideoElement that only + * shows a single frame. + **/ + public class RTMPPosterFrameElement extends ProxyElement + { + public function RTMPPosterFrameElement(resource:StreamingURLResource, posterFrameTime:Number, netLoader:NetLoader) + { + super(); + + // Treat this as a zero-length subclip. + resource.clipStartTime = posterFrameTime; + resource.clipEndTime = posterFrameTime; + + proxiedElement = new VideoElement(resource, netLoader); + } + + /** + * @private + **/ + override protected function setupTraits():void + { + super.setupTraits(); + + // Block all traits other than LOAD (so we can load the base + // VideoElement), DISPLAY_OBJECT (so we can display its view), + // and PLAY (which we'll override). This makes this element + // the functional equivalent of a playable ImageElement. + var traitsToBlock:Vector. = new Vector.(); + traitsToBlock.push(MediaTraitType.AUDIO); + traitsToBlock.push(MediaTraitType.BUFFER); + traitsToBlock.push(MediaTraitType.DRM); + traitsToBlock.push(MediaTraitType.DVR); + traitsToBlock.push(MediaTraitType.DYNAMIC_STREAM); + traitsToBlock.push(MediaTraitType.SEEK); + traitsToBlock.push(MediaTraitType.TIME); + super.blockedTraits = traitsToBlock; + + // To ensure that the user can complete playback of this item + // (and can't interact with the VideoElement), we add a dummy + // PlayTrait trait. + addTrait(MediaTraitType.PLAY, new PosterFramePlayTrait()); + } + + /** + * @private + **/ + override public function set proxiedElement(value:MediaElement):void + { + super.proxiedElement = value; + + if (value != null) + { + if (value.hasTrait(MediaTraitType.PLAY)) + { + processPlayTrait(); + } + else + { + // Wait for the PlayTrait to be added. + value.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + } + } + + private function onTraitAdd(event:MediaElementEvent):void + { + if (event.traitType == MediaTraitType.PLAY) + { + proxiedElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + + processPlayTrait(); + } + } + + private function processPlayTrait():void + { + // Calling play() on the proxied VideoElement's trait will + // cause the poster frame to be displayed. But because the + // base play trait is overridden, no events are dispatched + // to the client. + var playTrait:PlayTrait = proxiedElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + playTrait.play(); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/recommendations/RecommendationsElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/recommendations/RecommendationsElement.as index 9489df0..9b890a2 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/recommendations/RecommendationsElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/recommendations/RecommendationsElement.as @@ -1,83 +1,83 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.examples.recommendations -{ - import flash.display.Graphics; - import flash.display.Sprite; - import flash.events.MouseEvent; - import flash.text.TextField; - import flash.text.TextFormat; - import flash.text.TextFormatAlign; - - import org.osmf.media.MediaElement; - import org.osmf.metadata.Metadata; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.MediaTraitType; - - [Event(name="click", type="flash.events.MouseEvent")] - - public class RecommendationsElement extends MediaElement - { - public function RecommendationsElement() - { - super(); - - var format:TextFormat = new TextFormat(); - format.font = "Verdana"; - format.color = 0xFFFFFF; - format.size = 14; - format.align = TextFormatAlign.CENTER; - - var textField:TextField = new TextField(); - textField.defaultTextFormat = format; - textField.text = "Click to jump to the 'Video with Timed Ad Insertion' example!"; - textField.y = 100; - textField.width = 640; - textField.selectable = false; - - displayObject = new Sprite(); - - var g:Graphics = displayObject.graphics; - g.beginFill(0xffffff, 0.2); - g.drawRect(0,0,640, 360); - g.endFill(); - - displayObject.addChild(textField); - displayObject.addEventListener(MouseEvent.CLICK, onMouseClick); - - var displayObjectTrait:DisplayObjectTrait = new DisplayObjectTrait(displayObject, 640, 360); - - addTrait(MediaTraitType.DISPLAY_OBJECT, displayObjectTrait); - } - - private function onMouseClick(event:MouseEvent):void - { - var data:Metadata = new Metadata(); - data.addValue("open", "Video with Timed Ad Insertion"); - - addMetadata("recommendations", data); - } - - private var displayObject:Sprite; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.examples.recommendations +{ + import flash.display.Graphics; + import flash.display.Sprite; + import flash.events.MouseEvent; + import flash.text.TextField; + import flash.text.TextFormat; + import flash.text.TextFormatAlign; + + import org.osmf.media.MediaElement; + import org.osmf.metadata.Metadata; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.MediaTraitType; + + [Event(name="click", type="flash.events.MouseEvent")] + + public class RecommendationsElement extends MediaElement + { + public function RecommendationsElement() + { + super(); + + var format:TextFormat = new TextFormat(); + format.font = "Verdana"; + format.color = 0xFFFFFF; + format.size = 14; + format.align = TextFormatAlign.CENTER; + + var textField:TextField = new TextField(); + textField.defaultTextFormat = format; + textField.text = "Click to jump to the 'Video with Timed Ad Insertion' example!"; + textField.y = 100; + textField.width = 640; + textField.selectable = false; + + displayObject = new Sprite(); + + var g:Graphics = displayObject.graphics; + g.beginFill(0xffffff, 0.2); + g.drawRect(0,0,640, 360); + g.endFill(); + + displayObject.addChild(textField); + displayObject.addEventListener(MouseEvent.CLICK, onMouseClick); + + var displayObjectTrait:DisplayObjectTrait = new DisplayObjectTrait(displayObject, 640, 360); + + addTrait(MediaTraitType.DISPLAY_OBJECT, displayObjectTrait); + } + + private function onMouseClick(event:MouseEvent):void + { + var data:Metadata = new Metadata(); + data.addValue("open", "Video with Timed Ad Insertion"); + + addMetadata("recommendations", data); + } + + private var displayObject:Sprite; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/PreloadingLoadTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/PreloadingLoadTrait.as index 2d8041f..3d94ca0 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/PreloadingLoadTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/PreloadingLoadTrait.as @@ -1,141 +1,141 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.seeking -{ - import flash.events.Event; - import flash.events.TimerEvent; - import flash.utils.Timer; - - import org.osmf.events.MediaElementEvent; - import org.osmf.events.PlayEvent; - import org.osmf.events.SeekEvent; - import org.osmf.examples.loaderproxy.AsynchLoadingProxyLoadTrait; - import org.osmf.media.MediaElement; - import org.osmf.traits.AudioTrait; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - - /** - * A LoadTrait which maps the "load" operation to the preloading of - * a different MediaElement. - * - * The preload operation is defined as the load of the MediaElement, - * followed by a play and pause in succession. (The play/pause was - * added because RTMP streams need to be played before they're seekable.) - **/ - public class PreloadingLoadTrait extends AsynchLoadingProxyLoadTrait - { - /** - * Constructor. - **/ - public function PreloadingLoadTrait(proxiedElement:MediaElement) - { - super(proxiedElement.getTrait(MediaTraitType.LOAD) as LoadTrait); - - this.proxiedElement = proxiedElement; - - load(); - } - - /** - * @private - **/ - override protected function doCustomLoadLogic(eventToDispatch:Event):void - { - var playTrait:PlayTrait = proxiedElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - if (playTrait != null) - { - var audioTrait:AudioTrait = proxiedElement.getTrait(MediaTraitType.AUDIO) as AudioTrait; - - // Mute the video, but remember the mute state. - var previousMuted:Boolean = audioTrait.muted; - audioTrait.muted = true; - - // Begin playback. But don't pause immediately, as doing so for MBR - // streams seems to put them in a bad state. - playTrait.play(); - - var timer:Timer = new Timer(500, 1); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(event:TimerEvent):void - { - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - // Now pause the stream and seek back to the start. - playTrait.pause(); - - // It's possible that the media isn't seekable yet, in which - // case we must wait until it is. - var seekTrait:SeekTrait = proxiedElement.getTrait(MediaTraitType.SEEK) as SeekTrait; - if (seekTrait != null) - { - // Seek back to the start. - seekTrait.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); - seekTrait.seek(0); - - function onSeekingChange(event:SeekEvent):void - { - if (event.seeking == false) - { - seekTrait.removeEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); - - // Restore the original muted state, and signal we're loaded. - audioTrait.muted = previousMuted; - - calculatedLoadState = LoadState.READY; - dispatchEvent(eventToDispatch); - } - } - } - else - { - proxiedElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - - function onTraitAdd(event:MediaElementEvent):void - { - if (event.traitType == MediaTraitType.SEEK) - { - proxiedElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - - // Now we can seek back to the start. - seekTrait = proxiedElement.getTrait(MediaTraitType.SEEK) as SeekTrait; - seekTrait.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); - seekTrait.seek(0); - } - } - } - } - } - else - { - dispatchEvent(eventToDispatch); - } - } - - private var proxiedElement:MediaElement; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.seeking +{ + import flash.events.Event; + import flash.events.TimerEvent; + import flash.utils.Timer; + + import org.osmf.events.MediaElementEvent; + import org.osmf.events.PlayEvent; + import org.osmf.events.SeekEvent; + import org.osmf.examples.loaderproxy.AsynchLoadingProxyLoadTrait; + import org.osmf.media.MediaElement; + import org.osmf.traits.AudioTrait; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + + /** + * A LoadTrait which maps the "load" operation to the preloading of + * a different MediaElement. + * + * The preload operation is defined as the load of the MediaElement, + * followed by a play and pause in succession. (The play/pause was + * added because RTMP streams need to be played before they're seekable.) + **/ + public class PreloadingLoadTrait extends AsynchLoadingProxyLoadTrait + { + /** + * Constructor. + **/ + public function PreloadingLoadTrait(proxiedElement:MediaElement) + { + super(proxiedElement.getTrait(MediaTraitType.LOAD) as LoadTrait); + + this.proxiedElement = proxiedElement; + + load(); + } + + /** + * @private + **/ + override protected function doCustomLoadLogic(eventToDispatch:Event):void + { + var playTrait:PlayTrait = proxiedElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + if (playTrait != null) + { + var audioTrait:AudioTrait = proxiedElement.getTrait(MediaTraitType.AUDIO) as AudioTrait; + + // Mute the video, but remember the mute state. + var previousMuted:Boolean = audioTrait.muted; + audioTrait.muted = true; + + // Begin playback. But don't pause immediately, as doing so for MBR + // streams seems to put them in a bad state. + playTrait.play(); + + var timer:Timer = new Timer(500, 1); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + + function onTimer(event:TimerEvent):void + { + timer.removeEventListener(TimerEvent.TIMER, onTimer); + + // Now pause the stream and seek back to the start. + playTrait.pause(); + + // It's possible that the media isn't seekable yet, in which + // case we must wait until it is. + var seekTrait:SeekTrait = proxiedElement.getTrait(MediaTraitType.SEEK) as SeekTrait; + if (seekTrait != null) + { + // Seek back to the start. + seekTrait.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); + seekTrait.seek(0); + + function onSeekingChange(event:SeekEvent):void + { + if (event.seeking == false) + { + seekTrait.removeEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); + + // Restore the original muted state, and signal we're loaded. + audioTrait.muted = previousMuted; + + calculatedLoadState = LoadState.READY; + dispatchEvent(eventToDispatch); + } + } + } + else + { + proxiedElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + + function onTraitAdd(event:MediaElementEvent):void + { + if (event.traitType == MediaTraitType.SEEK) + { + proxiedElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + + // Now we can seek back to the start. + seekTrait = proxiedElement.getTrait(MediaTraitType.SEEK) as SeekTrait; + seekTrait.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); + seekTrait.seek(0); + } + } + } + } + } + else + { + dispatchEvent(eventToDispatch); + } + } + + private var proxiedElement:MediaElement; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/PreloadingProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/PreloadingProxyElement.as index 66d5487..af0e8b8 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/PreloadingProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/PreloadingProxyElement.as @@ -1,52 +1,52 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.seeking -{ - import org.osmf.examples.loaderproxy.AsynchLoadingProxyElement; - import org.osmf.media.MediaElement; - import org.osmf.traits.LoadTrait; - - /** - * A ProxyElement which preloads its proxied element up front. The preload - * operation is defined as a load plus a play followed by a pause. Extends - * AsynchLoadingProxyElement, which is a generic base class for proxies that - * need to incorporate custom logic into the load operation. - **/ - public class PreloadingProxyElement extends AsynchLoadingProxyElement - { - /** - * Constructor. - **/ - public function PreloadingProxyElement(proxiedElement:MediaElement) - { - super(proxiedElement); - } - - /** - * @private - **/ - override protected function createAsynchLoadingProxyLoadTrait():LoadTrait - { - return new PreloadingLoadTrait(proxiedElement); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.seeking +{ + import org.osmf.examples.loaderproxy.AsynchLoadingProxyElement; + import org.osmf.media.MediaElement; + import org.osmf.traits.LoadTrait; + + /** + * A ProxyElement which preloads its proxied element up front. The preload + * operation is defined as a load plus a play followed by a pause. Extends + * AsynchLoadingProxyElement, which is a generic base class for proxies that + * need to incorporate custom logic into the load operation. + **/ + public class PreloadingProxyElement extends AsynchLoadingProxyElement + { + /** + * Constructor. + **/ + public function PreloadingProxyElement(proxiedElement:MediaElement) + { + super(proxiedElement); + } + + /** + * @private + **/ + override protected function createAsynchLoadingProxyLoadTrait():LoadTrait + { + return new PreloadingLoadTrait(proxiedElement); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/UnseekableProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/UnseekableProxyElement.as index 5234f76..73ca7f9 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/UnseekableProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/seeking/UnseekableProxyElement.as @@ -1,82 +1,82 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.seeking -{ - import __AS3__.vec.Vector; - - import org.osmf.elements.ProxyElement; - import org.osmf.events.SeekEvent; - import org.osmf.events.TimeEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.TraitEventDispatcher; - - /** - * A ProxyElement which can non-invasively prevent another - * MediaElement from being seekable. - **/ - public class UnseekableProxyElement extends ProxyElement - { - public function UnseekableProxyElement(proxiedElement:MediaElement) - { - super(proxiedElement); - - // Prevent seeking. - enableSeeking(false); - - // We need to know when playback completes and when the media - // is rewound. - var traitEventDispatcher:TraitEventDispatcher = new TraitEventDispatcher(); - traitEventDispatcher.media = proxiedElement; - traitEventDispatcher.addEventListener(TimeEvent.COMPLETE, onComplete); - traitEventDispatcher.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); - } - - private function onComplete(event:TimeEvent):void - { - // When playback completes, unblock seeking (i.e. so that we - // can be rewound). - blockedTraits = new Vector.(); - } - - private function onSeekingChange(event:SeekEvent):void - { - if (event.seeking == false && event.time == 0) - { - // Prevent seeking. - enableSeeking(false); - } - } - - private function enableSeeking(enable:Boolean):void - { - var traitsToBlock:Vector. = new Vector.(); - - if (enable == false) - { - traitsToBlock.push(MediaTraitType.SEEK); - } - - blockedTraits = traitsToBlock; - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.seeking +{ + import __AS3__.vec.Vector; + + import org.osmf.elements.ProxyElement; + import org.osmf.events.SeekEvent; + import org.osmf.events.TimeEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.TraitEventDispatcher; + + /** + * A ProxyElement which can non-invasively prevent another + * MediaElement from being seekable. + **/ + public class UnseekableProxyElement extends ProxyElement + { + public function UnseekableProxyElement(proxiedElement:MediaElement) + { + super(proxiedElement); + + // Prevent seeking. + enableSeeking(false); + + // We need to know when playback completes and when the media + // is rewound. + var traitEventDispatcher:TraitEventDispatcher = new TraitEventDispatcher(); + traitEventDispatcher.media = proxiedElement; + traitEventDispatcher.addEventListener(TimeEvent.COMPLETE, onComplete); + traitEventDispatcher.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); + } + + private function onComplete(event:TimeEvent):void + { + // When playback completes, unblock seeking (i.e. so that we + // can be rewound). + blockedTraits = new Vector.(); + } + + private function onSeekingChange(event:SeekEvent):void + { + if (event.seeking == false && event.time == 0) + { + // Prevent seeking. + enableSeeking(false); + } + } + + private function enableSeeking(enable:Boolean):void + { + var traitsToBlock:Vector. = new Vector.(); + + if (enable == false) + { + traitsToBlock.push(MediaTraitType.SEEK); + } + + blockedTraits = traitsToBlock; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/switchingproxy/SwitchingProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/switchingproxy/SwitchingProxyElement.as index ca53640..39fedd0 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/switchingproxy/SwitchingProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/switchingproxy/SwitchingProxyElement.as @@ -1,121 +1,121 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.switchingproxy -{ - import flash.events.TimerEvent; - import flash.utils.Timer; - - import org.osmf.elements.ProxyElement; - import org.osmf.events.LoadEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - - /** - * SwitchingProxyElement is capable of switching between two MediaElements - * at runtime. - * - * @param firstElement The first MediaElement to display. - * @param secondElement The MediaElement to switch to at runtime. - * @param switchTime The time (in seconds) at which to switch from the first to the second. - * @param numSwitches The number of switches back and forth to do. Default is one. - **/ - public class SwitchingProxyElement extends ProxyElement - { - public function SwitchingProxyElement(firstElement:MediaElement, secondElement:MediaElement, switchTime:Number, numSwitches:int=1) - { - super(firstElement); - - this.firstElement = firstElement; - this.secondElement = secondElement; - this.switchTime = switchTime; - - switchTimer = new Timer(switchTime*1000, numSwitches); - switchTimer.addEventListener(TimerEvent.TIMER, onSwitchTimer); - - // Make sure both elements are loaded up front, so that our switch - // is seamless. - var firstLoadTrait:LoadTrait = firstElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - if (firstLoadTrait != null && firstLoadTrait.loadState == LoadState.UNINITIALIZED) - { - firstLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange, false, 0, true); - firstLoadTrait.load(); - } - var secondLoadTrait:LoadTrait = secondElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - if (secondLoadTrait != null && secondLoadTrait.loadState == LoadState.UNINITIALIZED) - { - secondLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange, false, 0, true); - secondLoadTrait.load(); - } - } - - private function onSwitchTimer(event:TimerEvent):void - { - // First pause the current one. - var currentPlayTrait:PlayTrait = proxiedElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - if (currentPlayTrait != null && currentPlayTrait.playState == PlayState.PLAYING) - { - currentPlayTrait.pause(); - } - - // Then switch wrapped elements. - proxiedElement = (proxiedElement == firstElement ? secondElement : firstElement); - - // Then play the new current one. - currentPlayTrait = proxiedElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - if (currentPlayTrait != null && currentPlayTrait.playState != PlayState.PLAYING) - { - currentPlayTrait.play(); - } - } - - private function onLoadStateChange(event:LoadEvent):void - { - // Start our timer as soon as something is loaded. - if ( event.loadState == LoadState.READY - && switchTimer.running == false - ) - { - switchTimer.start(); - } - - // If one of the two elements is unloaded, we should force the other - // to unload as well. - if ( event.loadState == LoadState.UNLOADING - && event.target == proxiedElement.getTrait(MediaTraitType.LOAD) - ) - { - var otherElement:MediaElement = (proxiedElement == firstElement ? secondElement : firstElement); - var otherLoadTrait:LoadTrait = otherElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - otherLoadTrait.unload(); - } - } - - private var firstElement:MediaElement; - private var secondElement:MediaElement; - private var switchTime:Number; - private var switchTimer:Timer; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.switchingproxy +{ + import flash.events.TimerEvent; + import flash.utils.Timer; + + import org.osmf.elements.ProxyElement; + import org.osmf.events.LoadEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + + /** + * SwitchingProxyElement is capable of switching between two MediaElements + * at runtime. + * + * @param firstElement The first MediaElement to display. + * @param secondElement The MediaElement to switch to at runtime. + * @param switchTime The time (in seconds) at which to switch from the first to the second. + * @param numSwitches The number of switches back and forth to do. Default is one. + **/ + public class SwitchingProxyElement extends ProxyElement + { + public function SwitchingProxyElement(firstElement:MediaElement, secondElement:MediaElement, switchTime:Number, numSwitches:int=1) + { + super(firstElement); + + this.firstElement = firstElement; + this.secondElement = secondElement; + this.switchTime = switchTime; + + switchTimer = new Timer(switchTime*1000, numSwitches); + switchTimer.addEventListener(TimerEvent.TIMER, onSwitchTimer); + + // Make sure both elements are loaded up front, so that our switch + // is seamless. + var firstLoadTrait:LoadTrait = firstElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + if (firstLoadTrait != null && firstLoadTrait.loadState == LoadState.UNINITIALIZED) + { + firstLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange, false, 0, true); + firstLoadTrait.load(); + } + var secondLoadTrait:LoadTrait = secondElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + if (secondLoadTrait != null && secondLoadTrait.loadState == LoadState.UNINITIALIZED) + { + secondLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange, false, 0, true); + secondLoadTrait.load(); + } + } + + private function onSwitchTimer(event:TimerEvent):void + { + // First pause the current one. + var currentPlayTrait:PlayTrait = proxiedElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + if (currentPlayTrait != null && currentPlayTrait.playState == PlayState.PLAYING) + { + currentPlayTrait.pause(); + } + + // Then switch wrapped elements. + proxiedElement = (proxiedElement == firstElement ? secondElement : firstElement); + + // Then play the new current one. + currentPlayTrait = proxiedElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + if (currentPlayTrait != null && currentPlayTrait.playState != PlayState.PLAYING) + { + currentPlayTrait.play(); + } + } + + private function onLoadStateChange(event:LoadEvent):void + { + // Start our timer as soon as something is loaded. + if ( event.loadState == LoadState.READY + && switchTimer.running == false + ) + { + switchTimer.start(); + } + + // If one of the two elements is unloaded, we should force the other + // to unload as well. + if ( event.loadState == LoadState.UNLOADING + && event.target == proxiedElement.getTrait(MediaTraitType.LOAD) + ) + { + var otherElement:MediaElement = (proxiedElement == firstElement ? secondElement : firstElement); + var otherLoadTrait:LoadTrait = otherElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + otherLoadTrait.unload(); + } + } + + private var firstElement:MediaElement; + private var secondElement:MediaElement; + private var switchTime:Number; + private var switchTimer:Timer; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/text/TextDisplayObjectTrait.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/text/TextDisplayObjectTrait.as index ea82d7c..7dc66a8 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/text/TextDisplayObjectTrait.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/text/TextDisplayObjectTrait.as @@ -1,40 +1,40 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.text -{ - import flash.display.DisplayObject; - - import org.osmf.traits.DisplayObjectTrait; - - internal class TextDisplayObjectTrait extends DisplayObjectTrait - { - public function TextDisplayObjectTrait(displayObject:DisplayObject, mediaWidth:Number=0, mediaHeight:Number=0) - { - super(displayObject, mediaWidth, mediaHeight); - } - - public function setSize(mediaWidth:Number, mediaHeight:Number):void - { - setMediaSize(mediaWidth, mediaHeight); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.text +{ + import flash.display.DisplayObject; + + import org.osmf.traits.DisplayObjectTrait; + + internal class TextDisplayObjectTrait extends DisplayObjectTrait + { + public function TextDisplayObjectTrait(displayObject:DisplayObject, mediaWidth:Number=0, mediaHeight:Number=0) + { + super(displayObject, mediaWidth, mediaHeight); + } + + public function setSize(mediaWidth:Number, mediaHeight:Number):void + { + setMediaSize(mediaWidth, mediaHeight); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/text/TextElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/text/TextElement.as index 0b0cd2d..62049f6 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/text/TextElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/text/TextElement.as @@ -1,89 +1,89 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.text -{ - import flash.text.TextField; - import flash.text.TextFieldAutoSize; - import flash.text.TextFormat; - - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.DisplayObjectTrait; - - public class TextElement extends MediaElement - { - public function TextElement(text:String=null) - { - super(); - - this.text = text; - } - - public function set text(value:String):void - { - if (value != text) - { - _text = value; - - updateText(); - } - } - - public function get text():String - { - return _text; - } - - // Internals - // - - private function updateText():void - { - var textField:TextField = new TextField(); - textField.autoSize = TextFieldAutoSize.LEFT; - - var format:TextFormat = new TextFormat(); - format.font = "Verdana"; - format.color = 0xFFFFFF; - format.size = 30; - - textField.defaultTextFormat = format; - - if (text != null) - { - textField.text = text; - - if (displayObjectTrait == null) - { - displayObjectTrait = new TextDisplayObjectTrait(textField); - - addTrait(MediaTraitType.DISPLAY_OBJECT, displayObjectTrait); - } - - displayObjectTrait.setSize(textField.width, textField.height); - } - } - - private var displayObjectTrait:TextDisplayObjectTrait; - private var _text:String; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.text +{ + import flash.text.TextField; + import flash.text.TextFieldAutoSize; + import flash.text.TextFormat; + + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.DisplayObjectTrait; + + public class TextElement extends MediaElement + { + public function TextElement(text:String=null) + { + super(); + + this.text = text; + } + + public function set text(value:String):void + { + if (value != text) + { + _text = value; + + updateText(); + } + } + + public function get text():String + { + return _text; + } + + // Internals + // + + private function updateText():void + { + var textField:TextField = new TextField(); + textField.autoSize = TextFieldAutoSize.LEFT; + + var format:TextFormat = new TextFormat(); + format.font = "Verdana"; + format.color = 0xFFFFFF; + format.size = 30; + + textField.defaultTextFormat = format; + + if (text != null) + { + textField.text = text; + + if (displayObjectTrait == null) + { + displayObjectTrait = new TextDisplayObjectTrait(textField); + + addTrait(MediaTraitType.DISPLAY_OBJECT, displayObjectTrait); + } + + displayObjectTrait.setSize(textField.width, textField.height); + } + } + + private var displayObjectTrait:TextDisplayObjectTrait; + private var _text:String; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/traceproxy/TraceListenerProxyElement.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/traceproxy/TraceListenerProxyElement.as index dd4bdc0..485722a 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/traceproxy/TraceListenerProxyElement.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/traceproxy/TraceListenerProxyElement.as @@ -1,170 +1,170 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.traceproxy -{ - import org.osmf.elements.*; - import org.osmf.events.*; - import org.osmf.media.*; - import org.osmf.metadata.*; - import org.osmf.traits.*; - - public class TraceListenerProxyElement extends ProxyElement - { - public function TraceListenerProxyElement(wrappedElement:MediaElement) - { - super(wrappedElement); - - dispatcher = new TraitEventDispatcher(); - dispatcher.media = wrappedElement; - - dispatcher.addEventListener(AudioEvent.MUTED_CHANGE, processMutedChange); - dispatcher.addEventListener(AudioEvent.PAN_CHANGE, processPanChange); - dispatcher.addEventListener(AudioEvent.VOLUME_CHANGE, processVolumeChange); - dispatcher.addEventListener(BufferEvent.BUFFER_TIME_CHANGE, processBufferTimeChange); - dispatcher.addEventListener(BufferEvent.BUFFERING_CHANGE, processBufferingChange); - dispatcher.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, processDisplayObjectChange); - dispatcher.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, processMediaSizeChange); - dispatcher.addEventListener(DRMEvent.DRM_STATE_CHANGE, processDRMStateChange); - dispatcher.addEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, processAutoSwitchChange); - dispatcher.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, processNumDynamicStreamsChange); - dispatcher.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, processSwitchingChange); - dispatcher.addEventListener(LoadEvent.BYTES_TOTAL_CHANGE, processBytesTotalChange); - dispatcher.addEventListener(LoadEvent.LOAD_STATE_CHANGE, processLoadStateChange); - dispatcher.addEventListener(PlayEvent.CAN_PAUSE_CHANGE, processCanPauseChange); - dispatcher.addEventListener(PlayEvent.PLAY_STATE_CHANGE, processPlayStateChange); - dispatcher.addEventListener(SeekEvent.SEEKING_CHANGE, processSeekingChange); - dispatcher.addEventListener(TimeEvent.COMPLETE, processComplete); - dispatcher.addEventListener(TimeEvent.DURATION_CHANGE, processDurationChange); - - wrappedElement.addEventListener(MediaElementEvent.TRAIT_ADD, processTraitAdd); - wrappedElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, processTraitRemove); - } - - - // Overrides - // - - private function processAutoSwitchChange(event:DynamicStreamEvent):void - { - trace("autoSwitchChange", event.autoSwitch); - } - - private function processBufferingChange(event:BufferEvent):void - { - trace("bufferingChange", event.buffering); - } - - private function processBufferTimeChange(event:BufferEvent):void - { - trace("bufferTimeChange", event.bufferTime); - } - - private function processComplete(event:TimeEvent):void - { - trace("complete"); - } - - private function processCanPauseChange(event:PlayEvent):void - { - trace("canPauseChange", event.canPause); - } - - private function processDisplayObjectChange(event:DisplayObjectEvent):void - { - trace("displayObjectChange"); - } - - private function processDurationChange(event:TimeEvent):void - { - trace("durationChange", event.time); - } - - private function processLoadStateChange(event:LoadEvent):void - { - trace("loadStateChange", event.loadState); - } - - private function processBytesTotalChange(event:LoadEvent):void - { - trace("bytesTotalChange", event.bytes); - } - - - private function processMediaSizeChange(event:DisplayObjectEvent):void - { - trace("mediaSizeChange", event.newWidth, event.newHeight); - } - - private function processMutedChange(event:AudioEvent):void - { - trace("mutedChange", event.muted); - } - - private function processNumDynamicStreamsChange(event:DynamicStreamEvent):void - { - trace("numDynamicStreamsChange"); - } - - private function processPanChange(event:AudioEvent):void - { - trace("panChange", event.pan); - } - - private function processPlayStateChange(event:PlayEvent):void - { - trace("playStateChange", event.playState); - } - - private function processSeekingChange(event:SeekEvent):void - { - trace("seekingChange", event.seeking, event.time); - } - - private function processSwitchingChange(event:DynamicStreamEvent):void - { - trace("switchingChange", event.switching); - } - - private function processVolumeChange(event:AudioEvent):void - { - trace("volumeChange", event.volume); - } - - private function processDRMStateChange(event:DRMEvent):void - { - trace("drmStateChange", event.drmState); - } - - private function processTraitAdd(event:MediaElementEvent):void - { - trace("Trait Add: " + event.traitType); - } - - private function processTraitRemove(event:MediaElementEvent):void - { - trace("Trait Remove: " + event.traitType); - } - - - private var dispatcher:TraitEventDispatcher; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.traceproxy +{ + import org.osmf.elements.*; + import org.osmf.events.*; + import org.osmf.media.*; + import org.osmf.metadata.*; + import org.osmf.traits.*; + + public class TraceListenerProxyElement extends ProxyElement + { + public function TraceListenerProxyElement(wrappedElement:MediaElement) + { + super(wrappedElement); + + dispatcher = new TraitEventDispatcher(); + dispatcher.media = wrappedElement; + + dispatcher.addEventListener(AudioEvent.MUTED_CHANGE, processMutedChange); + dispatcher.addEventListener(AudioEvent.PAN_CHANGE, processPanChange); + dispatcher.addEventListener(AudioEvent.VOLUME_CHANGE, processVolumeChange); + dispatcher.addEventListener(BufferEvent.BUFFER_TIME_CHANGE, processBufferTimeChange); + dispatcher.addEventListener(BufferEvent.BUFFERING_CHANGE, processBufferingChange); + dispatcher.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, processDisplayObjectChange); + dispatcher.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, processMediaSizeChange); + dispatcher.addEventListener(DRMEvent.DRM_STATE_CHANGE, processDRMStateChange); + dispatcher.addEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, processAutoSwitchChange); + dispatcher.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, processNumDynamicStreamsChange); + dispatcher.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, processSwitchingChange); + dispatcher.addEventListener(LoadEvent.BYTES_TOTAL_CHANGE, processBytesTotalChange); + dispatcher.addEventListener(LoadEvent.LOAD_STATE_CHANGE, processLoadStateChange); + dispatcher.addEventListener(PlayEvent.CAN_PAUSE_CHANGE, processCanPauseChange); + dispatcher.addEventListener(PlayEvent.PLAY_STATE_CHANGE, processPlayStateChange); + dispatcher.addEventListener(SeekEvent.SEEKING_CHANGE, processSeekingChange); + dispatcher.addEventListener(TimeEvent.COMPLETE, processComplete); + dispatcher.addEventListener(TimeEvent.DURATION_CHANGE, processDurationChange); + + wrappedElement.addEventListener(MediaElementEvent.TRAIT_ADD, processTraitAdd); + wrappedElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, processTraitRemove); + } + + + // Overrides + // + + private function processAutoSwitchChange(event:DynamicStreamEvent):void + { + trace("autoSwitchChange", event.autoSwitch); + } + + private function processBufferingChange(event:BufferEvent):void + { + trace("bufferingChange", event.buffering); + } + + private function processBufferTimeChange(event:BufferEvent):void + { + trace("bufferTimeChange", event.bufferTime); + } + + private function processComplete(event:TimeEvent):void + { + trace("complete"); + } + + private function processCanPauseChange(event:PlayEvent):void + { + trace("canPauseChange", event.canPause); + } + + private function processDisplayObjectChange(event:DisplayObjectEvent):void + { + trace("displayObjectChange"); + } + + private function processDurationChange(event:TimeEvent):void + { + trace("durationChange", event.time); + } + + private function processLoadStateChange(event:LoadEvent):void + { + trace("loadStateChange", event.loadState); + } + + private function processBytesTotalChange(event:LoadEvent):void + { + trace("bytesTotalChange", event.bytes); + } + + + private function processMediaSizeChange(event:DisplayObjectEvent):void + { + trace("mediaSizeChange", event.newWidth, event.newHeight); + } + + private function processMutedChange(event:AudioEvent):void + { + trace("mutedChange", event.muted); + } + + private function processNumDynamicStreamsChange(event:DynamicStreamEvent):void + { + trace("numDynamicStreamsChange"); + } + + private function processPanChange(event:AudioEvent):void + { + trace("panChange", event.pan); + } + + private function processPlayStateChange(event:PlayEvent):void + { + trace("playStateChange", event.playState); + } + + private function processSeekingChange(event:SeekEvent):void + { + trace("seekingChange", event.seeking, event.time); + } + + private function processSwitchingChange(event:DynamicStreamEvent):void + { + trace("switchingChange", event.switching); + } + + private function processVolumeChange(event:AudioEvent):void + { + trace("volumeChange", event.volume); + } + + private function processDRMStateChange(event:DRMEvent):void + { + trace("drmStateChange", event.drmState); + } + + private function processTraitAdd(event:MediaElementEvent):void + { + trace("Trait Add: " + event.traitType); + } + + private function processTraitRemove(event:MediaElementEvent):void + { + trace("Trait Remove: " + event.traitType); + } + + + private var dispatcher:TraitEventDispatcher; + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/traceproxy/TraceNetLoader.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/traceproxy/TraceNetLoader.as index fc81a2f..c9ec4c7 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/traceproxy/TraceNetLoader.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/examples/traceproxy/TraceNetLoader.as @@ -1,64 +1,64 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.examples.traceproxy -{ - import flash.events.NetStatusEvent; - import flash.net.NetConnection; - import flash.net.NetStream; - - import org.osmf.media.URLResource; - import org.osmf.net.NetClient; - import org.osmf.net.NetLoader; - - /** - * A NetLoader which outputs all NetStatusEvents to the console. - **/ - public class TraceNetLoader extends NetLoader - { - /** - * Constructor. - */ - public function TraceNetLoader() - { - super(); - } - - /** - * @private - **/ - override protected function createNetStream(connection:NetConnection, resource:URLResource):NetStream - { - var ns:NetStream = new NetStream(connection); - ns.client = new NetClient(); - ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStreamNetStatusEvent); - return ns; - } - - // Internals - // - - private function onNetStreamNetStatusEvent(event:NetStatusEvent):void - { - trace("NetStream: " + event.info.code + ": " + event.info.level); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.examples.traceproxy +{ + import flash.events.NetStatusEvent; + import flash.net.NetConnection; + import flash.net.NetStream; + + import org.osmf.media.URLResource; + import org.osmf.net.NetClient; + import org.osmf.net.NetLoader; + + /** + * A NetLoader which outputs all NetStatusEvents to the console. + **/ + public class TraceNetLoader extends NetLoader + { + /** + * Constructor. + */ + public function TraceNetLoader() + { + super(); + } + + /** + * @private + **/ + override protected function createNetStream(connection:NetConnection, resource:URLResource):NetStream + { + var ns:NetStream = new NetStream(connection); + ns.client = new NetClient(); + ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStreamNetStatusEvent); + return ns; + } + + // Internals + // + + private function onNetStreamNetStatusEvent(event:NetStatusEvent):void + { + trace("NetStream: " + event.info.code + ": " + event.info.level); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/view/MainWindow.as b/lib/osmf/samples/ExamplePlayer/src/org/osmf/view/MainWindow.as index 55bfe0a..c6bc9fd 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/view/MainWindow.as +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/view/MainWindow.as @@ -1,424 +1,424 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.view -{ - import flash.events.Event; - import flash.events.MouseEvent; - - import mx.collections.ArrayCollection; - import mx.events.ListEvent; - import mx.events.MenuEvent; - import mx.events.SliderEvent; - - import org.osmf.containers.MediaContainer; - import org.osmf.events.AudioEvent; - import org.osmf.events.BufferEvent; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaErrorEvent; - import org.osmf.events.MediaPlayerCapabilityChangeEvent; - import org.osmf.events.MediaPlayerStateChangeEvent; - import org.osmf.events.TimeEvent; - import org.osmf.examples.AllExamples; - import org.osmf.examples.Category; - import org.osmf.examples.Example; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaPlayer; - import org.osmf.media.MediaPlayerState; - import org.osmf.metadata.MetadataWatcher; - import org.osmf.utils.Version; - - public class MainWindow extends MainWindowLayout - { - // Overrides - // - - override protected function childrenCreated():void - { - super.childrenCreated(); - - // Set up our MediaPlayer. - // - - mediaPlayer = new MediaPlayer(); - mediaPlayer.autoPlay = true; - mediaPlayer.autoRewind = true; - - // Set up our list of examples. - // - - examples = AllExamples.examples; - exampleTree.labelField = "name"; - exampleTree.dataTipField = "name"; - exampleTree.showDataTips = true; - exampleTree.dataProvider = examples; - exampleTree.validateNow(); - exampleTree.expandChildrenOf(examples[0], true); - - // Add UI event handlers. - // - - exampleTree.addEventListener(ListEvent.CHANGE, onExampleTreeSelect); - - buttonPlay.addEventListener(MouseEvent.CLICK, onPlayClick); - buttonPause.addEventListener(MouseEvent.CLICK, onPauseClick); - - panControl.addEventListener(SliderEvent.CHANGE, onPan); - volumeSlider.addEventListener(SliderEvent.CHANGE, onVolume); - muteToggle.addEventListener(MouseEvent.CLICK, onToggleMuteClick); - - seekBar.addEventListener(SliderEvent.CHANGE, onSeek); - seekBar.addEventListener(SliderEvent.THUMB_DRAG, onSeek); - - scaleModeButton.dataProvider = new ArrayCollection([ScaleMode.NONE, ScaleMode.LETTERBOX, ScaleMode.STRETCH, ScaleMode.ZOOM]); - scaleModeButton.addEventListener(MenuEvent.ITEM_CLICK, onScaleModeSelect); - - playOptions.addEventListener(Event.CHANGE, onPlayOptions); - - // Add MediaPlayer event handlers. - // - - mediaPlayer.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, onStateChange); - mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.HAS_AUDIO_CHANGE, onCapabilityChange); - mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_BUFFER_CHANGE, onCapabilityChange); - mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_LOAD_CHANGE, onCapabilityChange); - mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_PLAY_CHANGE, onCapabilityChange); - mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE, onCapabilityChange); - mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.TEMPORAL_CHANGE, onCapabilityChange); - mediaPlayer.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - - mediaPlayer.addEventListener(TimeEvent.DURATION_CHANGE, onDurationChange); - mediaPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, onCurrentTimeChange); - mediaPlayer.addEventListener(AudioEvent.MUTED_CHANGE, onMutedChange); - mediaPlayer.addEventListener(BufferEvent.BUFFERING_CHANGE, onBufferingChange); - mediaPlayer.addEventListener(BufferEvent.BUFFER_TIME_CHANGE, onBufferTimeChange); - mediaPlayer.addEventListener(LoadEvent.BYTES_TOTAL_CHANGE, onBytesTotalChange); - mediaPlayer.addEventListener(LoadEvent.BYTES_LOADED_CHANGE, onBytesLoadedChange); - mediaPlayer.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, onDisplayObjectChange); - - // Set up the container. - // - - mediaContainerUIComponent.container = new MediaContainer(); - - // Sync the UI to the current (empty) state. - // - - updateControls(); - - version.text = "OSMF Version: " + Version.version; - } - - // UI Event Handlers - // - - private function onPlayOptions(event:Event):void - { - mediaPlayer.autoPlay = playOptions.dataProvider[0].autoPlay.@toggled == "true"; - mediaPlayer.autoRewind = playOptions.dataProvider[0].autoRewind.@toggled == "true"; - mediaPlayer.loop = playOptions.dataProvider[0].loop.@toggled == "true"; - } - - private function onPan(event:SliderEvent):void - { - mediaPlayer.audioPan = event.value; - } - - private function onVolume(event:SliderEvent):void - { - mediaPlayer.volume = event.value; - } - - private function onPlayClick(event:MouseEvent):void - { - mediaPlayer.play(); - } - - private function onPauseClick(event:MouseEvent):void - { - mediaPlayer.pause(); - } - - private function onToggleMuteClick(event:MouseEvent):void - { - mediaPlayer.muted = muteToggle.selected; - } - - private function onSeek(event:SliderEvent):void - { - if (mediaPlayer.canSeek) - { - mediaPlayer.seek(event.value); - } - } - - private function onScaleModeSelect(event:MenuEvent):void - { - setScaleMode(event.item.toString()); - } - - private function setScaleMode(scaleMode:String):void - { - scaleModeButton.label = scaleMode; - - if (mediaPlayer.media != null) - { - var layoutMetadata:LayoutMetadata = mediaPlayer.media.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; - layoutMetadata.scaleMode = scaleMode; - } - } - - private function setMediaElement(value:MediaElement):void - { - if (mediaPlayer.media != null) - { - mediaContainerUIComponent.container.removeMediaElement(mediaPlayer.media); - recommendationsWatcher.unwatch(); - } - - if (value != null) - { - // If there's no explicit layout metadata, center the content. - var layoutMetadata:LayoutMetadata = value.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; - if (layoutMetadata == null) - { - layoutMetadata = new LayoutMetadata(); - layoutMetadata.scaleMode = scaleMode; - layoutMetadata.percentHeight = layoutMetadata.percentWidth = 100; - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - value.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); - } - mediaContainerUIComponent.container.addMediaElement(value); - - recommendationsWatcher = new MetadataWatcher(value.metadata, "recommendations", "open", onRecomendationsOpenChange); - recommendationsWatcher.watch(false); - } - - mediaPlayer.media = value; - } - - private function onExampleTreeSelect(event:ListEvent = null):void - { - if (example != null) - { - example.dispose(); - } - - errorIDBox.visible = errorMessageBox.visible = errorDetailBox.visible = false; - errorID.text = errorMessage.text = errorDetail.text = ""; - duration.text = ""; - - if (exampleTree.selectedItem != null && - exampleTree.selectedItem is Example) - { - example = exampleTree.selectedItem as Example; - setMediaElement(example.mediaElement); - exampleDescription.text = example.description; - - disableScaleMode = false; - scaleModeButton.label = scaleMode; - if (example.scaleModeOverride != null) - { - if (example.scaleModeOverride == "disable") - { - disableScaleMode = true; - } - else - { - setScaleMode(example.scaleModeOverride); - } - } - } - else - { - setMediaElement(null); - exampleDescription.text = ""; - disableScaleMode = false; - } - - updateControls(); - } - - // MediaPlayer Event Handlers - // - - private function onStateChange(event:MediaPlayerStateChangeEvent):void - { - stateControls.visible = true; - playerState.text = event.state; - - updateControls(); - } - - private function onCapabilityChange(event:MediaPlayerCapabilityChangeEvent):void - { - updateControls(); - } - - private function onMediaError(event:MediaErrorEvent):void - { - errorIDBox.visible = errorMessageBox.visible = errorDetailBox.visible = true; - - errorID.text = "" + event.error.errorID; - errorMessage.text = event.error.message; - errorDetail.text = event.error.detail; - - updateControls(); - } - - private function onDurationChange(event:TimeEvent):void - { - seekBar.maximum = event.time; - duration.text = "" + Math.round(event.time); - } - - private function onCurrentTimeChange(event:TimeEvent):void - { - if (mediaPlayer.state != MediaPlayerState.BUFFERING) - { - position.text = "" + Math.round(event.time); - - seekBar.value = mediaPlayer.temporal - ? mediaPlayer.currentTime - : 0; - - bufferLength.text = mediaPlayer.canBuffer - ? mediaPlayer.bufferLength.toFixed(1) - : ""; - } - } - - private function onMutedChange(event:AudioEvent):void - { - muteToggle.selected = event.muted; - } - - private function onBufferingChange(event:BufferEvent):void - { - buffering.text = event.buffering ? "true" : "false"; - } - - private function onBufferTimeChange(event:BufferEvent):void - { - bufferTime.text = mediaPlayer.bufferTime.toFixed(1); - } - - private function onBytesTotalChange(event:LoadEvent):void - { - bytesTotal.text = event.bytes.toString(); - } - - private function onBytesLoadedChange(event:LoadEvent):void - { - bytesLoaded.text = event.bytes.toString(); - } - - private function onDisplayObjectChange(event:DisplayObjectEvent):void - { - updateControls(); - } - - private function updateControls():void - { - buttonPlay.visible = mediaPlayer.canPlay; - buttonPause.visible = mediaPlayer.canPlay && mediaPlayer.canPause; - audioTraitControls.visible = mediaPlayer.hasAudio; - timeTraitControls.visible = mediaPlayer.temporal; - bufferTraitControls.visible = mediaPlayer.canBuffer; - loadTraitControls.visible = mediaPlayer.canLoad; - seekBar.enabled = mediaPlayer.canSeek; - scaleModeBox.visible = mediaPlayer.displayObject != null && !disableScaleMode; - - if (mediaPlayer.temporal) - { - seekBar.maximum = mediaPlayer.duration; - duration.text = "" + Math.round(mediaPlayer.duration); - } - else - { - seekBar.maximum = 0; - duration.text = "0"; - } - - if (mediaPlayer.canLoad) - { - bytesTotal.text = "" + mediaPlayer.bytesTotal; - } - else - { - bytesTotal.text = ""; - } - - if (mediaPlayer.canBuffer) - { - bufferTime.text = mediaPlayer.bufferTime.toFixed(1); - bufferLength.text = mediaPlayer.bufferLength.toFixed(1); - } - else - { - bufferTime.text = ""; - bufferLength.text = ""; - } - - if (mediaPlayer.canLoad == false) - { - bytesTotal.text = ""; - bytesLoaded.text = ""; - } - - if (mediaPlayer.hasAudio) - { - muteToggle.selected = mediaPlayer.muted; - volumeSlider.value = mediaPlayer.volume; - panControl.value = mediaPlayer.audioPan; - } - } - - private function onRecomendationsOpenChange(value:String):void - { - for each (var category:Category in examples) - { - for each (var example:Example in category) - { - if (example.name == value) - { - exampleTree.selectedItem = example; - onExampleTreeSelect(); - return; - } - } - } - } - - private var mediaPlayer:MediaPlayer; - private var examples:ArrayCollection; - private var example:Example; - private var recommendationsWatcher:MetadataWatcher; - private var scaleMode:String = ScaleMode.NONE; - private var disableScaleMode:Boolean = false; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.view +{ + import flash.events.Event; + import flash.events.MouseEvent; + + import mx.collections.ArrayCollection; + import mx.events.ListEvent; + import mx.events.MenuEvent; + import mx.events.SliderEvent; + + import org.osmf.containers.MediaContainer; + import org.osmf.events.AudioEvent; + import org.osmf.events.BufferEvent; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaErrorEvent; + import org.osmf.events.MediaPlayerCapabilityChangeEvent; + import org.osmf.events.MediaPlayerStateChangeEvent; + import org.osmf.events.TimeEvent; + import org.osmf.examples.AllExamples; + import org.osmf.examples.Category; + import org.osmf.examples.Example; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaPlayer; + import org.osmf.media.MediaPlayerState; + import org.osmf.metadata.MetadataWatcher; + import org.osmf.utils.Version; + + public class MainWindow extends MainWindowLayout + { + // Overrides + // + + override protected function childrenCreated():void + { + super.childrenCreated(); + + // Set up our MediaPlayer. + // + + mediaPlayer = new MediaPlayer(); + mediaPlayer.autoPlay = true; + mediaPlayer.autoRewind = true; + + // Set up our list of examples. + // + + examples = AllExamples.examples; + exampleTree.labelField = "name"; + exampleTree.dataTipField = "name"; + exampleTree.showDataTips = true; + exampleTree.dataProvider = examples; + exampleTree.validateNow(); + exampleTree.expandChildrenOf(examples[0], true); + + // Add UI event handlers. + // + + exampleTree.addEventListener(ListEvent.CHANGE, onExampleTreeSelect); + + buttonPlay.addEventListener(MouseEvent.CLICK, onPlayClick); + buttonPause.addEventListener(MouseEvent.CLICK, onPauseClick); + + panControl.addEventListener(SliderEvent.CHANGE, onPan); + volumeSlider.addEventListener(SliderEvent.CHANGE, onVolume); + muteToggle.addEventListener(MouseEvent.CLICK, onToggleMuteClick); + + seekBar.addEventListener(SliderEvent.CHANGE, onSeek); + seekBar.addEventListener(SliderEvent.THUMB_DRAG, onSeek); + + scaleModeButton.dataProvider = new ArrayCollection([ScaleMode.NONE, ScaleMode.LETTERBOX, ScaleMode.STRETCH, ScaleMode.ZOOM]); + scaleModeButton.addEventListener(MenuEvent.ITEM_CLICK, onScaleModeSelect); + + playOptions.addEventListener(Event.CHANGE, onPlayOptions); + + // Add MediaPlayer event handlers. + // + + mediaPlayer.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, onStateChange); + mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.HAS_AUDIO_CHANGE, onCapabilityChange); + mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_BUFFER_CHANGE, onCapabilityChange); + mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_LOAD_CHANGE, onCapabilityChange); + mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_PLAY_CHANGE, onCapabilityChange); + mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE, onCapabilityChange); + mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.TEMPORAL_CHANGE, onCapabilityChange); + mediaPlayer.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + + mediaPlayer.addEventListener(TimeEvent.DURATION_CHANGE, onDurationChange); + mediaPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, onCurrentTimeChange); + mediaPlayer.addEventListener(AudioEvent.MUTED_CHANGE, onMutedChange); + mediaPlayer.addEventListener(BufferEvent.BUFFERING_CHANGE, onBufferingChange); + mediaPlayer.addEventListener(BufferEvent.BUFFER_TIME_CHANGE, onBufferTimeChange); + mediaPlayer.addEventListener(LoadEvent.BYTES_TOTAL_CHANGE, onBytesTotalChange); + mediaPlayer.addEventListener(LoadEvent.BYTES_LOADED_CHANGE, onBytesLoadedChange); + mediaPlayer.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, onDisplayObjectChange); + + // Set up the container. + // + + mediaContainerUIComponent.container = new MediaContainer(); + + // Sync the UI to the current (empty) state. + // + + updateControls(); + + version.text = "OSMF Version: " + Version.version; + } + + // UI Event Handlers + // + + private function onPlayOptions(event:Event):void + { + mediaPlayer.autoPlay = playOptions.dataProvider[0].autoPlay.@toggled == "true"; + mediaPlayer.autoRewind = playOptions.dataProvider[0].autoRewind.@toggled == "true"; + mediaPlayer.loop = playOptions.dataProvider[0].loop.@toggled == "true"; + } + + private function onPan(event:SliderEvent):void + { + mediaPlayer.audioPan = event.value; + } + + private function onVolume(event:SliderEvent):void + { + mediaPlayer.volume = event.value; + } + + private function onPlayClick(event:MouseEvent):void + { + mediaPlayer.play(); + } + + private function onPauseClick(event:MouseEvent):void + { + mediaPlayer.pause(); + } + + private function onToggleMuteClick(event:MouseEvent):void + { + mediaPlayer.muted = muteToggle.selected; + } + + private function onSeek(event:SliderEvent):void + { + if (mediaPlayer.canSeek) + { + mediaPlayer.seek(event.value); + } + } + + private function onScaleModeSelect(event:MenuEvent):void + { + setScaleMode(event.item.toString()); + } + + private function setScaleMode(scaleMode:String):void + { + scaleModeButton.label = scaleMode; + + if (mediaPlayer.media != null) + { + var layoutMetadata:LayoutMetadata = mediaPlayer.media.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; + layoutMetadata.scaleMode = scaleMode; + } + } + + private function setMediaElement(value:MediaElement):void + { + if (mediaPlayer.media != null) + { + mediaContainerUIComponent.container.removeMediaElement(mediaPlayer.media); + recommendationsWatcher.unwatch(); + } + + if (value != null) + { + // If there's no explicit layout metadata, center the content. + var layoutMetadata:LayoutMetadata = value.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; + if (layoutMetadata == null) + { + layoutMetadata = new LayoutMetadata(); + layoutMetadata.scaleMode = scaleMode; + layoutMetadata.percentHeight = layoutMetadata.percentWidth = 100; + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + value.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); + } + mediaContainerUIComponent.container.addMediaElement(value); + + recommendationsWatcher = new MetadataWatcher(value.metadata, "recommendations", "open", onRecomendationsOpenChange); + recommendationsWatcher.watch(false); + } + + mediaPlayer.media = value; + } + + private function onExampleTreeSelect(event:ListEvent = null):void + { + if (example != null) + { + example.dispose(); + } + + errorIDBox.visible = errorMessageBox.visible = errorDetailBox.visible = false; + errorID.text = errorMessage.text = errorDetail.text = ""; + duration.text = ""; + + if (exampleTree.selectedItem != null && + exampleTree.selectedItem is Example) + { + example = exampleTree.selectedItem as Example; + setMediaElement(example.mediaElement); + exampleDescription.text = example.description; + + disableScaleMode = false; + scaleModeButton.label = scaleMode; + if (example.scaleModeOverride != null) + { + if (example.scaleModeOverride == "disable") + { + disableScaleMode = true; + } + else + { + setScaleMode(example.scaleModeOverride); + } + } + } + else + { + setMediaElement(null); + exampleDescription.text = ""; + disableScaleMode = false; + } + + updateControls(); + } + + // MediaPlayer Event Handlers + // + + private function onStateChange(event:MediaPlayerStateChangeEvent):void + { + stateControls.visible = true; + playerState.text = event.state; + + updateControls(); + } + + private function onCapabilityChange(event:MediaPlayerCapabilityChangeEvent):void + { + updateControls(); + } + + private function onMediaError(event:MediaErrorEvent):void + { + errorIDBox.visible = errorMessageBox.visible = errorDetailBox.visible = true; + + errorID.text = "" + event.error.errorID; + errorMessage.text = event.error.message; + errorDetail.text = event.error.detail; + + updateControls(); + } + + private function onDurationChange(event:TimeEvent):void + { + seekBar.maximum = event.time; + duration.text = "" + Math.round(event.time); + } + + private function onCurrentTimeChange(event:TimeEvent):void + { + if (mediaPlayer.state != MediaPlayerState.BUFFERING) + { + position.text = "" + Math.round(event.time); + + seekBar.value = mediaPlayer.temporal + ? mediaPlayer.currentTime + : 0; + + bufferLength.text = mediaPlayer.canBuffer + ? mediaPlayer.bufferLength.toFixed(1) + : ""; + } + } + + private function onMutedChange(event:AudioEvent):void + { + muteToggle.selected = event.muted; + } + + private function onBufferingChange(event:BufferEvent):void + { + buffering.text = event.buffering ? "true" : "false"; + } + + private function onBufferTimeChange(event:BufferEvent):void + { + bufferTime.text = mediaPlayer.bufferTime.toFixed(1); + } + + private function onBytesTotalChange(event:LoadEvent):void + { + bytesTotal.text = event.bytes.toString(); + } + + private function onBytesLoadedChange(event:LoadEvent):void + { + bytesLoaded.text = event.bytes.toString(); + } + + private function onDisplayObjectChange(event:DisplayObjectEvent):void + { + updateControls(); + } + + private function updateControls():void + { + buttonPlay.visible = mediaPlayer.canPlay; + buttonPause.visible = mediaPlayer.canPlay && mediaPlayer.canPause; + audioTraitControls.visible = mediaPlayer.hasAudio; + timeTraitControls.visible = mediaPlayer.temporal; + bufferTraitControls.visible = mediaPlayer.canBuffer; + loadTraitControls.visible = mediaPlayer.canLoad; + seekBar.enabled = mediaPlayer.canSeek; + scaleModeBox.visible = mediaPlayer.displayObject != null && !disableScaleMode; + + if (mediaPlayer.temporal) + { + seekBar.maximum = mediaPlayer.duration; + duration.text = "" + Math.round(mediaPlayer.duration); + } + else + { + seekBar.maximum = 0; + duration.text = "0"; + } + + if (mediaPlayer.canLoad) + { + bytesTotal.text = "" + mediaPlayer.bytesTotal; + } + else + { + bytesTotal.text = ""; + } + + if (mediaPlayer.canBuffer) + { + bufferTime.text = mediaPlayer.bufferTime.toFixed(1); + bufferLength.text = mediaPlayer.bufferLength.toFixed(1); + } + else + { + bufferTime.text = ""; + bufferLength.text = ""; + } + + if (mediaPlayer.canLoad == false) + { + bytesTotal.text = ""; + bytesLoaded.text = ""; + } + + if (mediaPlayer.hasAudio) + { + muteToggle.selected = mediaPlayer.muted; + volumeSlider.value = mediaPlayer.volume; + panControl.value = mediaPlayer.audioPan; + } + } + + private function onRecomendationsOpenChange(value:String):void + { + for each (var category:Category in examples) + { + for each (var example:Example in category) + { + if (example.name == value) + { + exampleTree.selectedItem = example; + onExampleTreeSelect(); + return; + } + } + } + } + + private var mediaPlayer:MediaPlayer; + private var examples:ArrayCollection; + private var example:Example; + private var recommendationsWatcher:MetadataWatcher; + private var scaleMode:String = ScaleMode.NONE; + private var disableScaleMode:Boolean = false; + } +} diff --git a/lib/osmf/samples/ExamplePlayer/src/org/osmf/view/MainWindowLayout.mxml b/lib/osmf/samples/ExamplePlayer/src/org/osmf/view/MainWindowLayout.mxml index 6e5db00..ec0ecc1 100644 --- a/lib/osmf/samples/ExamplePlayer/src/org/osmf/view/MainWindowLayout.mxml +++ b/lib/osmf/samples/ExamplePlayer/src/org/osmf/view/MainWindowLayout.mxml @@ -1,401 +1,401 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {[new DropShadowFilter(1.5,45,0,1.0,2.5,2.5,2)]} - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {[new DropShadowFilter(1.5,45,0,1.0,2.5,2.5,2)]} + + + + diff --git a/lib/osmf/samples/HTMLMediaContainerSample/.actionScriptProperties b/lib/osmf/samples/HTMLMediaContainerSample/.actionScriptProperties index 9d53232..9e74da3 100644 --- a/lib/osmf/samples/HTMLMediaContainerSample/.actionScriptProperties +++ b/lib/osmf/samples/HTMLMediaContainerSample/.actionScriptProperties @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/HTMLMediaContainerSample/html-template/AC_OETags.js b/lib/osmf/samples/HTMLMediaContainerSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/HTMLMediaContainerSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/HTMLMediaContainerSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/HTMLMediaContainerSample/html-template/history/historyFrame.html b/lib/osmf/samples/HTMLMediaContainerSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/HTMLMediaContainerSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/HTMLMediaContainerSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/HTMLMediaContainerSample/html-template/index.template.html b/lib/osmf/samples/HTMLMediaContainerSample/html-template/index.template.html index de28d57..f9cf52f 100644 --- a/lib/osmf/samples/HTMLMediaContainerSample/html-template/index.template.html +++ b/lib/osmf/samples/HTMLMediaContainerSample/html-template/index.template.html @@ -1,273 +1,273 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - -
      - banner -
      - - -
      - banner - banner -
      - + + + + + + + + + + + + +${title} + + + + + + + + + + + +
      + banner +
      + + +
      + banner + banner +
      + \ No newline at end of file diff --git a/lib/osmf/samples/HTMLMediaContainerSample/readme.txt b/lib/osmf/samples/HTMLMediaContainerSample/readme.txt index 2c6e176..0446c9c 100644 --- a/lib/osmf/samples/HTMLMediaContainerSample/readme.txt +++ b/lib/osmf/samples/HTMLMediaContainerSample/readme.txt @@ -1,35 +1,35 @@ -Sample Application: HTMLMediaContainer - -A. Overview - -This sample application demonstrates part of the framework's container feature, that allows media -elements to be contained. - -The HTMLMediaContainer class implements the IMediaContainer interface. On initializing, the object -reaches out to the HTML document that is hosting the Flash application using Flash's external -interface feature. A JavaScript API gets added to the HTML element that allows elements in -JavaScript to be recognized as media elements by the Flash application. - -This sample demonstrates the playback of a video in Flash, in parallel with a series of banner -image that get loaded and displayed from HTML. The composition as a whole is managed from -Flash (see HTMLMediaContainerSample.as), whereas the usage of the JavaScript API can be found in the -HTML code (see html-template/index.template.html). - -B. Installation Instructions (Flex Builder) - -1. Unzip/copy the HTMLMediaContainerSample project into your Flex Builder workspace folder. -2. In Flex Builder, go to the File menu and select "Import". -3. Select "General", then "Existing Projects into Workspace", and click "Next". -4. Choose "Select root directory" and "Browse". -5. Browse to your Flex Builder workspace folder. -6. Select the checkbox next to "HTMLMediaContainerSample", and click "Finish". This will import the project. -7. Build the project. -8. Launch the application from the Run menu. - -Note that the sample loads assets from the web, so please make sure to be connected to the -internet when trying them out. - -C. Usage Instructions - -On running the sample, clicking the banner that shows above the video content will result in +Sample Application: HTMLMediaContainer + +A. Overview + +This sample application demonstrates part of the framework's container feature, that allows media +elements to be contained. + +The HTMLMediaContainer class implements the IMediaContainer interface. On initializing, the object +reaches out to the HTML document that is hosting the Flash application using Flash's external +interface feature. A JavaScript API gets added to the HTML element that allows elements in +JavaScript to be recognized as media elements by the Flash application. + +This sample demonstrates the playback of a video in Flash, in parallel with a series of banner +image that get loaded and displayed from HTML. The composition as a whole is managed from +Flash (see HTMLMediaContainerSample.as), whereas the usage of the JavaScript API can be found in the +HTML code (see html-template/index.template.html). + +B. Installation Instructions (Flex Builder) + +1. Unzip/copy the HTMLMediaContainerSample project into your Flex Builder workspace folder. +2. In Flex Builder, go to the File menu and select "Import". +3. Select "General", then "Existing Projects into Workspace", and click "Next". +4. Choose "Select root directory" and "Browse". +5. Browse to your Flex Builder workspace folder. +6. Select the checkbox next to "HTMLMediaContainerSample", and click "Finish". This will import the project. +7. Build the project. +8. Launch the application from the Run menu. + +Note that the sample loads assets from the web, so please make sure to be connected to the +internet when trying them out. + +C. Usage Instructions + +On running the sample, clicking the banner that shows above the video content will result in the composition as a whole being paused. Clicking the banner once more will resume playback. \ No newline at end of file diff --git a/lib/osmf/samples/HTMLMediaContainerSample/src/HTMLMediaContainerSample.as b/lib/osmf/samples/HTMLMediaContainerSample/src/HTMLMediaContainerSample.as index ac1bf79..da4fa50 100644 --- a/lib/osmf/samples/HTMLMediaContainerSample/src/HTMLMediaContainerSample.as +++ b/lib/osmf/samples/HTMLMediaContainerSample/src/HTMLMediaContainerSample.as @@ -1,156 +1,156 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import org.osmf.containers.HTMLMediaContainer; - import org.osmf.containers.MediaContainer; - import org.osmf.elements.HTMLElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.SerialElement; - import org.osmf.elements.VideoElement; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - [SWF(backgroundColor='#333333', frameRate='30', width='640', height='358')] - public class HTMLMediaContainerSample extends MediaContainer - { - public function HTMLMediaContainerSample() - { - runSample1(); - //runSample2(); --> uncomment to run sample 2 (and comment out the line above). - } - - /** - * Sample 1 demonstrates how a banner area in HTML can be controlled from - * the framework using composition: - * - * A parallel element gets defined that holds a video element, and a serial - * element. The serial element contains three HTMLElements that reference the - * URLs to banner images. The serial element gets assigned to an HTMLContainer - * instance. - * - * On the JavaScript side (see [project root]/html-template/index.template.html) - * the HTMLElements have a load, play- and time trait implemented. This way, each - * of the three banner images assigned will show for 5 seconds. After the last - * image was shown, it gets removed. - */ - private function runSample1():void - { - var htmlContainer:HTMLMediaContainer = new HTMLMediaContainer("bannerContainer"); - - var rootElement:ParallelElement = new ParallelElement(); - - var banners:SerialElement = new SerialElement(); - rootElement.addChild(banners); - - var banner1:HTMLElement = new HTMLElement(); - banner1.resource = new URLResource(BANNER_1); - banners.addChild(banner1); - - var banner2:HTMLElement = new HTMLElement(); - banner2.resource = new URLResource(BANNER_2); - banners.addChild(banner2); - - var banner3:HTMLElement = new HTMLElement(); - banner3.resource = new URLResource(BANNER_3); - banners.addChild(banner3); - - var video:VideoElement = constructVideo(REMOTE_PROGRESSIVE); - rootElement.addChild(video); - - addMediaElement(rootElement); - htmlContainer.addMediaElement(banner1); - htmlContainer.addMediaElement(banner2); - htmlContainer.addMediaElement(banner3); - - var mediaPlayer:MediaPlayer = new MediaPlayer(); - mediaPlayer.autoPlay = true; - mediaPlayer.media = rootElement; - } - - /** - * Sample 2 demonstrates how multiple HTMLContainer instances can be used - * in parallel. - * - * A parallel element gets defined that holds a video element, and three - * HTMLElement instance. Each of the HTMLElements gets assigned to an - * individual HTMLContainer instance. - * - * On the JavaScript side (see [project root]/html-template/index.template.html), - * the HTMLElements have a load trait implemented. This results in all of - * the banners showing in parallel at different locations (defined in HTML as - * image tags that the JavaScript load trait implementation interacts with). - */ - private function runSample2():void - { - var htmlContainer1:HTMLMediaContainer = new HTMLMediaContainer("bannerContainer1"); - var htmlContainer2:HTMLMediaContainer = new HTMLMediaContainer("bannerContainer2"); - var htmlContainer3:HTMLMediaContainer = new HTMLMediaContainer("bannerContainer3"); - - var rootElement:ParallelElement = new ParallelElement(); - - var banner1:HTMLElement = new HTMLElement(); - banner1.resource = new URLResource(BANNER_1); - rootElement.addChild(banner1); - - var banner2:HTMLElement = new HTMLElement(); - banner2.resource = new URLResource(BANNER_2); - rootElement.addChild(banner2); - - var banner3:HTMLElement = new HTMLElement(); - banner3.resource = new URLResource(BANNER_3); - rootElement.addChild(banner3); - - var video:VideoElement = constructVideo(REMOTE_PROGRESSIVE); - rootElement.addChild(video); - - addMediaElement(rootElement); - - htmlContainer1.addMediaElement(banner1); - htmlContainer2.addMediaElement(banner2); - htmlContainer3.addMediaElement(banner3); - - var mediaPlayer:MediaPlayer = new MediaPlayer(); - mediaPlayer.autoPlay = true; - mediaPlayer.media = rootElement; - } - - private function constructVideo(url:String):VideoElement - { - return new VideoElement - ( new URLResource(url) - ); - } - - private static const REMOTE_PROGRESSIVE:String - = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; - - private static const BANNER_1:String - = "http://www.iab.net/media/image/468x60.gif"; - - private static const BANNER_2:String - = "http://www.iab.net/media/image/234x60.gif"; - - private static const BANNER_3:String - = "http://www.iab.net/media/image/120x60.gif"; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import org.osmf.containers.HTMLMediaContainer; + import org.osmf.containers.MediaContainer; + import org.osmf.elements.HTMLElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.SerialElement; + import org.osmf.elements.VideoElement; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + [SWF(backgroundColor='#333333', frameRate='30', width='640', height='358')] + public class HTMLMediaContainerSample extends MediaContainer + { + public function HTMLMediaContainerSample() + { + runSample1(); + //runSample2(); --> uncomment to run sample 2 (and comment out the line above). + } + + /** + * Sample 1 demonstrates how a banner area in HTML can be controlled from + * the framework using composition: + * + * A parallel element gets defined that holds a video element, and a serial + * element. The serial element contains three HTMLElements that reference the + * URLs to banner images. The serial element gets assigned to an HTMLContainer + * instance. + * + * On the JavaScript side (see [project root]/html-template/index.template.html) + * the HTMLElements have a load, play- and time trait implemented. This way, each + * of the three banner images assigned will show for 5 seconds. After the last + * image was shown, it gets removed. + */ + private function runSample1():void + { + var htmlContainer:HTMLMediaContainer = new HTMLMediaContainer("bannerContainer"); + + var rootElement:ParallelElement = new ParallelElement(); + + var banners:SerialElement = new SerialElement(); + rootElement.addChild(banners); + + var banner1:HTMLElement = new HTMLElement(); + banner1.resource = new URLResource(BANNER_1); + banners.addChild(banner1); + + var banner2:HTMLElement = new HTMLElement(); + banner2.resource = new URLResource(BANNER_2); + banners.addChild(banner2); + + var banner3:HTMLElement = new HTMLElement(); + banner3.resource = new URLResource(BANNER_3); + banners.addChild(banner3); + + var video:VideoElement = constructVideo(REMOTE_PROGRESSIVE); + rootElement.addChild(video); + + addMediaElement(rootElement); + htmlContainer.addMediaElement(banner1); + htmlContainer.addMediaElement(banner2); + htmlContainer.addMediaElement(banner3); + + var mediaPlayer:MediaPlayer = new MediaPlayer(); + mediaPlayer.autoPlay = true; + mediaPlayer.media = rootElement; + } + + /** + * Sample 2 demonstrates how multiple HTMLContainer instances can be used + * in parallel. + * + * A parallel element gets defined that holds a video element, and three + * HTMLElement instance. Each of the HTMLElements gets assigned to an + * individual HTMLContainer instance. + * + * On the JavaScript side (see [project root]/html-template/index.template.html), + * the HTMLElements have a load trait implemented. This results in all of + * the banners showing in parallel at different locations (defined in HTML as + * image tags that the JavaScript load trait implementation interacts with). + */ + private function runSample2():void + { + var htmlContainer1:HTMLMediaContainer = new HTMLMediaContainer("bannerContainer1"); + var htmlContainer2:HTMLMediaContainer = new HTMLMediaContainer("bannerContainer2"); + var htmlContainer3:HTMLMediaContainer = new HTMLMediaContainer("bannerContainer3"); + + var rootElement:ParallelElement = new ParallelElement(); + + var banner1:HTMLElement = new HTMLElement(); + banner1.resource = new URLResource(BANNER_1); + rootElement.addChild(banner1); + + var banner2:HTMLElement = new HTMLElement(); + banner2.resource = new URLResource(BANNER_2); + rootElement.addChild(banner2); + + var banner3:HTMLElement = new HTMLElement(); + banner3.resource = new URLResource(BANNER_3); + rootElement.addChild(banner3); + + var video:VideoElement = constructVideo(REMOTE_PROGRESSIVE); + rootElement.addChild(video); + + addMediaElement(rootElement); + + htmlContainer1.addMediaElement(banner1); + htmlContainer2.addMediaElement(banner2); + htmlContainer3.addMediaElement(banner3); + + var mediaPlayer:MediaPlayer = new MediaPlayer(); + mediaPlayer.autoPlay = true; + mediaPlayer.media = rootElement; + } + + private function constructVideo(url:String):VideoElement + { + return new VideoElement + ( new URLResource(url) + ); + } + + private static const REMOTE_PROGRESSIVE:String + = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; + + private static const BANNER_1:String + = "http://www.iab.net/media/image/468x60.gif"; + + private static const BANNER_2:String + = "http://www.iab.net/media/image/234x60.gif"; + + private static const BANNER_3:String + = "http://www.iab.net/media/image/120x60.gif"; + } +} diff --git a/lib/osmf/samples/HelloWorldJavaScriptSample/.actionScriptProperties b/lib/osmf/samples/HelloWorldJavaScriptSample/.actionScriptProperties index fb940cf..a654a51 100644 --- a/lib/osmf/samples/HelloWorldJavaScriptSample/.actionScriptProperties +++ b/lib/osmf/samples/HelloWorldJavaScriptSample/.actionScriptProperties @@ -1,40 +1,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/HelloWorldSample/.actionScriptProperties b/lib/osmf/samples/HelloWorldSample/.actionScriptProperties index 2594887..d521b79 100644 --- a/lib/osmf/samples/HelloWorldSample/.actionScriptProperties +++ b/lib/osmf/samples/HelloWorldSample/.actionScriptProperties @@ -1,39 +1,39 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/HelloWorldSample/html-template/AC_OETags.js b/lib/osmf/samples/HelloWorldSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/HelloWorldSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/HelloWorldSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/HelloWorldSample/html-template/history/historyFrame.html b/lib/osmf/samples/HelloWorldSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/HelloWorldSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/HelloWorldSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/HelloWorldSample/html-template/index.template.html b/lib/osmf/samples/HelloWorldSample/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/HelloWorldSample/html-template/index.template.html +++ b/lib/osmf/samples/HelloWorldSample/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/HelloWorldSample/readme.txt b/lib/osmf/samples/HelloWorldSample/readme.txt index 4a45477..ba00163 100644 --- a/lib/osmf/samples/HelloWorldSample/readme.txt +++ b/lib/osmf/samples/HelloWorldSample/readme.txt @@ -1,38 +1,38 @@ -Sample Application: Hello World - -A. Overview - -This sample application demonstrates the simplest possible application that can be built with -the OSMF (see HelloWorld.as). The sample is gradually extended, to demonstrate additional framework -features: - -HelloWorld.as: Uses MediaPlayerSprite to play a video. -HelloWorld2.as: Uses MediaPlayer and MediaContainer instead of MediaPlayerSprite. -HelloWorld3.as: Same as HelloWorld2, but centers the content. -HelloWorld4.as: Uses MediaElement and DisplayObjectTrait, rather than MediaPlayerSprite. -HelloWorld5.as: Uses MediaPlayer and DisplayObjectTrait, rather than MediaContainer. -HelloWorld6.as: Uses LightweightVideoElement instead of VideoElement to minimize player size. -HelloWorld7.as: Plays a video, then shows a SWF, then plays another video. - -For more detail on this sample, please refer to: -http://blogs.adobe.com/osmf/2009/09/building_a_helloworld_app_with_osmf.html - -B. Installation Instructions (Flex Builder) - -1. Unzip/copy the HelloWorld project into your Flex Builder workspace folder. -2. In Flex Builder, go to the File menu and select "Import". -3. Select "General", then "Existing Projects into Workspace", and click "Next". -4. Choose "Select root directory" and "Browse". -5. Browse to your Flex Builder workspace folder. -6. Select the checkbox next to "HelloWorld", and click "Finish". This will import the project. -7. Build the project. -8. Launch the application from the Run menu. - -Note that the sample loads assets from the web, so please make sure to be connected to the -internet when trying them out. - -C. Usage Instructions - -To switch from HelloWorld.as to HelloWorld2.as, right-click HelloWorld2.as in the Flex -Navigator panel. Select 'Set as Default Application', and launch the application from the +Sample Application: Hello World + +A. Overview + +This sample application demonstrates the simplest possible application that can be built with +the OSMF (see HelloWorld.as). The sample is gradually extended, to demonstrate additional framework +features: + +HelloWorld.as: Uses MediaPlayerSprite to play a video. +HelloWorld2.as: Uses MediaPlayer and MediaContainer instead of MediaPlayerSprite. +HelloWorld3.as: Same as HelloWorld2, but centers the content. +HelloWorld4.as: Uses MediaElement and DisplayObjectTrait, rather than MediaPlayerSprite. +HelloWorld5.as: Uses MediaPlayer and DisplayObjectTrait, rather than MediaContainer. +HelloWorld6.as: Uses LightweightVideoElement instead of VideoElement to minimize player size. +HelloWorld7.as: Plays a video, then shows a SWF, then plays another video. + +For more detail on this sample, please refer to: +http://blogs.adobe.com/osmf/2009/09/building_a_helloworld_app_with_osmf.html + +B. Installation Instructions (Flex Builder) + +1. Unzip/copy the HelloWorld project into your Flex Builder workspace folder. +2. In Flex Builder, go to the File menu and select "Import". +3. Select "General", then "Existing Projects into Workspace", and click "Next". +4. Choose "Select root directory" and "Browse". +5. Browse to your Flex Builder workspace folder. +6. Select the checkbox next to "HelloWorld", and click "Finish". This will import the project. +7. Build the project. +8. Launch the application from the Run menu. + +Note that the sample loads assets from the web, so please make sure to be connected to the +internet when trying them out. + +C. Usage Instructions + +To switch from HelloWorld.as to HelloWorld2.as, right-click HelloWorld2.as in the Flex +Navigator panel. Select 'Set as Default Application', and launch the application from the Run menu. \ No newline at end of file diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld.as index 977d12a..b8f26c6 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld.as @@ -1,50 +1,50 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - - import org.osmf.media.MediaPlayerSprite; - import org.osmf.media.URLResource; - - /** - * The simplest OSMF application possible. - * - * The metadata sets the SWF size to match that of the video. - **/ - [SWF(width="640", height="352")] - public class HelloWorld extends Sprite - { - public function HelloWorld() - { - // Create the container class that displays the media. - var sprite:MediaPlayerSprite = new MediaPlayerSprite(); - addChild(sprite); - - // Assign the resource to play. This will generate the - // appropriate MediaElement and pass it to the MediaPlayer. - // Because the MediaPlayer is set to auto-play by default, - // playback begins immediately. - sprite.resource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); - } - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + + import org.osmf.media.MediaPlayerSprite; + import org.osmf.media.URLResource; + + /** + * The simplest OSMF application possible. + * + * The metadata sets the SWF size to match that of the video. + **/ + [SWF(width="640", height="352")] + public class HelloWorld extends Sprite + { + public function HelloWorld() + { + // Create the container class that displays the media. + var sprite:MediaPlayerSprite = new MediaPlayerSprite(); + addChild(sprite); + + // Assign the resource to play. This will generate the + // appropriate MediaElement and pass it to the MediaPlayer. + // Because the MediaPlayer is set to auto-play by default, + // playback begins immediately. + sprite.resource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); + } + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld2.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld2.as index 94dc800..eac1bd5 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld2.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld2.as @@ -1,57 +1,57 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.VideoElement; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - /** - * Variation on HelloWorld, using MediaPlayer + MediaContainer - * rather than MediaPlayerSprite. - **/ - [SWF(width="640", height="352")] - public class HelloWorld2 extends Sprite - { - public function HelloWorld2() - { - // Create the container class that displays the media. - var container:MediaContainer = new MediaContainer(); - addChild(container); - - // Create the resource to play. - var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); - - // Create the MediaElement and add it to our container class. - var videoElement:VideoElement = new VideoElement(resource); - container.addMediaElement(videoElement); - - // Set the MediaElement on a MediaPlayer. Because autoPlay - // defaults to true, playback begins immediately. - var mediaPlayer:MediaPlayer = new MediaPlayer(); - mediaPlayer.media = videoElement; - } - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.VideoElement; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + /** + * Variation on HelloWorld, using MediaPlayer + MediaContainer + * rather than MediaPlayerSprite. + **/ + [SWF(width="640", height="352")] + public class HelloWorld2 extends Sprite + { + public function HelloWorld2() + { + // Create the container class that displays the media. + var container:MediaContainer = new MediaContainer(); + addChild(container); + + // Create the resource to play. + var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); + + // Create the MediaElement and add it to our container class. + var videoElement:VideoElement = new VideoElement(resource); + container.addMediaElement(videoElement); + + // Set the MediaElement on a MediaPlayer. Because autoPlay + // defaults to true, playback begins immediately. + var mediaPlayer:MediaPlayer = new MediaPlayer(); + mediaPlayer.media = videoElement; + } + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld3.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld3.as index fc0a5d0..734c66e 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld3.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld3.as @@ -1,85 +1,85 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - import flash.display.StageAlign; - import flash.display.StageScaleMode; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.VideoElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - /** - * A simple OSMF application, building on HelloWorld2.as. - * - * Rather than specify explicit dimensions for the SWF, we now - * maximize the SWF and center the content. - **/ - [SWF(backgroundColor="0x333333")] - public class HelloWorld3 extends Sprite - { - public function HelloWorld3() - { - stage.scaleMode = StageScaleMode.NO_SCALE; - stage.align = StageAlign.TOP_LEFT; - - // Create the container class that displays the media. - var container:MediaContainer = new MediaContainer(); - addChild(container); - - // Set the container's size to match that of the stage, and - // prevent the content from being scaled. - container.width = stage.stageWidth; - container.height = stage.stageHeight; - container.layoutMetadata.scaleMode = ScaleMode.NONE; - - // Create the resource to play. - var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); - - // Create the MediaElement. - var videoElement:VideoElement = new VideoElement(resource); - - // Assign some layout metadata to the MediaElement. This will cause - // it to be centered in the container, with no scaling of content. - var layoutMetadata:LayoutMetadata = new LayoutMetadata(); - layoutMetadata.scaleMode = ScaleMode.NONE; - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - videoElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); - - // Add the MediaElement to our container class, so that it gets - // displayed. - container.addMediaElement(videoElement); - - // Set the MediaElement on a MediaPlayer. Because autoPlay - // defaults to true, playback begins immediately. - var mediaPlayer:MediaPlayer = new MediaPlayer(); - mediaPlayer.media = videoElement; - } - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.VideoElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + /** + * A simple OSMF application, building on HelloWorld2.as. + * + * Rather than specify explicit dimensions for the SWF, we now + * maximize the SWF and center the content. + **/ + [SWF(backgroundColor="0x333333")] + public class HelloWorld3 extends Sprite + { + public function HelloWorld3() + { + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + + // Create the container class that displays the media. + var container:MediaContainer = new MediaContainer(); + addChild(container); + + // Set the container's size to match that of the stage, and + // prevent the content from being scaled. + container.width = stage.stageWidth; + container.height = stage.stageHeight; + container.layoutMetadata.scaleMode = ScaleMode.NONE; + + // Create the resource to play. + var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); + + // Create the MediaElement. + var videoElement:VideoElement = new VideoElement(resource); + + // Assign some layout metadata to the MediaElement. This will cause + // it to be centered in the container, with no scaling of content. + var layoutMetadata:LayoutMetadata = new LayoutMetadata(); + layoutMetadata.scaleMode = ScaleMode.NONE; + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + videoElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); + + // Add the MediaElement to our container class, so that it gets + // displayed. + container.addMediaElement(videoElement); + + // Set the MediaElement on a MediaPlayer. Because autoPlay + // defaults to true, playback begins immediately. + var mediaPlayer:MediaPlayer = new MediaPlayer(); + mediaPlayer.media = videoElement; + } + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld4.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld4.as index 26213b7..fc73c81 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld4.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld4.as @@ -1,69 +1,69 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - - import org.osmf.elements.VideoElement; - import org.osmf.events.LoadEvent; - import org.osmf.media.URLResource; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - - /** - * Variation on HelloWorld, using MediaElement + DisplayObjectTrait - * rather than MediaPlayerSprite. - **/ - [SWF(width="640", height="352")] - public class HelloWorld4 extends Sprite - { - public function HelloWorld4() - { - var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); - videoElement = new VideoElement(resource); - - var loadTrait:LoadTrait = videoElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onReady); - loadTrait.load(); - } - - private function onReady(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - var loadTrait:LoadTrait = videoElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onReady); - - var playTrait:PlayTrait = videoElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - playTrait.play(); - - var displayObjectTrait:DisplayObjectTrait = videoElement.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; - addChild(displayObjectTrait.displayObject); - } - } - - private var videoElement:VideoElement; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + + import org.osmf.elements.VideoElement; + import org.osmf.events.LoadEvent; + import org.osmf.media.URLResource; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + + /** + * Variation on HelloWorld, using MediaElement + DisplayObjectTrait + * rather than MediaPlayerSprite. + **/ + [SWF(width="640", height="352")] + public class HelloWorld4 extends Sprite + { + public function HelloWorld4() + { + var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); + videoElement = new VideoElement(resource); + + var loadTrait:LoadTrait = videoElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onReady); + loadTrait.load(); + } + + private function onReady(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + var loadTrait:LoadTrait = videoElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onReady); + + var playTrait:PlayTrait = videoElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + playTrait.play(); + + var displayObjectTrait:DisplayObjectTrait = videoElement.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; + addChild(displayObjectTrait.displayObject); + } + } + + private var videoElement:VideoElement; + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld5.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld5.as index 9363969..65d5266 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld5.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld5.as @@ -1,57 +1,57 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - - import org.osmf.elements.VideoElement; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - /** - * Variation on HelloWorld, using MediaPlayer + DisplayObjectTrait - * rather than MediaPlayerSprite. - **/ - [SWF(width="640", height="352")] - public class HelloWorld5 extends Sprite - { - public function HelloWorld5() - { - mediaPlayer = new MediaPlayer(); - mediaPlayer.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, onDisplayObjectChange); - - var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); - - // Set the MediaElement on the MediaPlayer. Because - // autoPlay defaults to true, playback begins immediately. - mediaPlayer.media = new VideoElement(resource); - } - - private function onDisplayObjectChange(event:DisplayObjectEvent):void - { - addChild(mediaPlayer.displayObject); - } - - private var mediaPlayer:MediaPlayer; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + + import org.osmf.elements.VideoElement; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + /** + * Variation on HelloWorld, using MediaPlayer + DisplayObjectTrait + * rather than MediaPlayerSprite. + **/ + [SWF(width="640", height="352")] + public class HelloWorld5 extends Sprite + { + public function HelloWorld5() + { + mediaPlayer = new MediaPlayer(); + mediaPlayer.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, onDisplayObjectChange); + + var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); + + // Set the MediaElement on the MediaPlayer. Because + // autoPlay defaults to true, playback begins immediately. + mediaPlayer.media = new VideoElement(resource); + } + + private function onDisplayObjectChange(event:DisplayObjectEvent):void + { + addChild(mediaPlayer.displayObject); + } + + private var mediaPlayer:MediaPlayer; + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld6.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld6.as index 5b54c23..5945e83 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld6.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld6.as @@ -1,71 +1,71 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - - import org.osmf.elements.LightweightVideoElement; - import org.osmf.events.LoadEvent; - import org.osmf.media.URLResource; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - - /** - * Variation on HelloWorld, using MediaElement + DisplayObjectTrait - * rather than MediaPlayerSprite. This example uses LightweightVideoElement - * instead of VideoElement. LightweightVideoElement has a smaller footprint, - * but only supports progressive and simple streaming. - **/ - [SWF(width="640", height="352")] - public class HelloWorld6 extends Sprite - { - public function HelloWorld6() - { - var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); - videoElement = new LightweightVideoElement(resource); - - var loadTrait:LoadTrait = videoElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onReady); - loadTrait.load(); - } - - private function onReady(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - var loadTrait:LoadTrait = videoElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onReady); - - var playTrait:PlayTrait = videoElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - playTrait.play(); - - var displayObjectTrait:DisplayObjectTrait = videoElement.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; - addChild(displayObjectTrait.displayObject); - } - } - - private var videoElement:LightweightVideoElement; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + + import org.osmf.elements.LightweightVideoElement; + import org.osmf.events.LoadEvent; + import org.osmf.media.URLResource; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + + /** + * Variation on HelloWorld, using MediaElement + DisplayObjectTrait + * rather than MediaPlayerSprite. This example uses LightweightVideoElement + * instead of VideoElement. LightweightVideoElement has a smaller footprint, + * but only supports progressive and simple streaming. + **/ + [SWF(width="640", height="352")] + public class HelloWorld6 extends Sprite + { + public function HelloWorld6() + { + var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); + videoElement = new LightweightVideoElement(resource); + + var loadTrait:LoadTrait = videoElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onReady); + loadTrait.load(); + } + + private function onReady(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + var loadTrait:LoadTrait = videoElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onReady); + + var playTrait:PlayTrait = videoElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + playTrait.play(); + + var displayObjectTrait:DisplayObjectTrait = videoElement.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; + addChild(displayObjectTrait.displayObject); + } + } + + private var videoElement:LightweightVideoElement; + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld7.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld7.as index 163d1f5..7b2d776 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld7.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld7.as @@ -1,141 +1,141 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - import flash.display.StageAlign; - import flash.display.StageScaleMode; - import flash.events.Event; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.DurationElement; - import org.osmf.elements.SWFElement; - import org.osmf.elements.SerialElement; - import org.osmf.elements.VideoElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - /** - * Another simple OSMF application, building on HelloWorld2.as. - * - * Plays a video, then shows a SWF, then plays another video. - **/ - [SWF(backgroundColor="0x333333")] - public class HelloWorld7 extends Sprite - { - public function HelloWorld7() - { - stage.scaleMode = StageScaleMode.NO_SCALE; - stage.align = StageAlign.TOP_LEFT; - - // Create the container class that displays the media. - container = new MediaContainer(); - addChild(container); - - // Set the container's size to match that of the stage, and - // prevent the content from being scaled. - container.width = stage.stageWidth; - container.height = stage.stageHeight; - - // Make sure we resize the container when the stage dimensions - // change. - stage.addEventListener(Event.RESIZE, onStageResize); - - // Create the resource to play. - var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); - - // Create a composite MediaElement, consisting of a video - // followed by a SWF, followed by another video. - var mediaElement:MediaElement = createMediaElement(); - - // Assign some layout metadata to the MediaElement. This will cause - // it to be centered in the container, with no scaling of content. - var layoutMetadata:LayoutMetadata = new LayoutMetadata(); - layoutMetadata.scaleMode = ScaleMode.NONE; - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); - - // Add the MediaElement to our container class, so that it gets - // displayed. - container.addMediaElement(mediaElement); - - // Set the MediaElement on a MediaPlayer. Because autoPlay - // defaults to true, playback begins immediately. - var mediaPlayer:MediaPlayer = new MediaPlayer(); - mediaPlayer.media = mediaElement; - } - - private function createMediaElement():MediaElement - { - var serialElement:SerialElement = new SerialElement(); - - // First child is a progressive video. - serialElement.addChild - ( new VideoElement - ( new URLResource(REMOTE_PROGRESSIVE) - ) - ); - - // Second child is a SWF that shows for three seconds. - serialElement.addChild - ( new DurationElement - ( 3 - , new SWFElement - ( new URLResource(REMOTE_SWF) - ) - ) - ); - - // Third child is a progressive video. - serialElement.addChild - ( new VideoElement - ( new URLResource(REMOTE_STREAM) - ) - ); - - return serialElement; - } - - private function onStageResize(event:Event):void - { - container.width = stage.stageWidth; - container.height = stage.stageHeight; - } - - private var container:MediaContainer; - - private static const REMOTE_PROGRESSIVE:String - = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; - - private static const REMOTE_SWF:String - = "http://mediapm.edgesuite.net/osmf/swf/ReferenceSampleSWF.swf"; - - private static const REMOTE_STREAM:String - = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.DurationElement; + import org.osmf.elements.SWFElement; + import org.osmf.elements.SerialElement; + import org.osmf.elements.VideoElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + /** + * Another simple OSMF application, building on HelloWorld2.as. + * + * Plays a video, then shows a SWF, then plays another video. + **/ + [SWF(backgroundColor="0x333333")] + public class HelloWorld7 extends Sprite + { + public function HelloWorld7() + { + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + + // Create the container class that displays the media. + container = new MediaContainer(); + addChild(container); + + // Set the container's size to match that of the stage, and + // prevent the content from being scaled. + container.width = stage.stageWidth; + container.height = stage.stageHeight; + + // Make sure we resize the container when the stage dimensions + // change. + stage.addEventListener(Event.RESIZE, onStageResize); + + // Create the resource to play. + var resource:URLResource = new URLResource("http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"); + + // Create a composite MediaElement, consisting of a video + // followed by a SWF, followed by another video. + var mediaElement:MediaElement = createMediaElement(); + + // Assign some layout metadata to the MediaElement. This will cause + // it to be centered in the container, with no scaling of content. + var layoutMetadata:LayoutMetadata = new LayoutMetadata(); + layoutMetadata.scaleMode = ScaleMode.NONE; + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); + + // Add the MediaElement to our container class, so that it gets + // displayed. + container.addMediaElement(mediaElement); + + // Set the MediaElement on a MediaPlayer. Because autoPlay + // defaults to true, playback begins immediately. + var mediaPlayer:MediaPlayer = new MediaPlayer(); + mediaPlayer.media = mediaElement; + } + + private function createMediaElement():MediaElement + { + var serialElement:SerialElement = new SerialElement(); + + // First child is a progressive video. + serialElement.addChild + ( new VideoElement + ( new URLResource(REMOTE_PROGRESSIVE) + ) + ); + + // Second child is a SWF that shows for three seconds. + serialElement.addChild + ( new DurationElement + ( 3 + , new SWFElement + ( new URLResource(REMOTE_SWF) + ) + ) + ); + + // Third child is a progressive video. + serialElement.addChild + ( new VideoElement + ( new URLResource(REMOTE_STREAM) + ) + ); + + return serialElement; + } + + private function onStageResize(event:Event):void + { + container.width = stage.stageWidth; + container.height = stage.stageHeight; + } + + private var container:MediaContainer; + + private static const REMOTE_PROGRESSIVE:String + = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; + + private static const REMOTE_SWF:String + = "http://mediapm.edgesuite.net/osmf/swf/ReferenceSampleSWF.swf"; + + private static const REMOTE_STREAM:String + = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld8.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld8.as index c007dae..b105436 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld8.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld8.as @@ -1,177 +1,177 @@ -/***************************************************** -* -* Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - import flash.display.StageAlign; - import flash.display.StageScaleMode; - - import org.osmf.containers.MediaContainer; - import org.osmf.events.AlternativeAudioEvent; - import org.osmf.events.MediaErrorEvent; - import org.osmf.events.MediaPlayerStateChangeEvent; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaPlayer; - import org.osmf.media.MediaPlayerState; - import org.osmf.media.URLResource; +/***************************************************** +* +* Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + + import org.osmf.containers.MediaContainer; + import org.osmf.events.AlternativeAudioEvent; + import org.osmf.events.MediaErrorEvent; + import org.osmf.events.MediaPlayerStateChangeEvent; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaPlayer; + import org.osmf.media.MediaPlayerState; + import org.osmf.media.URLResource; import org.osmf.net.StreamingItem; - - /** - * Plays a video with alternate audio streams. - **/ - [SWF(backgroundColor="0xdedede", width=640, height=480)] - public class HelloWorld8 extends Sprite - { - /** - * Default constructor. - */ - public function HelloWorld8() - { - stage.scaleMode = StageScaleMode.NO_SCALE; - stage.align = StageAlign.TOP_LEFT; - - // Create the container class that displays the media. - var container:MediaContainer = new MediaContainer(); - container.x = 0; - container.y = 0; - container.width = stage.stageWidth; - container.height = stage.stageHeight; - addChild(container); - - // Create some layout metadata from the MediaElement. This will cause - // it to be centered in the container, with no scaling of content. - var layoutMetadata:LayoutMetadata = new LayoutMetadata(); - layoutMetadata.layoutMode = LayoutMode.NONE; - layoutMetadata.scaleMode = ScaleMode.LETTERBOX; - layoutMetadata.percentHeight = 100; - layoutMetadata.percentWidth = 100; - layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - - // create media element - var mediaFactory:MediaFactory = new DefaultMediaFactory(); - var mediaElement:MediaElement = mediaFactory.createMediaElement(new URLResource(F4M_VOD)); - mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); - container.addMediaElement(mediaElement); - - // create media player - _player = new MediaPlayer(); - - _player.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - _player.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, onPlayerStateChange); - _player.addEventListener(AlternativeAudioEvent.AUDIO_SWITCHING_CHANGE, onAlternateAudioSwitchingChange); - _player.addEventListener(AlternativeAudioEvent.NUM_ALTERNATIVE_AUDIO_STREAMS_CHANGE, onNumAlternativeAudioStreamsChange); - - _player.media = mediaElement; - _player.loop = false; - _player.autoPlay = false; - _player.bufferTime = 4 ; - } - - /** - * Error event handler. - */ - private function onMediaError(event:MediaErrorEvent):void - { - trace("[Error]", event.toString()); - } - - /** - * @private - * - * Event handler called when the total number of associated alternative streams changes. - */ - private function onNumAlternativeAudioStreamsChange(event:AlternativeAudioEvent):void - { - if (_player.hasAlternativeAudio) - { - trace("Number of alternative audio streams = ", _player.numAlternativeAudioStreams); - } - } - - /** - * @private - * - * Event handler called when an alternative audio stream switch is in progress or has been completed. - */ - private function onAlternateAudioSwitchingChange(event:AlternativeAudioEvent):void - { - if (event.switching) - { - trace("Alternative audio stream switch in progress"); - } - else - { - trace("Alternate audio stream switch completed"); - trace("Current alternate audio index is [" + _player.currentAlternativeAudioStreamIndex + "]."); - } - } - - /** - * Event handler for player state change event. - */ - private function onPlayerStateChange(event:MediaPlayerStateChangeEvent):void - { - switch (event.state) - { - case MediaPlayerState.READY: - if (!_playbackInitiated) - { - _playbackInitiated = true; - - trace("Alternative languages", _player.hasAlternativeAudio ? "available" : " not available" ); - if (_player.hasAlternativeAudio) - { - for (var index:int = 0; index < _player.numAlternativeAudioStreams; index++) - { - var item:StreamingItem = _player.getAlternativeAudioItemAt(index); - trace("[LBA] [", item.info.language, "]", item.info.label); - } - - // we'll just select the first available alternate language - _player.switchAlternativeAudioIndex(0); - } - if (_player.canPlay) - { - _player.play(); - } - } - break; - case MediaPlayerState.PLAYING: - break; - } - } - - /// Internal - private var _player:MediaPlayer = null; - private var _playbackInitiated:Boolean = false; - - private static const F4M_VOD:String = "http://10.131.237.107/vod/hs/vod_2alt/ex.f4m"; - } -} + + /** + * Plays a video with alternate audio streams. + **/ + [SWF(backgroundColor="0xdedede", width=640, height=480)] + public class HelloWorld8 extends Sprite + { + /** + * Default constructor. + */ + public function HelloWorld8() + { + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + + // Create the container class that displays the media. + var container:MediaContainer = new MediaContainer(); + container.x = 0; + container.y = 0; + container.width = stage.stageWidth; + container.height = stage.stageHeight; + addChild(container); + + // Create some layout metadata from the MediaElement. This will cause + // it to be centered in the container, with no scaling of content. + var layoutMetadata:LayoutMetadata = new LayoutMetadata(); + layoutMetadata.layoutMode = LayoutMode.NONE; + layoutMetadata.scaleMode = ScaleMode.LETTERBOX; + layoutMetadata.percentHeight = 100; + layoutMetadata.percentWidth = 100; + layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + + // create media element + var mediaFactory:MediaFactory = new DefaultMediaFactory(); + var mediaElement:MediaElement = mediaFactory.createMediaElement(new URLResource(F4M_VOD)); + mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); + container.addMediaElement(mediaElement); + + // create media player + _player = new MediaPlayer(); + + _player.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + _player.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, onPlayerStateChange); + _player.addEventListener(AlternativeAudioEvent.AUDIO_SWITCHING_CHANGE, onAlternateAudioSwitchingChange); + _player.addEventListener(AlternativeAudioEvent.NUM_ALTERNATIVE_AUDIO_STREAMS_CHANGE, onNumAlternativeAudioStreamsChange); + + _player.media = mediaElement; + _player.loop = false; + _player.autoPlay = false; + _player.bufferTime = 4 ; + } + + /** + * Error event handler. + */ + private function onMediaError(event:MediaErrorEvent):void + { + trace("[Error]", event.toString()); + } + + /** + * @private + * + * Event handler called when the total number of associated alternative streams changes. + */ + private function onNumAlternativeAudioStreamsChange(event:AlternativeAudioEvent):void + { + if (_player.hasAlternativeAudio) + { + trace("Number of alternative audio streams = ", _player.numAlternativeAudioStreams); + } + } + + /** + * @private + * + * Event handler called when an alternative audio stream switch is in progress or has been completed. + */ + private function onAlternateAudioSwitchingChange(event:AlternativeAudioEvent):void + { + if (event.switching) + { + trace("Alternative audio stream switch in progress"); + } + else + { + trace("Alternate audio stream switch completed"); + trace("Current alternate audio index is [" + _player.currentAlternativeAudioStreamIndex + "]."); + } + } + + /** + * Event handler for player state change event. + */ + private function onPlayerStateChange(event:MediaPlayerStateChangeEvent):void + { + switch (event.state) + { + case MediaPlayerState.READY: + if (!_playbackInitiated) + { + _playbackInitiated = true; + + trace("Alternative languages", _player.hasAlternativeAudio ? "available" : " not available" ); + if (_player.hasAlternativeAudio) + { + for (var index:int = 0; index < _player.numAlternativeAudioStreams; index++) + { + var item:StreamingItem = _player.getAlternativeAudioItemAt(index); + trace("[LBA] [", item.info.language, "]", item.info.label); + } + + // we'll just select the first available alternate language + _player.switchAlternativeAudioIndex(0); + } + if (_player.canPlay) + { + _player.play(); + } + } + break; + case MediaPlayerState.PLAYING: + break; + } + } + + /// Internal + private var _player:MediaPlayer = null; + private var _playbackInitiated:Boolean = false; + + private static const F4M_VOD:String = "http://10.131.237.107/vod/hs/vod_2alt/ex.f4m"; + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/HelloWorld9.as b/lib/osmf/samples/HelloWorldSample/src/HelloWorld9.as index 2d4f566..6919838 100644 --- a/lib/osmf/samples/HelloWorldSample/src/HelloWorld9.as +++ b/lib/osmf/samples/HelloWorldSample/src/HelloWorld9.as @@ -1,137 +1,137 @@ -/***************************************************** -* -* Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - import flash.display.StageAlign; - import flash.display.StageScaleMode; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.F4MElement; - import org.osmf.events.DynamicStreamEvent; - import org.osmf.events.MediaErrorEvent; - import org.osmf.events.MediaPlayerStateChangeEvent; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaPlayer; - import org.osmf.media.MediaPlayerState; - import org.osmf.net.StreamingXMLResource; +/***************************************************** +* +* Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; - - /** - * Another simple OSMF application, building on HelloWorld2.as. - * - * Plays a video, then shows a SWF, then plays another video. - **/ - [SWF(backgroundColor="0xdedede", width=640, height=480)] - public class HelloWorld9 extends Sprite - { - public function HelloWorld9() - { - stage.scaleMode = StageScaleMode.NO_SCALE; - stage.align = StageAlign.TOP_LEFT; - - // Create the container class that displays the media. - container = new MediaContainer(); - container.x = 0; - container.y = 0; - container.width = stage.stageWidth; - container.height = stage.stageHeight; - addChild(container); - - // Create some layout metadata from the MediaElement. This will cause - // it to be centered in the container, with no scaling of content. - var layoutMetadata:LayoutMetadata = new LayoutMetadata(); - layoutMetadata.layoutMode = LayoutMode.NONE; - layoutMetadata.scaleMode = ScaleMode.LETTERBOX; - layoutMetadata.percentHeight = 100; - layoutMetadata.percentWidth = 100; - layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; - layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - - // create media element - var streamingXMLResource:StreamingXMLResource = new StreamingXMLResource(XML_F4M, XML_PATH); - var f4MElement:F4MElement = new F4MElement(streamingXMLResource); - container.addMediaElement(f4MElement); - - player = new MediaPlayer(); - player.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, onPlayerStateChange); - player.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - - player.addEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, onAutoSwitchChange); - player.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, onNumDynamicStreamChange); - player.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, onSwitchingChange); - - player.muted = false; - player.loop = false; - player.autoPlay = false; - player.media = f4MElement; - player.bufferTime = 4 ; - player.autoDynamicStreamSwitch=true; - } - - private function onPlayerStateChange(event:MediaPlayerStateChangeEvent):void - { - switch (event.state) - { - case MediaPlayerState.READY: - { - trace("started"); - player.play(); - } - break; - case MediaPlayerState.PLAYING: - break; - } - } - - private function onMediaError(event:MediaErrorEvent):void - { - trace("[Error]", event.toString()); - } - - private function onAutoSwitchChange(event:DynamicStreamEvent):void - { - trace(" [MBR]", event.toString()); - } - - private function onNumDynamicStreamChange(event:DynamicStreamEvent):void - { - trace(" [MBR]", event.toString()); - } - - private function onSwitchingChange(event:DynamicStreamEvent):void - { - trace(" [MBR]", event.toString()); - } - - private var player:MediaPlayer; - private var container:MediaContainer; - private var start:Boolean = true; - - private static const XML_F4M:String = " recorded 0 30000 AAABq2Fic3QAAAAAAAAAFAAAAAPoAAAAAAAJPCoAAAAAAAAAAAAAAAAAAQAAABlhc3J0AAAAAAAAAAABAAAAAQAAABUBAAABZmFmcnQAAAAAAAAD6AAAAAAVAAAAAQAAAAAAAAAAAAB1lAAAAAMAAAAAAADrQgAAdsAAAAAEAAAAAAABYf8AAHUwAAAABQAAAAAAAddNAAB0zAAAAAYAAAAAAAJMNwAActgAAAAHAAAAAAACvy0AAHeIAAAACAAAAAAAAzaRAAB0BAAAAAkAAAAAAAOqcAAAeFAAAAAKAAAAAAAEIr0AAHUwAAAACwAAAAAABJfJAABzPAAAAAwAAAAAAAULAQAAdAQAAAANAAAAAAAFfuAAAHX4AAAADgAAAAAABfT2AAB3iAAAAA8AAAAAAAZsewAAdGgAAAAQAAAAAAAG4OAAAHTMAAAAEQAAAAAAB1WoAAB1+AAAABIAAAAAAAfLnQAAc6AAAAATAAAAAAAIPxgAAHUwAAAAFAAAAAAACLRmAAB1lAAAABUAAAAAAAkqGAAAEfgAAAAAAAAAAAAAAAAAAAAAAA== AgAKb25NZXRhRGF0YQgAAAAAAAhkdXJhdGlvbgBAgupTSQua9wAFd2lkdGgAQJQAAAAAAAAABmhlaWdodABAhoAAAAAAAAAMdmlkZW9jb2RlY2lkAgAEYXZjMQAMYXVkaW9jb2RlY2lkAgAEbXA0YQAKYXZjcHJvZmlsZQBAU0AAAAAAAAAIYXZjbGV2ZWwAQEAAAAAAAAAABmFhY2FvdAAAAAAAAAAAAAAOdmlkZW9mcmFtZXJhdGUAQD34UeuFHrgAD2F1ZGlvc2FtcGxlcmF0ZQBA53AAAAAAAAANYXVkaW9jaGFubmVscwBAAAAAAAAAAAAJdHJhY2tpbmZvCgAAAAIDAAZsZW5ndGgAQXFMd4AAAAAACXRpbWVzY2FsZQBA3USAAAAAAAAIbGFuZ3VhZ2UCAANlbmcAAAkDAAZsZW5ndGgAQXu0o7AAAAAACXRpbWVzY2FsZQBA53AAAAAAAAAIbGFuZ3VhZ2UCAANlbmcAAAkAAAk= AAABq2Fic3QAAAAAAAAAFAAAAAPoAAAAAAAJPCoAAAAAAAAAAAAAAAAAAQAAABlhc3J0AAAAAAAAAAABAAAAAQAAABUBAAABZmFmcnQAAAAAAAAD6AAAAAAVAAAAAQAAAAAAAAAAAAB1lAAAAAMAAAAAAADrQgAAdsAAAAAEAAAAAAABYf8AAHUwAAAABQAAAAAAAddNAAB0zAAAAAYAAAAAAAJMNwAActgAAAAHAAAAAAACvy0AAHeIAAAACAAAAAAAAzaRAAB0BAAAAAkAAAAAAAOqcAAAeFAAAAAKAAAAAAAEIr0AAHUwAAAACwAAAAAABJfJAABzPAAAAAwAAAAAAAULAQAAdAQAAAANAAAAAAAFfuAAAHX4AAAADgAAAAAABfT2AAB3iAAAAA8AAAAAAAZsewAAdGgAAAAQAAAAAAAG4OAAAHTMAAAAEQAAAAAAB1WoAAB1+AAAABIAAAAAAAfLnQAAc6AAAAATAAAAAAAIPxgAAHUwAAAAFAAAAAAACLRmAAB1lAAAABUAAAAAAAkqGAAAEfgAAAAAAAAAAAAAAAAAAAAAAA== AgAKb25NZXRhRGF0YQgAAAAAAAhkdXJhdGlvbgBAgupTSQua9wAFd2lkdGgAQJQAAAAAAAAABmhlaWdodABAhoAAAAAAAAAMdmlkZW9jb2RlY2lkAgAEYXZjMQAMYXVkaW9jb2RlY2lkAgAEbXA0YQAKYXZjcHJvZmlsZQBAU0AAAAAAAAAIYXZjbGV2ZWwAQEAAAAAAAAAABmFhY2FvdAAAAAAAAAAAAAAOdmlkZW9mcmFtZXJhdGUAQD34UeuFHrgAD2F1ZGlvc2FtcGxlcmF0ZQBA53AAAAAAAAANYXVkaW9jaGFubmVscwBAAAAAAAAAAAAJdHJhY2tpbmZvCgAAAAIDAAZsZW5ndGgAQXFMd4AAAAAACXRpbWVzY2FsZQBA3USAAAAAAAAIbGFuZ3VhZ2UCAANlbmcAAAkDAAZsZW5ndGgAQXu0o7AAAAAACXRpbWVzY2FsZQBA53AAAAAAAAAIbGFuZ3VhZ2UCAANlbmcAAAkAAAk= "; - private static const XML_PATH:String = "http://catherine.corp.adobe.com/osmf/mlm_tests"; - } -} + import org.osmf.containers.MediaContainer; + import org.osmf.elements.F4MElement; + import org.osmf.events.DynamicStreamEvent; + import org.osmf.events.MediaErrorEvent; + import org.osmf.events.MediaPlayerStateChangeEvent; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaPlayer; + import org.osmf.media.MediaPlayerState; + import org.osmf.net.StreamingXMLResource; + + + /** + * Another simple OSMF application, building on HelloWorld2.as. + * + * Plays a video, then shows a SWF, then plays another video. + **/ + [SWF(backgroundColor="0xdedede", width=640, height=480)] + public class HelloWorld9 extends Sprite + { + public function HelloWorld9() + { + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + + // Create the container class that displays the media. + container = new MediaContainer(); + container.x = 0; + container.y = 0; + container.width = stage.stageWidth; + container.height = stage.stageHeight; + addChild(container); + + // Create some layout metadata from the MediaElement. This will cause + // it to be centered in the container, with no scaling of content. + var layoutMetadata:LayoutMetadata = new LayoutMetadata(); + layoutMetadata.layoutMode = LayoutMode.NONE; + layoutMetadata.scaleMode = ScaleMode.LETTERBOX; + layoutMetadata.percentHeight = 100; + layoutMetadata.percentWidth = 100; + layoutMetadata.verticalAlign = VerticalAlign.MIDDLE; + layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + + // create media element + var streamingXMLResource:StreamingXMLResource = new StreamingXMLResource(XML_F4M, XML_PATH); + var f4MElement:F4MElement = new F4MElement(streamingXMLResource); + container.addMediaElement(f4MElement); + + player = new MediaPlayer(); + player.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, onPlayerStateChange); + player.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + + player.addEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, onAutoSwitchChange); + player.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, onNumDynamicStreamChange); + player.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, onSwitchingChange); + + player.muted = false; + player.loop = false; + player.autoPlay = false; + player.media = f4MElement; + player.bufferTime = 4 ; + player.autoDynamicStreamSwitch=true; + } + + private function onPlayerStateChange(event:MediaPlayerStateChangeEvent):void + { + switch (event.state) + { + case MediaPlayerState.READY: + { + trace("started"); + player.play(); + } + break; + case MediaPlayerState.PLAYING: + break; + } + } + + private function onMediaError(event:MediaErrorEvent):void + { + trace("[Error]", event.toString()); + } + + private function onAutoSwitchChange(event:DynamicStreamEvent):void + { + trace(" [MBR]", event.toString()); + } + + private function onNumDynamicStreamChange(event:DynamicStreamEvent):void + { + trace(" [MBR]", event.toString()); + } + + private function onSwitchingChange(event:DynamicStreamEvent):void + { + trace(" [MBR]", event.toString()); + } + + private var player:MediaPlayer; + private var container:MediaContainer; + private var start:Boolean = true; + + private static const XML_F4M:String = " recorded 0 30000 AAABq2Fic3QAAAAAAAAAFAAAAAPoAAAAAAAJPCoAAAAAAAAAAAAAAAAAAQAAABlhc3J0AAAAAAAAAAABAAAAAQAAABUBAAABZmFmcnQAAAAAAAAD6AAAAAAVAAAAAQAAAAAAAAAAAAB1lAAAAAMAAAAAAADrQgAAdsAAAAAEAAAAAAABYf8AAHUwAAAABQAAAAAAAddNAAB0zAAAAAYAAAAAAAJMNwAActgAAAAHAAAAAAACvy0AAHeIAAAACAAAAAAAAzaRAAB0BAAAAAkAAAAAAAOqcAAAeFAAAAAKAAAAAAAEIr0AAHUwAAAACwAAAAAABJfJAABzPAAAAAwAAAAAAAULAQAAdAQAAAANAAAAAAAFfuAAAHX4AAAADgAAAAAABfT2AAB3iAAAAA8AAAAAAAZsewAAdGgAAAAQAAAAAAAG4OAAAHTMAAAAEQAAAAAAB1WoAAB1+AAAABIAAAAAAAfLnQAAc6AAAAATAAAAAAAIPxgAAHUwAAAAFAAAAAAACLRmAAB1lAAAABUAAAAAAAkqGAAAEfgAAAAAAAAAAAAAAAAAAAAAAA== AgAKb25NZXRhRGF0YQgAAAAAAAhkdXJhdGlvbgBAgupTSQua9wAFd2lkdGgAQJQAAAAAAAAABmhlaWdodABAhoAAAAAAAAAMdmlkZW9jb2RlY2lkAgAEYXZjMQAMYXVkaW9jb2RlY2lkAgAEbXA0YQAKYXZjcHJvZmlsZQBAU0AAAAAAAAAIYXZjbGV2ZWwAQEAAAAAAAAAABmFhY2FvdAAAAAAAAAAAAAAOdmlkZW9mcmFtZXJhdGUAQD34UeuFHrgAD2F1ZGlvc2FtcGxlcmF0ZQBA53AAAAAAAAANYXVkaW9jaGFubmVscwBAAAAAAAAAAAAJdHJhY2tpbmZvCgAAAAIDAAZsZW5ndGgAQXFMd4AAAAAACXRpbWVzY2FsZQBA3USAAAAAAAAIbGFuZ3VhZ2UCAANlbmcAAAkDAAZsZW5ndGgAQXu0o7AAAAAACXRpbWVzY2FsZQBA53AAAAAAAAAIbGFuZ3VhZ2UCAANlbmcAAAkAAAk= AAABq2Fic3QAAAAAAAAAFAAAAAPoAAAAAAAJPCoAAAAAAAAAAAAAAAAAAQAAABlhc3J0AAAAAAAAAAABAAAAAQAAABUBAAABZmFmcnQAAAAAAAAD6AAAAAAVAAAAAQAAAAAAAAAAAAB1lAAAAAMAAAAAAADrQgAAdsAAAAAEAAAAAAABYf8AAHUwAAAABQAAAAAAAddNAAB0zAAAAAYAAAAAAAJMNwAActgAAAAHAAAAAAACvy0AAHeIAAAACAAAAAAAAzaRAAB0BAAAAAkAAAAAAAOqcAAAeFAAAAAKAAAAAAAEIr0AAHUwAAAACwAAAAAABJfJAABzPAAAAAwAAAAAAAULAQAAdAQAAAANAAAAAAAFfuAAAHX4AAAADgAAAAAABfT2AAB3iAAAAA8AAAAAAAZsewAAdGgAAAAQAAAAAAAG4OAAAHTMAAAAEQAAAAAAB1WoAAB1+AAAABIAAAAAAAfLnQAAc6AAAAATAAAAAAAIPxgAAHUwAAAAFAAAAAAACLRmAAB1lAAAABUAAAAAAAkqGAAAEfgAAAAAAAAAAAAAAAAAAAAAAA== AgAKb25NZXRhRGF0YQgAAAAAAAhkdXJhdGlvbgBAgupTSQua9wAFd2lkdGgAQJQAAAAAAAAABmhlaWdodABAhoAAAAAAAAAMdmlkZW9jb2RlY2lkAgAEYXZjMQAMYXVkaW9jb2RlY2lkAgAEbXA0YQAKYXZjcHJvZmlsZQBAU0AAAAAAAAAIYXZjbGV2ZWwAQEAAAAAAAAAABmFhY2FvdAAAAAAAAAAAAAAOdmlkZW9mcmFtZXJhdGUAQD34UeuFHrgAD2F1ZGlvc2FtcGxlcmF0ZQBA53AAAAAAAAANYXVkaW9jaGFubmVscwBAAAAAAAAAAAAJdHJhY2tpbmZvCgAAAAIDAAZsZW5ndGgAQXFMd4AAAAAACXRpbWVzY2FsZQBA3USAAAAAAAAIbGFuZ3VhZ2UCAANlbmcAAAkDAAZsZW5ndGgAQXu0o7AAAAAACXRpbWVzY2FsZQBA53AAAAAAAAAIbGFuZ3VhZ2UCAANlbmcAAAkAAAk= "; + private static const XML_PATH:String = "http://catherine.corp.adobe.com/osmf/mlm_tests"; + } +} diff --git a/lib/osmf/samples/HelloWorldSample/src/publish_settings.xml b/lib/osmf/samples/HelloWorldSample/src/publish_settings.xml index 55f66f3..0916ee7 100644 --- a/lib/osmf/samples/HelloWorldSample/src/publish_settings.xml +++ b/lib/osmf/samples/HelloWorldSample/src/publish_settings.xml @@ -1,180 +1,180 @@ - - - - 1 - 1 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - HelloWorld.swf - HelloWorld.swt - HelloWorld.exe - HelloWorld.app - HelloWorld.html - HelloWorld.gif - HelloWorld.jpg - HelloWorld.png - HelloWorld.mov - HelloWorld.smil - - - 0 - 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; - 1 - 1 - HelloWorld_content.html - HelloWorld_alternate.html - 0 - - 100 - 100 - 0 - 2 - 0 - 0 - 3 - 1 - 1 - 4 - 0 - 0 - 1 - 0 - /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html - 1 - - - - - 0 - 0 - 0 - 80 - 0 - 0 - 7 - 0 - 7 - 0 - 10 - FlashPlayer10 - 3 - 1 - - .;../../../../libs/ChromeLibrary;../../../../framework/OSMF - $(AppConfig)/ActionScript 3.0/libs - . - CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; - 0 - - 1 - 1 - 0 - 0 - 0 - 0 - HelloWorld - 1 - 1 - 1 - AS3 - 1 - 1 - 0 - 15 - 1 - 0 - - - 550 - 400 - 0 - 4718592 - 0 - 80 - 1 - - - 1 - 0 - 1 - 0 - 0 - 100000 - 1 - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 1 - - - 550 - 400 - 0 - 1 - 1 - - 1 - 0 - 1 - 0 - 0 - - 128 - - - 255 - - - - 550 - 400 - 1 - 0 - 0 - 1 - 0 - 0 - 1 - - - - 24-bit with Alpha - 255 - - - - 550 - 400 - 1 - 0 - - - 00000000 - 0 - 0 - 0 - 0 - 1 - - + + + + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + HelloWorld.swf + HelloWorld.swt + HelloWorld.exe + HelloWorld.app + HelloWorld.html + HelloWorld.gif + HelloWorld.jpg + HelloWorld.png + HelloWorld.mov + HelloWorld.smil + + + 0 + 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + HelloWorld_content.html + HelloWorld_alternate.html + 0 + + 100 + 100 + 0 + 2 + 0 + 0 + 3 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 10 + FlashPlayer10 + 3 + 1 + + .;../../../../libs/ChromeLibrary;../../../../framework/OSMF + $(AppConfig)/ActionScript 3.0/libs + . + CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; + 0 + + 1 + 1 + 0 + 0 + 0 + 0 + HelloWorld + 1 + 1 + 1 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + + + 550 + 400 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 550 + 400 + 0 + 1 + 1 + + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 550 + 400 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 550 + 400 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + diff --git a/lib/osmf/samples/LateBindingAudioSample/.actionScriptProperties b/lib/osmf/samples/LateBindingAudioSample/.actionScriptProperties index 6ce136f..919b0f7 100644 --- a/lib/osmf/samples/LateBindingAudioSample/.actionScriptProperties +++ b/lib/osmf/samples/LateBindingAudioSample/.actionScriptProperties @@ -1,27 +1,27 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/LateBindingAudioSample/.flexProperties b/lib/osmf/samples/LateBindingAudioSample/.flexProperties index f207211..0f603b0 100644 --- a/lib/osmf/samples/LateBindingAudioSample/.flexProperties +++ b/lib/osmf/samples/LateBindingAudioSample/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/LateBindingAudioSample/src/LateBindingAudioSample.mxml b/lib/osmf/samples/LateBindingAudioSample/src/LateBindingAudioSample.mxml index 4a2aa40..c1c3f2c 100644 --- a/lib/osmf/samples/LateBindingAudioSample/src/LateBindingAudioSample.mxml +++ b/lib/osmf/samples/LateBindingAudioSample/src/LateBindingAudioSample.mxml @@ -1,530 +1,530 @@ - - - - = sldSeek.minimum && event.time <= sldSeek.maximum) - { - sldSeek.value = event.time; - lblTime.text = Number(event.time).toFixed(3); - } - } - - /** - * @private - * When the player is ready for playback, iterate through alternate - * audio tracks and update the UI. - **/ - private function onPlayerStateChange(event:MediaPlayerStateChangeEvent):void - { - updateUI(); - var targetPlayer:MediaPlayer = event.target as MediaPlayer; - if (targetPlayer != null && event.state == MediaPlayerState.READY) - { - languages = new ArrayCollection(); - alternativeLanguage = -1; - - var index:int = 0; - if (targetPlayer.hasAlternativeAudio) - { - trace("[LBA - Sample] Alternative audio tracks available."); - - var languageItem:Object = new Object(); - languageItem["label"] = "Default"; - languageItem["data"] = -1; - languages.addItem(languageItem); - - for (index = 0; index < targetPlayer.numAlternativeAudioStreams; index++) - { - var item:StreamingItem = targetPlayer.getAlternativeAudioItemAt(index); - trace("[LBA - Sample] ", item.info.language, "]", item.info.label); - - languageItem = new Object(); - languageItem["label"] = item.info.label + "(" + item.info.language + ")"; - languageItem["data"] = index; - languages.addItem(languageItem); - } - } - - streams = new ArrayCollection(); - - if (targetPlayer.isDynamicStream) - { - trace("[LBA - Sample] Dynamic streams available."); - for (index = 0; index < targetPlayer.numDynamicStreams; index++) - { - var bitrate:Number = targetPlayer.getBitrateForDynamicStreamIndex(index); - trace("[LBA - Sample] Bitrate :", bitrate); - - var bitRateItem:Object = new Object(); - bitRateItem["data"] = bitRateItem["label"] = bitrate; - streams.addItem(bitrate); - } - } - } - } - - /** - * @private - * Executed when player encounters an error. - **/ - private function onPlayerError(event:MediaErrorEvent):void - { - updateUI(); - } - - /** - * @private - * Play the current media element. - **/ - private function onPlayPauseClick(event:MouseEvent):void - { - if (!player.playing) - { - if (player.canPlay) - player.play(); - } - else - { - if (player.canPause) - player.pause(); - } - } - - /** - * @private - * Snap the current media element to live. - **/ - private function onSnapToLiveClick(event:MouseEvent):void - { - if (player != null && player.state == MediaPlayerState.PLAYING) - { - if (player.canSeek) - { - player.seek(10000); - } - } - } - - private function onSeekRequest():void - { - var seekTarget:Number = sldSeek.value; - if (player.canSeek) - player.seek(seekTarget); - } - - private function onAutoRewindChange(event:Event):void - { - player.autoRewind = chkAutoRewind.selected; - } - - private function onAutoSwitchChange(event:Event):void - { - player.autoDynamicStreamSwitch = chkAutoSwitch.selected; - } - - /** - * @private - * Listen for audio stream events. - **/ - private function onPlayerAudioStreamChange(event:AlternativeAudioEvent):void - { - if (event.switching) - trace("[LBA - Sample] Alternative audio stream is switching."); - else - trace("[LBA - Sample] Alternative audio switch is complete."); - } - - /** - * @private - **/ - private var player:MediaPlayer = null; - private var factory:MediaFactory = null; - private var container:MediaContainer = null; - - private var alternativeLanguage:int = -1; - private var dynamicStream:int = -1; - - private var seekedToLive:Boolean = false; - - [Bindable] - protected var streams:ArrayCollection = null; - - [Bindable] - protected var languages:ArrayCollection = null; - - [Bindable] - protected var urls:ArrayCollection = null; - private static const URLS:Array = - [ -// { -// label:"Synced video and audio", -// data:"http://10.131.237.104/hds-live/latebind_sync/_definst_/liveevent.f4m" -// }, -// { -// label:"Rolling window", -// data:"http://10.131.165.62/live/events/livehds/events/_definst_/liveevent.f4m" -// }, - { - label:"VOD: 1 video with 2 alternative audio tracks", - data:"http://10.131.165.85/vod/vod/late_binding_audio/API_tests_assets/1_media_v_2_alternate_a/1_media_v_2_alternate_a.f4m" - }, -// { -// label:"Seek outside buffer", -// data:"http://10.131.237.107/vod/hs/vod/ex.f4m" -// }, -// { -// label:"Legacy HDS manifest", -// data:"http://zeridemo-f.akamaihd.net/content/inoutedit-mbr/inoutedit_h264_3000.f4m" -// }, -// { -// label:"Legacy Live HDS manifest", -// data:"http://10.131.237.107/live/videostream.f4m" -// }, -// { -// label:"Legacy Live HDS with DVR", -// data:" http://10.131.237.107/live/events/hs_sbr_dvr/events/_definst_/liveevent.f4m" -// }, -// { -// label:"Legacy Live HDS manifest with MBR", -// data:"http://10.131.237.107/live/events/hs_mbr_live/events/_definst_/liveevent.f4m" -// }, -// { -// label:"Legacy live HDS manifest without DVR", -// data:"http://10.122.233.48/live/events/livepkgr/events/_definst_/liveevent.f4m"  -// }, - { - label:"VOD: 1 audio-video with 2 alternative audio tracks", - data:"http://10.131.237.104/vod/late_binding_audio/API_tests_assets/1_media_av_2_alternate_a/1_media_av_2_alternate_a.f4m" - }, -// { -// label:"MBR: 1 mbr stream with 2 alternative audio tracks", -// data:"http://10.131.237.107/vod/mbr/sample1_audio2.f4m" -// }, - { - label:"LIVE: 1 video with 2 alternative audio tracks", - data:"http://10.131.237.107/live/events/latebind/events/_definst_/liveevent.f4m" - }, -// { -// label:"LIVE: 1 video with 1 alternate audio track", -// data:"http://10.131.237.107/live/purelive_lba.f4m" -// }, -// { -// label:"LIVE: audio only", -// data:"http://10.131.237.107/live/events/live_audio_only/events/_definst_/liveevent_audio_only.f4m" -// }, -// { -// label:"SeeSaw/ioko SBR protected content 1 (700)", -// data:"http://10.131.237.107/vod/mbr/drm/sample1_drm_700kbps.f4m" //http://10.131.237.107/vod/SeeSaw/35321_single_796.f4m" -// }, -// { -// label:"SeeSaw/ioko SBR protected content 2 (1000)", -// data:"http://10.131.237.107/vod/mbr/drm/sample1_drm_1000kbps.f4m" //http://10.131.237.107/vod/SeeSaw/35322_single_500.f4m" -// }, -// { -// label:"SeeSaw/ioko SBR protected content 3 (1500)", -// data:"http://10.131.237.107/vod/mbr/drm/sample1_drm_1500kbps.f4m" //http://10.131.237.107/vod/SeeSaw/35323_single_1500.f4m" -// }, -// { -// label:"SeeSaw/ioko MBR protected content", -// data:"http://10.131.237.107/vod/mbr/drm/sample1_mbr_drm.f4m" //http://10.131.237.107/vod/SeeSaw/seesaw_mbr.f4m" -// }, - { - label:"LIVE: 1 video with 1 synced alternative audio track", - data:"http://10.131.237.104/hds-live/latebind_sync/_definst_/liveevent.f4m" - }, - { - label:"VOD: 1 audio-video with 2 shorter alternative audio tracks", - data:"http://10.131.237.104/vod/late_binding_audio/API_tests_assets/1_media_av_2_shorter_alternate_a/1_media_av_2_shorter_alternate_a.f4m" - }, - { - label:"VOD: 1 video with 2 shorter alternative audio tracks", - data:"http://10.131.237.104/vod/late_binding_audio/API_tests_assets/1_media_v_2_shorter_alternate_a/interview_video_only_2_shorter_alternate_audio.f4m" - } - ]; - - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + = sldSeek.minimum && event.time <= sldSeek.maximum) + { + sldSeek.value = event.time; + lblTime.text = Number(event.time).toFixed(3); + } + } + + /** + * @private + * When the player is ready for playback, iterate through alternate + * audio tracks and update the UI. + **/ + private function onPlayerStateChange(event:MediaPlayerStateChangeEvent):void + { + updateUI(); + var targetPlayer:MediaPlayer = event.target as MediaPlayer; + if (targetPlayer != null && event.state == MediaPlayerState.READY) + { + languages = new ArrayCollection(); + alternativeLanguage = -1; + + var index:int = 0; + if (targetPlayer.hasAlternativeAudio) + { + trace("[LBA - Sample] Alternative audio tracks available."); + + var languageItem:Object = new Object(); + languageItem["label"] = "Default"; + languageItem["data"] = -1; + languages.addItem(languageItem); + + for (index = 0; index < targetPlayer.numAlternativeAudioStreams; index++) + { + var item:StreamingItem = targetPlayer.getAlternativeAudioItemAt(index); + trace("[LBA - Sample] ", item.info.language, "]", item.info.label); + + languageItem = new Object(); + languageItem["label"] = item.info.label + "(" + item.info.language + ")"; + languageItem["data"] = index; + languages.addItem(languageItem); + } + } + + streams = new ArrayCollection(); + + if (targetPlayer.isDynamicStream) + { + trace("[LBA - Sample] Dynamic streams available."); + for (index = 0; index < targetPlayer.numDynamicStreams; index++) + { + var bitrate:Number = targetPlayer.getBitrateForDynamicStreamIndex(index); + trace("[LBA - Sample] Bitrate :", bitrate); + + var bitRateItem:Object = new Object(); + bitRateItem["data"] = bitRateItem["label"] = bitrate; + streams.addItem(bitrate); + } + } + } + } + + /** + * @private + * Executed when player encounters an error. + **/ + private function onPlayerError(event:MediaErrorEvent):void + { + updateUI(); + } + + /** + * @private + * Play the current media element. + **/ + private function onPlayPauseClick(event:MouseEvent):void + { + if (!player.playing) + { + if (player.canPlay) + player.play(); + } + else + { + if (player.canPause) + player.pause(); + } + } + + /** + * @private + * Snap the current media element to live. + **/ + private function onSnapToLiveClick(event:MouseEvent):void + { + if (player != null && player.state == MediaPlayerState.PLAYING) + { + if (player.canSeek) + { + player.seek(10000); + } + } + } + + private function onSeekRequest():void + { + var seekTarget:Number = sldSeek.value; + if (player.canSeek) + player.seek(seekTarget); + } + + private function onAutoRewindChange(event:Event):void + { + player.autoRewind = chkAutoRewind.selected; + } + + private function onAutoSwitchChange(event:Event):void + { + player.autoDynamicStreamSwitch = chkAutoSwitch.selected; + } + + /** + * @private + * Listen for audio stream events. + **/ + private function onPlayerAudioStreamChange(event:AlternativeAudioEvent):void + { + if (event.switching) + trace("[LBA - Sample] Alternative audio stream is switching."); + else + trace("[LBA - Sample] Alternative audio switch is complete."); + } + + /** + * @private + **/ + private var player:MediaPlayer = null; + private var factory:MediaFactory = null; + private var container:MediaContainer = null; + + private var alternativeLanguage:int = -1; + private var dynamicStream:int = -1; + + private var seekedToLive:Boolean = false; + + [Bindable] + protected var streams:ArrayCollection = null; + + [Bindable] + protected var languages:ArrayCollection = null; + + [Bindable] + protected var urls:ArrayCollection = null; + private static const URLS:Array = + [ +// { +// label:"Synced video and audio", +// data:"http://10.131.237.104/hds-live/latebind_sync/_definst_/liveevent.f4m" +// }, +// { +// label:"Rolling window", +// data:"http://10.131.165.62/live/events/livehds/events/_definst_/liveevent.f4m" +// }, + { + label:"VOD: 1 video with 2 alternative audio tracks", + data:"http://10.131.165.85/vod/vod/late_binding_audio/API_tests_assets/1_media_v_2_alternate_a/1_media_v_2_alternate_a.f4m" + }, +// { +// label:"Seek outside buffer", +// data:"http://10.131.237.107/vod/hs/vod/ex.f4m" +// }, +// { +// label:"Legacy HDS manifest", +// data:"http://zeridemo-f.akamaihd.net/content/inoutedit-mbr/inoutedit_h264_3000.f4m" +// }, +// { +// label:"Legacy Live HDS manifest", +// data:"http://10.131.237.107/live/videostream.f4m" +// }, +// { +// label:"Legacy Live HDS with DVR", +// data:" http://10.131.237.107/live/events/hs_sbr_dvr/events/_definst_/liveevent.f4m" +// }, +// { +// label:"Legacy Live HDS manifest with MBR", +// data:"http://10.131.237.107/live/events/hs_mbr_live/events/_definst_/liveevent.f4m" +// }, +// { +// label:"Legacy live HDS manifest without DVR", +// data:"http://10.122.233.48/live/events/livepkgr/events/_definst_/liveevent.f4m"  +// }, + { + label:"VOD: 1 audio-video with 2 alternative audio tracks", + data:"http://10.131.237.104/vod/late_binding_audio/API_tests_assets/1_media_av_2_alternate_a/1_media_av_2_alternate_a.f4m" + }, +// { +// label:"MBR: 1 mbr stream with 2 alternative audio tracks", +// data:"http://10.131.237.107/vod/mbr/sample1_audio2.f4m" +// }, + { + label:"LIVE: 1 video with 2 alternative audio tracks", + data:"http://10.131.237.107/live/events/latebind/events/_definst_/liveevent.f4m" + }, +// { +// label:"LIVE: 1 video with 1 alternate audio track", +// data:"http://10.131.237.107/live/purelive_lba.f4m" +// }, +// { +// label:"LIVE: audio only", +// data:"http://10.131.237.107/live/events/live_audio_only/events/_definst_/liveevent_audio_only.f4m" +// }, +// { +// label:"SeeSaw/ioko SBR protected content 1 (700)", +// data:"http://10.131.237.107/vod/mbr/drm/sample1_drm_700kbps.f4m" //http://10.131.237.107/vod/SeeSaw/35321_single_796.f4m" +// }, +// { +// label:"SeeSaw/ioko SBR protected content 2 (1000)", +// data:"http://10.131.237.107/vod/mbr/drm/sample1_drm_1000kbps.f4m" //http://10.131.237.107/vod/SeeSaw/35322_single_500.f4m" +// }, +// { +// label:"SeeSaw/ioko SBR protected content 3 (1500)", +// data:"http://10.131.237.107/vod/mbr/drm/sample1_drm_1500kbps.f4m" //http://10.131.237.107/vod/SeeSaw/35323_single_1500.f4m" +// }, +// { +// label:"SeeSaw/ioko MBR protected content", +// data:"http://10.131.237.107/vod/mbr/drm/sample1_mbr_drm.f4m" //http://10.131.237.107/vod/SeeSaw/seesaw_mbr.f4m" +// }, + { + label:"LIVE: 1 video with 1 synced alternative audio track", + data:"http://10.131.237.104/hds-live/latebind_sync/_definst_/liveevent.f4m" + }, + { + label:"VOD: 1 audio-video with 2 shorter alternative audio tracks", + data:"http://10.131.237.104/vod/late_binding_audio/API_tests_assets/1_media_av_2_shorter_alternate_a/1_media_av_2_shorter_alternate_a.f4m" + }, + { + label:"VOD: 1 video with 2 shorter alternative audio tracks", + data:"http://10.131.237.104/vod/late_binding_audio/API_tests_assets/1_media_v_2_shorter_alternate_a/interview_video_only_2_shorter_alternate_audio.f4m" + } + ]; + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/LayoutSample/.actionScriptProperties b/lib/osmf/samples/LayoutSample/.actionScriptProperties index 3ca76b6..aaac8d5 100644 --- a/lib/osmf/samples/LayoutSample/.actionScriptProperties +++ b/lib/osmf/samples/LayoutSample/.actionScriptProperties @@ -1,36 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/LayoutSample/html-template/AC_OETags.js b/lib/osmf/samples/LayoutSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/LayoutSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/LayoutSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/LayoutSample/html-template/history/historyFrame.html b/lib/osmf/samples/LayoutSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/LayoutSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/LayoutSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/LayoutSample/html-template/index.template.html b/lib/osmf/samples/LayoutSample/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/LayoutSample/html-template/index.template.html +++ b/lib/osmf/samples/LayoutSample/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/LayoutSample/readme.txt b/lib/osmf/samples/LayoutSample/readme.txt index ba160e8..8ff9d0a 100644 --- a/lib/osmf/samples/LayoutSample/readme.txt +++ b/lib/osmf/samples/LayoutSample/readme.txt @@ -1,26 +1,26 @@ -Sample Application: LayoutSample - -A. Overview - -This sample application demonstrates how to use the OSMF layout API to: - -- show an overlay bug at the bottom-right side of a video, -- use the API to layout things other than media elements. - -B. Installation Instructions (Flex Builder) - -1. Unzip/copy the LayoutSample project into your Flex Builder workspace folder. -2. In Flex Builder, go to the File menu and select "Import". -3. Select "General", then "Existing Projects into Workspace", and click "Next". -4. Choose "Select root directory" and "Browse". -5. Browse to your Flex Builder workspace folder. -6. Select the checkbox next to "LayoutSample", and click "Finish". This will import the project. -7. Build the project. -8. Launch the application from the Run menu. - -Note that the sample loads assets from the web, so please make sure to be connected to the -internet when trying them out. - -C. Usage Instructions - +Sample Application: LayoutSample + +A. Overview + +This sample application demonstrates how to use the OSMF layout API to: + +- show an overlay bug at the bottom-right side of a video, +- use the API to layout things other than media elements. + +B. Installation Instructions (Flex Builder) + +1. Unzip/copy the LayoutSample project into your Flex Builder workspace folder. +2. In Flex Builder, go to the File menu and select "Import". +3. Select "General", then "Existing Projects into Workspace", and click "Next". +4. Choose "Select root directory" and "Browse". +5. Browse to your Flex Builder workspace folder. +6. Select the checkbox next to "LayoutSample", and click "Finish". This will import the project. +7. Build the project. +8. Launch the application from the Run menu. + +Note that the sample loads assets from the web, so please make sure to be connected to the +internet when trying them out. + +C. Usage Instructions + Both LayoutSample.as and LayoutSample2.as are runable applications. Use Flex Builder's "Set as Default Application" to select one. \ No newline at end of file diff --git a/lib/osmf/samples/LayoutSample/src/LayoutSample.as b/lib/osmf/samples/LayoutSample/src/LayoutSample.as index 04739e7..d066c75 100644 --- a/lib/osmf/samples/LayoutSample/src/LayoutSample.as +++ b/lib/osmf/samples/LayoutSample/src/LayoutSample.as @@ -1,105 +1,105 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package -{ - import flash.display.Sprite; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.ImageElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.VideoElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - [SWF(backgroundColor="0x000000", frameRate="25", width="640", height="360")] - public class LayoutSample extends Sprite - { - public function LayoutSample() - { - // Contstruct and image element: - var logo:ImageElement = new ImageElement(new URLResource(LOGO_PNG)); - logo.smoothing = true; - - // Construct a layout properties object for the logo: - var logoLayout:LayoutMetadata = new LayoutMetadata(); - logo.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, logoLayout);; - - // Set the image to take 30% of its parent's width and height: - logoLayout.percentWidth = 30; - logoLayout.percentHeight = 30; - - // Position the image's bottom-right corner 20 pixels away from - // the container's bottom-right corner: - logoLayout.bottom = 20; - logoLayout.right = 20; - - // Set the image to scale, keeping aspect ratio: - logoLayout.scaleMode = ScaleMode.LETTERBOX; - - // Instruct the image to be moved to the right hand side, should - // any surplus horizontal space be available after scaling: - logoLayout.horizontalAlign = HorizontalAlign.RIGHT; - - // Construct a video element: - var video:MediaElement = new VideoElement(new URLResource(LOGO_VID)); - - // If no layout properties have been set on an element when it gets - // added to a parent, then the the parent will set the target to - // scale letter-box mode, vertical alignment to center, horizontal - // alignment to middle, and set width and height to 100% of the - // parent. This is fine for the video element at hand, so no additional - // layout properties are set for it. - - // Construct a parallel element that holds both the video and the - // logo still: - var parallel:ParallelElement = new ParallelElement(); - parallel.addChild(video); - parallel.addChild(logo); - - // Give the parallel element a fixed width and height. Both the - // video element and the logo will base their appearance of these - // metrics: - var parallelLayout:LayoutMetadata = new LayoutMetadata(); - parallel.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, parallelLayout); - parallelLayout.width = stage.stageWidth; - parallelLayout.height = stage.stageHeight; - - // Construct a container that will display the parallel media - // element: - var container:MediaContainer = new MediaContainer() - container.addMediaElement(parallel); - addChild(container); - - // Construct a player to load and play the parallel element: - var player:MediaPlayer = new MediaPlayer(parallel); - player.loop = true; - } - - private static const LOGO_PNG:String = "http://dl.dropbox.com/u/2980264/OSMF/logo_white.png"; - private static const LOGO_VID:String = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; - } -} +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package +{ + import flash.display.Sprite; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.ImageElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.VideoElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + [SWF(backgroundColor="0x000000", frameRate="25", width="640", height="360")] + public class LayoutSample extends Sprite + { + public function LayoutSample() + { + // Contstruct and image element: + var logo:ImageElement = new ImageElement(new URLResource(LOGO_PNG)); + logo.smoothing = true; + + // Construct a layout properties object for the logo: + var logoLayout:LayoutMetadata = new LayoutMetadata(); + logo.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, logoLayout);; + + // Set the image to take 30% of its parent's width and height: + logoLayout.percentWidth = 30; + logoLayout.percentHeight = 30; + + // Position the image's bottom-right corner 20 pixels away from + // the container's bottom-right corner: + logoLayout.bottom = 20; + logoLayout.right = 20; + + // Set the image to scale, keeping aspect ratio: + logoLayout.scaleMode = ScaleMode.LETTERBOX; + + // Instruct the image to be moved to the right hand side, should + // any surplus horizontal space be available after scaling: + logoLayout.horizontalAlign = HorizontalAlign.RIGHT; + + // Construct a video element: + var video:MediaElement = new VideoElement(new URLResource(LOGO_VID)); + + // If no layout properties have been set on an element when it gets + // added to a parent, then the the parent will set the target to + // scale letter-box mode, vertical alignment to center, horizontal + // alignment to middle, and set width and height to 100% of the + // parent. This is fine for the video element at hand, so no additional + // layout properties are set for it. + + // Construct a parallel element that holds both the video and the + // logo still: + var parallel:ParallelElement = new ParallelElement(); + parallel.addChild(video); + parallel.addChild(logo); + + // Give the parallel element a fixed width and height. Both the + // video element and the logo will base their appearance of these + // metrics: + var parallelLayout:LayoutMetadata = new LayoutMetadata(); + parallel.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, parallelLayout); + parallelLayout.width = stage.stageWidth; + parallelLayout.height = stage.stageHeight; + + // Construct a container that will display the parallel media + // element: + var container:MediaContainer = new MediaContainer() + container.addMediaElement(parallel); + addChild(container); + + // Construct a player to load and play the parallel element: + var player:MediaPlayer = new MediaPlayer(parallel); + player.loop = true; + } + + private static const LOGO_PNG:String = "http://dl.dropbox.com/u/2980264/OSMF/logo_white.png"; + private static const LOGO_VID:String = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; + } +} diff --git a/lib/osmf/samples/LayoutSample/src/LayoutSample2.as b/lib/osmf/samples/LayoutSample/src/LayoutSample2.as index 0265d85..43d82dd 100644 --- a/lib/osmf/samples/LayoutSample/src/LayoutSample2.as +++ b/lib/osmf/samples/LayoutSample/src/LayoutSample2.as @@ -1,79 +1,79 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package -{ - import flash.display.Sprite; - - import org.osmf.layout.LayoutMode; - import org.osmf.layout.LayoutRenderer; - import org.osmf.layout.LayoutTargetSprite; - - [SWF(backgroundColor="0xC0C0C0", frameRate="25", width="640", height="360")] - public class LayoutSample2 extends Sprite - { - public function LayoutSample2() - { - // Construct a layout renderer: - var renderer:LayoutRenderer = new LayoutRenderer(); - - // Construct a red, green and blue ball: - var ball1:LayoutTargetSprite = createBall(0xff0000); - var ball2:LayoutTargetSprite = createBall(0x00ff00); - var ball3:LayoutTargetSprite = createBall(0x0000ff); - - // Add each ball as a target to the renderer: - renderer.addTarget(ball1); - renderer.addTarget(ball2); - renderer.addTarget(ball3); - - // Construct a layout target sprite that the renderer - // can use as its container: - var container:LayoutTargetSprite - = new LayoutTargetSprite(); - renderer.container = container; - addChild(container); - - // Set the container to operate in VERTICAL layoutMode: - container.layoutMetadata.layoutMode = LayoutMode.VERTICAL; - } - - private function createBall(color:uint):LayoutTargetSprite - { - // Construct a layout target sprite (a Sprite that implements - // the ILayoutTarget interface): - var result:LayoutTargetSprite = new LayoutTargetSprite(); - - // Draw a circle: - result.graphics.beginFill(color); - result.graphics.drawCircle(50,50,50); - result.graphics.endFill(); - - // Inform the layout system that this layout target is a - // 100x100 pixels in size: - result.layoutMetadata.width = 100; - result.layoutMetadata.height = 100; - - return result; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package +{ + import flash.display.Sprite; + + import org.osmf.layout.LayoutMode; + import org.osmf.layout.LayoutRenderer; + import org.osmf.layout.LayoutTargetSprite; + + [SWF(backgroundColor="0xC0C0C0", frameRate="25", width="640", height="360")] + public class LayoutSample2 extends Sprite + { + public function LayoutSample2() + { + // Construct a layout renderer: + var renderer:LayoutRenderer = new LayoutRenderer(); + + // Construct a red, green and blue ball: + var ball1:LayoutTargetSprite = createBall(0xff0000); + var ball2:LayoutTargetSprite = createBall(0x00ff00); + var ball3:LayoutTargetSprite = createBall(0x0000ff); + + // Add each ball as a target to the renderer: + renderer.addTarget(ball1); + renderer.addTarget(ball2); + renderer.addTarget(ball3); + + // Construct a layout target sprite that the renderer + // can use as its container: + var container:LayoutTargetSprite + = new LayoutTargetSprite(); + renderer.container = container; + addChild(container); + + // Set the container to operate in VERTICAL layoutMode: + container.layoutMetadata.layoutMode = LayoutMode.VERTICAL; + } + + private function createBall(color:uint):LayoutTargetSprite + { + // Construct a layout target sprite (a Sprite that implements + // the ILayoutTarget interface): + var result:LayoutTargetSprite = new LayoutTargetSprite(); + + // Draw a circle: + result.graphics.beginFill(color); + result.graphics.drawCircle(50,50,50); + result.graphics.endFill(); + + // Inform the layout system that this layout target is a + // 100x100 pixels in size: + result.layoutMetadata.width = 100; + result.layoutMetadata.height = 100; + + return result; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/LayoutSample/src/LayoutSample3.as b/lib/osmf/samples/LayoutSample/src/LayoutSample3.as index 52341b0..4d9bb9d 100644 --- a/lib/osmf/samples/LayoutSample/src/LayoutSample3.as +++ b/lib/osmf/samples/LayoutSample/src/LayoutSample3.as @@ -1,98 +1,98 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package -{ - import flash.display.Sprite; - - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.LayoutRenderer; - import org.osmf.layout.LayoutTargetSprite; - import org.osmf.layout.ScaleMode; - - [SWF(backgroundColor="0x000000", frameRate="25", width="640", height="360")] - public class LayoutSample3 extends Sprite - { - public function LayoutSample3() - { - // Construct a layout renderer: - var renderer:LayoutRenderer = new LayoutRenderer(); - - // Add some targets to the renderer: - renderer.addTarget(constructBall(0xC89B41)); - renderer.addTarget(constructBall(0xA16B2B)); - var ball3:LayoutTargetSprite = constructBall(0x77312B); - renderer.addTarget(ball3); - - // Set some extra layout properties on ball3: since it got - // added to a renderer without any layout properties set, - // it is now defaulting to 100% width and height, letterbox - // scaled, and centering. Let's change this: - ball3.layoutMetadata.percentWidth = 100; - ball3.layoutMetadata.percentHeight = 50; - ball3.layoutMetadata.scaleMode = ScaleMode.STRETCH; - - // Construct a layout target sprite that the renderer - // can use as its container: - var container:LayoutTargetSprite = new LayoutTargetSprite(); - container.width = 640; - container.height = 360; - renderer.container = container; - addChild(container); - - // Set the container to operate in VERTICAL layoutMode: - container.layoutMetadata.layoutMode = LayoutMode.VERTICAL; - container.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - - // Add a child container/renderer pair, and add targets - // to it too: - var renderer2:LayoutRenderer = new LayoutRenderer(); - renderer2.addTarget(constructBall(0x1C2331)); - renderer2.addTarget(constructBall(0x152C52)); - - var container2:LayoutTargetSprite = new LayoutTargetSprite(); - container2.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; - container2.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; - // By default, items appear in the order that they were added to - // the renderer. By setting an we override the order: - container2.layoutMetadata.index = -1; - renderer2.container = container2; - renderer.addTarget(container2); - - } - - private function constructBall(color:uint):LayoutTargetSprite - { - // Construct a layout target sprite (a Sprite that implements - // the ILayoutTarget interface): - var result:LayoutTargetSprite = new LayoutTargetSprite(); - - // Draw a circle: - result.graphics.beginFill(color); - result.graphics.drawCircle(100,100,100); - result.graphics.endFill(); - - return result; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package +{ + import flash.display.Sprite; + + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.LayoutRenderer; + import org.osmf.layout.LayoutTargetSprite; + import org.osmf.layout.ScaleMode; + + [SWF(backgroundColor="0x000000", frameRate="25", width="640", height="360")] + public class LayoutSample3 extends Sprite + { + public function LayoutSample3() + { + // Construct a layout renderer: + var renderer:LayoutRenderer = new LayoutRenderer(); + + // Add some targets to the renderer: + renderer.addTarget(constructBall(0xC89B41)); + renderer.addTarget(constructBall(0xA16B2B)); + var ball3:LayoutTargetSprite = constructBall(0x77312B); + renderer.addTarget(ball3); + + // Set some extra layout properties on ball3: since it got + // added to a renderer without any layout properties set, + // it is now defaulting to 100% width and height, letterbox + // scaled, and centering. Let's change this: + ball3.layoutMetadata.percentWidth = 100; + ball3.layoutMetadata.percentHeight = 50; + ball3.layoutMetadata.scaleMode = ScaleMode.STRETCH; + + // Construct a layout target sprite that the renderer + // can use as its container: + var container:LayoutTargetSprite = new LayoutTargetSprite(); + container.width = 640; + container.height = 360; + renderer.container = container; + addChild(container); + + // Set the container to operate in VERTICAL layoutMode: + container.layoutMetadata.layoutMode = LayoutMode.VERTICAL; + container.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + + // Add a child container/renderer pair, and add targets + // to it too: + var renderer2:LayoutRenderer = new LayoutRenderer(); + renderer2.addTarget(constructBall(0x1C2331)); + renderer2.addTarget(constructBall(0x152C52)); + + var container2:LayoutTargetSprite = new LayoutTargetSprite(); + container2.layoutMetadata.layoutMode = LayoutMode.HORIZONTAL; + container2.layoutMetadata.horizontalAlign = HorizontalAlign.CENTER; + // By default, items appear in the order that they were added to + // the renderer. By setting an we override the order: + container2.layoutMetadata.index = -1; + renderer2.container = container2; + renderer.addTarget(container2); + + } + + private function constructBall(color:uint):LayoutTargetSprite + { + // Construct a layout target sprite (a Sprite that implements + // the ILayoutTarget interface): + var result:LayoutTargetSprite = new LayoutTargetSprite(); + + // Draw a circle: + result.graphics.beginFill(color); + result.graphics.drawCircle(100,100,100); + result.graphics.endFill(); + + return result; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/LayoutSample/src/LayoutSample4.as b/lib/osmf/samples/LayoutSample/src/LayoutSample4.as index 23fdff5..005b038 100644 --- a/lib/osmf/samples/LayoutSample/src/LayoutSample4.as +++ b/lib/osmf/samples/LayoutSample/src/LayoutSample4.as @@ -1,87 +1,87 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package -{ - import flash.display.Sprite; - - import org.osmf.layout.LayoutMode; - import org.osmf.layout.LayoutRenderer; - import org.osmf.layout.LayoutTargetSprite; - - [SWF(backgroundColor="0xC0C0C0", frameRate="25", width="640", height="360")] - public class LayoutSample4 extends Sprite - { - public function LayoutSample4() - { - // Construct a layout renderer: - var renderer:LayoutRenderer = new LayoutRenderer(); - - // Construct a red, green and blue ball: - var ball1:LayoutTargetSprite = createBall(0xeeddee); - var ball2:LayoutTargetSprite = createBall(0xccff00); - var ball3:LayoutTargetSprite = createBall(0xff0000); - var ball4:LayoutTargetSprite = createBall(0x333333); - - // Add each ball as a target to the renderer: - renderer.addTarget(ball1); - renderer.addTarget(ball2); - renderer.addTarget(ball3); - renderer.addTarget(ball4); - - // Construct a layout target sprite that the renderer - // can use as its container: - var container:LayoutTargetSprite - = new LayoutTargetSprite(); - renderer.container = container; - addChild(container); - - // Set the container to operate in VERTICAL layoutMode: - container.layoutMetadata.layoutMode = LayoutMode.NONE; - } - - private function createBall(color:uint):LayoutTargetSprite - { - // Construct a layout target sprite (a Sprite that implements - // the ILayoutTarget interface): - var result:LayoutTargetSprite = new LayoutTargetSprite(); - - // Draw a circle: - result.graphics.beginFill(color); - result.graphics.drawCircle(50,50,50); - result.graphics.endFill(); - - // Inform the layout system that this layout target is a - // 100x100 pixels in size: - result.layoutMetadata.width = 100; - result.layoutMetadata.height = 100; - - // Derive from color the RED component of the color - // and index from the GREEN component - result.layoutMetadata.percentX = (((color & 0xff0000) >> 16) / 255) * 100; - result.layoutMetadata.percentY = ((color & 0x0000ff) / 255) * 100; - result.layoutMetadata.index = (((color & 0x00ff00) >> 8) / 255) * 100; - - return result; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package +{ + import flash.display.Sprite; + + import org.osmf.layout.LayoutMode; + import org.osmf.layout.LayoutRenderer; + import org.osmf.layout.LayoutTargetSprite; + + [SWF(backgroundColor="0xC0C0C0", frameRate="25", width="640", height="360")] + public class LayoutSample4 extends Sprite + { + public function LayoutSample4() + { + // Construct a layout renderer: + var renderer:LayoutRenderer = new LayoutRenderer(); + + // Construct a red, green and blue ball: + var ball1:LayoutTargetSprite = createBall(0xeeddee); + var ball2:LayoutTargetSprite = createBall(0xccff00); + var ball3:LayoutTargetSprite = createBall(0xff0000); + var ball4:LayoutTargetSprite = createBall(0x333333); + + // Add each ball as a target to the renderer: + renderer.addTarget(ball1); + renderer.addTarget(ball2); + renderer.addTarget(ball3); + renderer.addTarget(ball4); + + // Construct a layout target sprite that the renderer + // can use as its container: + var container:LayoutTargetSprite + = new LayoutTargetSprite(); + renderer.container = container; + addChild(container); + + // Set the container to operate in VERTICAL layoutMode: + container.layoutMetadata.layoutMode = LayoutMode.NONE; + } + + private function createBall(color:uint):LayoutTargetSprite + { + // Construct a layout target sprite (a Sprite that implements + // the ILayoutTarget interface): + var result:LayoutTargetSprite = new LayoutTargetSprite(); + + // Draw a circle: + result.graphics.beginFill(color); + result.graphics.drawCircle(50,50,50); + result.graphics.endFill(); + + // Inform the layout system that this layout target is a + // 100x100 pixels in size: + result.layoutMetadata.width = 100; + result.layoutMetadata.height = 100; + + // Derive from color the RED component of the color + // and index from the GREEN component + result.layoutMetadata.percentX = (((color & 0xff0000) >> 16) / 255) * 100; + result.layoutMetadata.percentY = ((color & 0x0000ff) / 255) * 100; + result.layoutMetadata.index = (((color & 0x00ff00) >> 8) / 255) * 100; + + return result; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/LayoutSample/src/LayoutSample5.as b/lib/osmf/samples/LayoutSample/src/LayoutSample5.as index 1e7e553..f420e80 100644 --- a/lib/osmf/samples/LayoutSample/src/LayoutSample5.as +++ b/lib/osmf/samples/LayoutSample/src/LayoutSample5.as @@ -1,120 +1,120 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package -{ - import flash.display.Sprite; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.ImageElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.VideoElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.ScaleMode; - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - import org.osmf.net.DynamicStreamingResource; - import org.osmf.utils.OSMFSettings; - +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package +{ + import flash.display.Sprite; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.ImageElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.VideoElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.ScaleMode; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + import org.osmf.net.DynamicStreamingResource; + import org.osmf.utils.OSMFSettings; + import spark.layouts.supportClasses.LayoutBase; - - [SWF(backgroundColor="0x000000", frameRate="25", width="640", height="360")] - public class LayoutSample5 extends Sprite - { - public function LayoutSample5() - { - OSMFSettings.enableStageVideo=false; - // Contstruct and image element: - var logo:ImageElement = new ImageElement(new URLResource(LOGO_PNG)); - logo.smoothing = true; - - // Construct a layout properties object for the logo: - var logoLayout:LayoutMetadata = new LayoutMetadata(); - logo.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, logoLayout); - - - logoLayout.x = 5; - logoLayout.paddingBottom=10; - logoLayout.paddingLeft=10; - logoLayout.paddingRight=10; - logoLayout.paddingTop=10; - - - - // Set the image to scale, keeping aspect ratio: - logoLayout.scaleMode = ScaleMode.NONE; - - // Instruct the image to be moved to the right hand side, should - // any surplus horizontal space be available after scaling: - //logoLayout.horizontalAlign = HorizontalAlign.RIGHT; - - - // Construct a video element: - var resource:URLResource = new URLResource(LOGO_VID); - var mediaFactory:MediaFactory = new DefaultMediaFactory(); - var video:MediaElement = mediaFactory.createMediaElement(resource); - - var videoLayout: LayoutMetadata = new LayoutMetadata(); - videoLayout.scaleMode = ScaleMode.LETTERBOX; - videoLayout.bottom=0; - videoLayout.percentHeight=90; - - video.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, videoLayout); - - - - - var parallel:ParallelElement = new ParallelElement(); - - parallel.addChild(video); - parallel.addChild(logo); - - - var parallelLayout:LayoutMetadata = new LayoutMetadata(); - parallel.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, parallelLayout); - parallelLayout.width = stage.stageWidth; - parallelLayout.height = stage.stageHeight; - - - var container:MediaContainer = new MediaContainer() - container.addMediaElement(parallel); - addChild(container); - - var player:MediaPlayer = new MediaPlayer(parallel); - player.loop = true; - - parallelLayout.layoutMode= LayoutMode.NONE; - //videoLayout.index = 10; - } - - private static const LOGO_PNG:String = "http://dl.dropbox.com/u/2980264/OSMF/logo_white.png"; - - private static const LOGO_VID:String = "http://zeridemo-f.akamaihd.net/content/inoutedit-mbr/inoutedit_h264_3000.f4m"; - //private static const LOGO_VID:String = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; - - } -} + + [SWF(backgroundColor="0x000000", frameRate="25", width="640", height="360")] + public class LayoutSample5 extends Sprite + { + public function LayoutSample5() + { + OSMFSettings.enableStageVideo=false; + // Contstruct and image element: + var logo:ImageElement = new ImageElement(new URLResource(LOGO_PNG)); + logo.smoothing = true; + + // Construct a layout properties object for the logo: + var logoLayout:LayoutMetadata = new LayoutMetadata(); + logo.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, logoLayout); + + + logoLayout.x = 5; + logoLayout.paddingBottom=10; + logoLayout.paddingLeft=10; + logoLayout.paddingRight=10; + logoLayout.paddingTop=10; + + + + // Set the image to scale, keeping aspect ratio: + logoLayout.scaleMode = ScaleMode.NONE; + + // Instruct the image to be moved to the right hand side, should + // any surplus horizontal space be available after scaling: + //logoLayout.horizontalAlign = HorizontalAlign.RIGHT; + + + // Construct a video element: + var resource:URLResource = new URLResource(LOGO_VID); + var mediaFactory:MediaFactory = new DefaultMediaFactory(); + var video:MediaElement = mediaFactory.createMediaElement(resource); + + var videoLayout: LayoutMetadata = new LayoutMetadata(); + videoLayout.scaleMode = ScaleMode.LETTERBOX; + videoLayout.bottom=0; + videoLayout.percentHeight=90; + + video.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, videoLayout); + + + + + var parallel:ParallelElement = new ParallelElement(); + + parallel.addChild(video); + parallel.addChild(logo); + + + var parallelLayout:LayoutMetadata = new LayoutMetadata(); + parallel.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, parallelLayout); + parallelLayout.width = stage.stageWidth; + parallelLayout.height = stage.stageHeight; + + + var container:MediaContainer = new MediaContainer() + container.addMediaElement(parallel); + addChild(container); + + var player:MediaPlayer = new MediaPlayer(parallel); + player.loop = true; + + parallelLayout.layoutMode= LayoutMode.NONE; + //videoLayout.index = 10; + } + + private static const LOGO_PNG:String = "http://dl.dropbox.com/u/2980264/OSMF/logo_white.png"; + + private static const LOGO_VID:String = "http://zeridemo-f.akamaihd.net/content/inoutedit-mbr/inoutedit_h264_3000.f4m"; + //private static const LOGO_VID:String = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; + + } +} diff --git a/lib/osmf/samples/LayoutSample/src/LayoutSample6.as b/lib/osmf/samples/LayoutSample/src/LayoutSample6.as index 7e1c4a6..2fc5f9b 100644 --- a/lib/osmf/samples/LayoutSample/src/LayoutSample6.as +++ b/lib/osmf/samples/LayoutSample/src/LayoutSample6.as @@ -1,112 +1,112 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package -{ - import flash.display.Sprite; - import flash.events.TimerEvent; - import flash.geom.PerspectiveProjection; - import flash.utils.Timer; - - import org.osmf.layout.LayoutMode; - import org.osmf.layout.LayoutRenderer; +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package +{ + import flash.display.Sprite; + import flash.events.TimerEvent; + import flash.geom.PerspectiveProjection; + import flash.utils.Timer; + + import org.osmf.layout.LayoutMode; + import org.osmf.layout.LayoutRenderer; import org.osmf.layout.LayoutTargetSprite; - - [SWF(backgroundColor="0xC0C0C0", frameRate="25", width="640", height="360")] - public class LayoutSample6 extends Sprite - { - private var t:Timer; - private var ball1:LayoutTargetSprite; - private var ball2:LayoutTargetSprite; - private var ball3:LayoutTargetSprite; - private var ball4:LayoutTargetSprite; - private var renderer:LayoutRenderer; - - public function LayoutSample6() - { - // Construct a layout renderer: - renderer = new LayoutRenderer(); - - // Construct a red, green and blue ball: - ball1 = createBall(0xeeddee); - ball2 = createBall(0xccff00); - ball3 = createBall(0xff0000); - ball4 = createBall(0x333333); - - // Add each ball as a target to the renderer: - renderer.addTarget(ball1); - renderer.addTarget(ball2); - renderer.addTarget(ball3); - renderer.addTarget(ball4); - - // Construct a layout target sprite that the renderer - // can use as its container: - var container:LayoutTargetSprite - = new LayoutTargetSprite(); - renderer.container = container; - addChild(container); - - // Set the container to operate in VERTICAL layoutMode: - container.layoutMetadata.layoutMode = LayoutMode.NONE; - - - t = new Timer(2500, 0); - t.start(); - t.addEventListener(TimerEvent.TIMER, onTimer); - - } - - private function onTimer(e:TimerEvent):void - { - var tmp:int = ball1.layoutMetadata.index; - ball1.layoutMetadata.index= ball2.layoutMetadata.index ; - ball2.layoutMetadata.index = ball3.layoutMetadata.index ; - ball3.layoutMetadata.index = ball4.layoutMetadata.index ; - ball4.layoutMetadata.index = tmp; - } - - private function createBall(color:uint):LayoutTargetSprite - { - // Construct a layout target sprite (a Sprite that implements - // the ILayoutTarget interface): - var result:LayoutTargetSprite = new LayoutTargetSprite(); - - // Draw a circle: - result.graphics.beginFill(color); - result.graphics.drawCircle(50,50,50); - result.graphics.endFill(); - - // Inform the layout system that this layout target is a - // 100x100 pixels in size: - result.layoutMetadata.width = 100; - result.layoutMetadata.height = 100; - - // Derive from color the RED component of the color - // and index from the GREEN component - result.layoutMetadata.percentX = (((color & 0xff0000) >> 16) / 255) * 100; - result.layoutMetadata.percentY = ((color & 0x0000ff) / 255) * 100; - result.layoutMetadata.index = (((color & 0x00ff00) >> 8) / 255) * 100; - - return result; - } - } + + [SWF(backgroundColor="0xC0C0C0", frameRate="25", width="640", height="360")] + public class LayoutSample6 extends Sprite + { + private var t:Timer; + private var ball1:LayoutTargetSprite; + private var ball2:LayoutTargetSprite; + private var ball3:LayoutTargetSprite; + private var ball4:LayoutTargetSprite; + private var renderer:LayoutRenderer; + + public function LayoutSample6() + { + // Construct a layout renderer: + renderer = new LayoutRenderer(); + + // Construct a red, green and blue ball: + ball1 = createBall(0xeeddee); + ball2 = createBall(0xccff00); + ball3 = createBall(0xff0000); + ball4 = createBall(0x333333); + + // Add each ball as a target to the renderer: + renderer.addTarget(ball1); + renderer.addTarget(ball2); + renderer.addTarget(ball3); + renderer.addTarget(ball4); + + // Construct a layout target sprite that the renderer + // can use as its container: + var container:LayoutTargetSprite + = new LayoutTargetSprite(); + renderer.container = container; + addChild(container); + + // Set the container to operate in VERTICAL layoutMode: + container.layoutMetadata.layoutMode = LayoutMode.NONE; + + + t = new Timer(2500, 0); + t.start(); + t.addEventListener(TimerEvent.TIMER, onTimer); + + } + + private function onTimer(e:TimerEvent):void + { + var tmp:int = ball1.layoutMetadata.index; + ball1.layoutMetadata.index= ball2.layoutMetadata.index ; + ball2.layoutMetadata.index = ball3.layoutMetadata.index ; + ball3.layoutMetadata.index = ball4.layoutMetadata.index ; + ball4.layoutMetadata.index = tmp; + } + + private function createBall(color:uint):LayoutTargetSprite + { + // Construct a layout target sprite (a Sprite that implements + // the ILayoutTarget interface): + var result:LayoutTargetSprite = new LayoutTargetSprite(); + + // Draw a circle: + result.graphics.beginFill(color); + result.graphics.drawCircle(50,50,50); + result.graphics.endFill(); + + // Inform the layout system that this layout target is a + // 100x100 pixels in size: + result.layoutMetadata.width = 100; + result.layoutMetadata.height = 100; + + // Derive from color the RED component of the color + // and index from the GREEN component + result.layoutMetadata.percentX = (((color & 0xff0000) >> 16) / 255) * 100; + result.layoutMetadata.percentY = ((color & 0x0000ff) / 255) * 100; + result.layoutMetadata.index = (((color & 0x00ff00) >> 8) / 255) * 100; + + return result; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/LayoutSample/src/LayoutSample7.as b/lib/osmf/samples/LayoutSample/src/LayoutSample7.as index e10e0e6..13c4541 100644 --- a/lib/osmf/samples/LayoutSample/src/LayoutSample7.as +++ b/lib/osmf/samples/LayoutSample/src/LayoutSample7.as @@ -1,120 +1,120 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package -{ - import flash.display.Sprite; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.ImageElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.VideoElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.ScaleMode; - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - import org.osmf.net.DynamicStreamingResource; - import org.osmf.utils.OSMFSettings; - +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package +{ + import flash.display.Sprite; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.ImageElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.VideoElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutMode; + import org.osmf.layout.ScaleMode; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + import org.osmf.net.DynamicStreamingResource; + import org.osmf.utils.OSMFSettings; + import spark.layouts.supportClasses.LayoutBase; - - [SWF(backgroundColor="0x000000", frameRate="25", width="640", height="360")] - public class LayoutSample7 extends Sprite - { - public function LayoutSample7() - { - OSMFSettings.enableStageVideo=false; - // Contstruct and image element: - var logo:ImageElement = new ImageElement(new URLResource(LOGO_PNG)); - logo.smoothing = true; - - // Construct a layout properties object for the logo: - var logoLayout:LayoutMetadata = new LayoutMetadata(); - logo.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, logoLayout); - - logoLayout.x = 5; - logoLayout.paddingBottom=10; - logoLayout.paddingLeft=10; - logoLayout.paddingRight=10; - logoLayout.paddingTop=10; - - // Set the image to scale, keeping aspect ratio: - logoLayout.scaleMode = ScaleMode.NONE; - - // Instruct the image to be moved to the right hand side, should - // any surplus horizontal space be available after scaling: - //logoLayout.horizontalAlign = HorizontalAlign.RIGHT; - - - // Construct a video element: - var resource:URLResource = new URLResource(LOGO_VID); - var mediaFactory:MediaFactory = new DefaultMediaFactory(); - var video:MediaElement = mediaFactory.createMediaElement(resource); - - var videoLayout: LayoutMetadata = new LayoutMetadata(); - videoLayout.scaleMode = ScaleMode.LETTERBOX; - videoLayout.bottom=10; - videoLayout.percentHeight=80; - videoLayout.percentWidth=80; - videoLayout.horizontalAlign = HorizontalAlign.RIGHT; - - video.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, videoLayout); - - - - - var parallel:ParallelElement = new ParallelElement(); - - parallel.addChild(video); - parallel.addChild(logo); - - - var parallelLayout:LayoutMetadata = new LayoutMetadata(); - parallel.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, parallelLayout); - parallelLayout.width = stage.stageWidth; - parallelLayout.height = stage.stageHeight; - - - var container:MediaContainer = new MediaContainer() - container.addMediaElement(parallel); - addChild(container); - - var player:MediaPlayer = new MediaPlayer(parallel); - player.loop = true; - - parallelLayout.layoutMode= LayoutMode.NONE; - - //videoLayout.index = 10; - } - - private static const LOGO_PNG:String = "http://dl.dropbox.com/u/2980264/OSMF/logo_white.png"; - - private static const LOGO_VID:String = "http://zeridemo-f.akamaihd.net/content/inoutedit-mbr/inoutedit_h264_3000.f4m"; - //private static const LOGO_VID:String = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; - - } -} + + [SWF(backgroundColor="0x000000", frameRate="25", width="640", height="360")] + public class LayoutSample7 extends Sprite + { + public function LayoutSample7() + { + OSMFSettings.enableStageVideo=false; + // Contstruct and image element: + var logo:ImageElement = new ImageElement(new URLResource(LOGO_PNG)); + logo.smoothing = true; + + // Construct a layout properties object for the logo: + var logoLayout:LayoutMetadata = new LayoutMetadata(); + logo.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, logoLayout); + + logoLayout.x = 5; + logoLayout.paddingBottom=10; + logoLayout.paddingLeft=10; + logoLayout.paddingRight=10; + logoLayout.paddingTop=10; + + // Set the image to scale, keeping aspect ratio: + logoLayout.scaleMode = ScaleMode.NONE; + + // Instruct the image to be moved to the right hand side, should + // any surplus horizontal space be available after scaling: + //logoLayout.horizontalAlign = HorizontalAlign.RIGHT; + + + // Construct a video element: + var resource:URLResource = new URLResource(LOGO_VID); + var mediaFactory:MediaFactory = new DefaultMediaFactory(); + var video:MediaElement = mediaFactory.createMediaElement(resource); + + var videoLayout: LayoutMetadata = new LayoutMetadata(); + videoLayout.scaleMode = ScaleMode.LETTERBOX; + videoLayout.bottom=10; + videoLayout.percentHeight=80; + videoLayout.percentWidth=80; + videoLayout.horizontalAlign = HorizontalAlign.RIGHT; + + video.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, videoLayout); + + + + + var parallel:ParallelElement = new ParallelElement(); + + parallel.addChild(video); + parallel.addChild(logo); + + + var parallelLayout:LayoutMetadata = new LayoutMetadata(); + parallel.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, parallelLayout); + parallelLayout.width = stage.stageWidth; + parallelLayout.height = stage.stageHeight; + + + var container:MediaContainer = new MediaContainer() + container.addMediaElement(parallel); + addChild(container); + + var player:MediaPlayer = new MediaPlayer(parallel); + player.loop = true; + + parallelLayout.layoutMode= LayoutMode.NONE; + + //videoLayout.index = 10; + } + + private static const LOGO_PNG:String = "http://dl.dropbox.com/u/2980264/OSMF/logo_white.png"; + + private static const LOGO_VID:String = "http://zeridemo-f.akamaihd.net/content/inoutedit-mbr/inoutedit_h264_3000.f4m"; + //private static const LOGO_VID:String = "http://mediapm.edgesuite.net/osmf/content/test/logo_animated.flv"; + + } +} diff --git a/lib/osmf/samples/LayoutSample/src/publish_settings.xml b/lib/osmf/samples/LayoutSample/src/publish_settings.xml index b378b71..2bf8666 100644 --- a/lib/osmf/samples/LayoutSample/src/publish_settings.xml +++ b/lib/osmf/samples/LayoutSample/src/publish_settings.xml @@ -1,180 +1,180 @@ - - - - 1 - 1 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - LayoutSample.swf - LayoutSample.swt - LayoutSample.exe - LayoutSample.app - LayoutSample.html - LayoutSample.gif - LayoutSample.jpg - LayoutSample.png - LayoutSample.mov - LayoutSample.smil - - - 0 - 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; - 1 - 1 - LayoutSample_content.html - LayoutSample_alternate.html - 0 - - 640 - 360 - 0 - 0 - 0 - 0 - 3 - 1 - 1 - 4 - 0 - 0 - 1 - 0 - /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html - 1 - - - - - 0 - 0 - 0 - 80 - 0 - 0 - 7 - 0 - 7 - 0 - 10 - FlashPlayer10 - 3 - 1 - - .;../../../../libs/ChromeLibrary;../../../../framework/OSMF;./src - $(AppConfig)/ActionScript 3.0/libs - . - CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; - 0 - - 1 - 1 - 0 - 0 - 0 - 0 - LayoutSample - 1 - 1 - 1 - AS3 - 1 - 1 - 0 - 15 - 1 - 0 - - - 640 - 360 - 0 - 4718592 - 0 - 80 - 1 - - - 1 - 0 - 1 - 0 - 0 - 100000 - 1 - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 1 - - - 640 - 360 - 0 - 1 - 1 - - 1 - 0 - 1 - 0 - 0 - - 128 - - - 255 - - - - 640 - 360 - 1 - 0 - 0 - 1 - 0 - 0 - 1 - - - - 24-bit with Alpha - 255 - - - - 640 - 360 - 1 - 0 - - - 00000000 - 0 - 0 - 0 - 0 - 1 - - + + + + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + LayoutSample.swf + LayoutSample.swt + LayoutSample.exe + LayoutSample.app + LayoutSample.html + LayoutSample.gif + LayoutSample.jpg + LayoutSample.png + LayoutSample.mov + LayoutSample.smil + + + 0 + 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + LayoutSample_content.html + LayoutSample_alternate.html + 0 + + 640 + 360 + 0 + 0 + 0 + 0 + 3 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 10 + FlashPlayer10 + 3 + 1 + + .;../../../../libs/ChromeLibrary;../../../../framework/OSMF;./src + $(AppConfig)/ActionScript 3.0/libs + . + CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; + 0 + + 1 + 1 + 0 + 0 + 0 + 0 + LayoutSample + 1 + 1 + 1 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + + + 640 + 360 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 640 + 360 + 0 + 1 + 1 + + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 640 + 360 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 640 + 360 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + diff --git a/lib/osmf/samples/MASTPlugin/.actionScriptProperties b/lib/osmf/samples/MASTPlugin/.actionScriptProperties index 26d34df..f357816 100644 --- a/lib/osmf/samples/MASTPlugin/.actionScriptProperties +++ b/lib/osmf/samples/MASTPlugin/.actionScriptProperties @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MASTPlugin/MASTPlugin-build-config.xml b/lib/osmf/samples/MASTPlugin/MASTPlugin-build-config.xml index 7fce189..d1906c7 100644 --- a/lib/osmf/samples/MASTPlugin/MASTPlugin-build-config.xml +++ b/lib/osmf/samples/MASTPlugin/MASTPlugin-build-config.xml @@ -25,8 +25,8 @@ - @@ -40,10 +40,10 @@ false - @@ -106,11 +106,11 @@ - @@ -118,8 +118,8 @@ - @@ -138,13 +138,13 @@ - @@ -154,12 +154,12 @@ flash.fonts.BatikFontManager - @@ -283,19 +283,19 @@ - - - @@ -309,8 +309,8 @@ true - diff --git a/lib/osmf/samples/MASTPlugin/readme.txt b/lib/osmf/samples/MASTPlugin/readme.txt index 8aa883a..5546394 100644 --- a/lib/osmf/samples/MASTPlugin/readme.txt +++ b/lib/osmf/samples/MASTPlugin/readme.txt @@ -1,3 +1,3 @@ -The MASTPlugin project is a plugin that adds support for MAST, and which integrates with the VAST plugin (which supports VAST 1.0). It will eventually be deprecated in favor of MASTPluginNew. - -The MASTPluginNew project is a newer implementation which integrates with the VASTNew library (which in turn provides support for VAST 1.0 and VAST 2.0). +The MASTPlugin project is a plugin that adds support for MAST, and which integrates with the VAST plugin (which supports VAST 1.0). It will eventually be deprecated in favor of MASTPluginNew. + +The MASTPluginNew project is a newer implementation which integrates with the VASTNew library (which in turn provides support for VAST 1.0 and VAST 2.0). diff --git a/lib/osmf/samples/MASTPlugin/src/MASTPlugin.as b/lib/osmf/samples/MASTPlugin/src/MASTPlugin.as index 9ef2c36..586bedf 100644 --- a/lib/osmf/samples/MASTPlugin/src/MASTPlugin.as +++ b/lib/osmf/samples/MASTPlugin/src/MASTPlugin.as @@ -1,57 +1,57 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - import flash.system.Security; - - import org.osmf.mast.MASTPluginInfo; - import org.osmf.media.PluginInfo; - - /** - * The root level object of the MAST plugin. - */ - public class MASTPlugin extends Sprite - { - /** - * Constructor. - */ - public function MASTPlugin() - { - // Allow any SWF that loads this SWF to access objects and - // variables in this SWF. - Security.allowDomain(this.root.loaderInfo.loaderURL); - - _pluginInfo = new MASTPluginInfo(); - } - - /** - * Gives the player the PluginInfo. - */ - public function get pluginInfo():PluginInfo - { - return _pluginInfo; - } - - private var _pluginInfo:MASTPluginInfo; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + import flash.system.Security; + + import org.osmf.mast.MASTPluginInfo; + import org.osmf.media.PluginInfo; + + /** + * The root level object of the MAST plugin. + */ + public class MASTPlugin extends Sprite + { + /** + * Constructor. + */ + public function MASTPlugin() + { + // Allow any SWF that loads this SWF to access objects and + // variables in this SWF. + Security.allowDomain(this.root.loaderInfo.loaderURL); + + _pluginInfo = new MASTPluginInfo(); + } + + /** + * Gives the player the PluginInfo. + */ + public function get pluginInfo():PluginInfo + { + return _pluginInfo; + } + + private var _pluginInfo:MASTPluginInfo; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/MASTPluginInfo.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/MASTPluginInfo.as index 5087d14..a8558f3 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/MASTPluginInfo.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/MASTPluginInfo.as @@ -1,98 +1,98 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Eyewonder, LLC -* -*****************************************************/ -package org.osmf.mast -{ - import __AS3__.vec.Vector; - - import org.osmf.elements.F4MLoader; - import org.osmf.mast.media.MASTProxyElement; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.MediaFactoryItemType; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.PluginInfo; - import org.osmf.metadata.Metadata; +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Eyewonder, LLC +* +*****************************************************/ +package org.osmf.mast +{ + import __AS3__.vec.Vector; + + import org.osmf.elements.F4MLoader; + import org.osmf.mast.media.MASTProxyElement; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.MediaFactoryItemType; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.PluginInfo; + import org.osmf.metadata.Metadata; import org.osmf.net.NetLoader; - - /** - * Encapsulation of a MAST plugin. - **/ - public class MASTPluginInfo extends PluginInfo - { - // Constants for specifying the MAST document URL on the resource metadata - public static const MAST_METADATA_NAMESPACE:String = "http://www.akamai.com/mast/1.0"; - public static const MAST_METADATA_KEY_URI:String = "uri"; - - /** - * Constructor. - */ - public function MASTPluginInfo() - { - var items:Vector. = new Vector.(); - - loader = new NetLoader(); - var item:MediaFactoryItem = new MediaFactoryItem - ( "org.osmf.mast.MASTPluginInfo" - , canHandleResource - , createMASTProxyElement - , MediaFactoryItemType.PROXY - ); - items.push(item); - - f4mLoader = new F4MLoader(); - - super(items); - } - - private function canHandleResource(resource:MediaResourceBase):Boolean - { - // We only handle the resource if it has MAST metadata. - var metadata:Metadata = resource.getMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE) as Metadata; - return metadata != null - && metadata.getValue(MASTPluginInfo.MAST_METADATA_KEY_URI) != null - && ( loader.canHandleResource(resource) - || f4mLoader.canHandleResource(resource) - || mediaFactory.getItemById(SMIL_PLUGIN_ID) != null - ); - } - - private function createMASTProxyElement():MediaElement - { - return new MASTProxyElement(null, mediaFactory); - } - - override public function initializePlugin(resource:MediaResourceBase):void - { - // We'll use the player-supplied MediaFactory for creating all MediaElements. - mediaFactory = resource.getMetadataValue(PluginInfo.PLUGIN_MEDIAFACTORY_NAMESPACE) as MediaFactory; - } - - private var loader:NetLoader; - private var f4mLoader:F4MLoader; - private var mediaFactory:MediaFactory; - - private static const SMIL_PLUGIN_ID:String = "org.osmf.smil.SMILPluginInfo"; - } -} + + /** + * Encapsulation of a MAST plugin. + **/ + public class MASTPluginInfo extends PluginInfo + { + // Constants for specifying the MAST document URL on the resource metadata + public static const MAST_METADATA_NAMESPACE:String = "http://www.akamai.com/mast/1.0"; + public static const MAST_METADATA_KEY_URI:String = "uri"; + + /** + * Constructor. + */ + public function MASTPluginInfo() + { + var items:Vector. = new Vector.(); + + loader = new NetLoader(); + var item:MediaFactoryItem = new MediaFactoryItem + ( "org.osmf.mast.MASTPluginInfo" + , canHandleResource + , createMASTProxyElement + , MediaFactoryItemType.PROXY + ); + items.push(item); + + f4mLoader = new F4MLoader(); + + super(items); + } + + private function canHandleResource(resource:MediaResourceBase):Boolean + { + // We only handle the resource if it has MAST metadata. + var metadata:Metadata = resource.getMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE) as Metadata; + return metadata != null + && metadata.getValue(MASTPluginInfo.MAST_METADATA_KEY_URI) != null + && ( loader.canHandleResource(resource) + || f4mLoader.canHandleResource(resource) + || mediaFactory.getItemById(SMIL_PLUGIN_ID) != null + ); + } + + private function createMASTProxyElement():MediaElement + { + return new MASTProxyElement(null, mediaFactory); + } + + override public function initializePlugin(resource:MediaResourceBase):void + { + // We'll use the player-supplied MediaFactory for creating all MediaElements. + mediaFactory = resource.getMetadataValue(PluginInfo.PLUGIN_MEDIAFACTORY_NAMESPACE) as MediaFactory; + } + + private var loader:NetLoader; + private var f4mLoader:F4MLoader; + private var mediaFactory:MediaFactory; + + private static const SMIL_PLUGIN_ID:String = "org.osmf.smil.SMILPluginInfo"; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/adapter/MASTAdapter.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/adapter/MASTAdapter.as index a005501..a5cfb2c 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/adapter/MASTAdapter.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/adapter/MASTAdapter.as @@ -1,157 +1,157 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.mast.adapter -{ - import flash.utils.Dictionary; - - /** - * The purpose of this class is to map the OSMF - * properties and events to the MAST properties - * and events. - */ - public class MASTAdapter - { - // Properties - - /** - * The duration of the current content. - */ - public static const DURATION:String = "duration"; - - /** - * The playhead postion of the current content. - */ - public static const POSITION:String = "position"; - - /** - * True if the content is currently rendering in fullscreen mode. - */ - public static const FULLSCREEN:String = "fullScreen"; - - /** - * True if the content is currently playing. - */ - public static const IS_PLAYING:String = "isPlaying"; - - /** - * True if the content is currently paused. - */ - public static const IS_PAUSED:String = "isPaused"; - - /** - * The native width of the current content. - */ - public static const CONTENT_WIDTH:String = "contentWidth"; - - /** - * The native height of the current content. - */ - public static const CONTENT_HEIGHT:String = "contentHeight"; - - // events - - /** - * Defined as anytime the play command is issued, even after a pause - */ - public static const ON_PLAY:String = "OnPlay"; - - /** - * The stop command is given - */ - public static const ON_STOP:String = "OnStop"; - - /** - * The pause command is given - */ - public static const ON_PAUSE:String = "OnPause"; - - /** - * The player was muted - */ - public static const ON_MUTE:String = "OnMute"; - - /** - * Volume was changed - */ - public static const ON_VOLUME_CHANGE:String = "OnVolumeChange"; - - /** - * The player has stopped naturally, with no new content - */ - public static const ON_END:String = "OnEnd"; - - /** - * The player was manually seeked - */ - public static const ON_SEEK:String = "OnSeek"; - - /** - * A new item is being started - */ - public static const ON_ITEM_START:String = "OnItemStart"; - - /** - * An item has ended - */ - public static const ON_ITEM_END:String = "OnItemEnd"; - - /** - * Constructor. - */ - public function MASTAdapter() - { - _map = new Dictionary(); - - // Properties - _map[DURATION] = "TimeTrait.duration"; - _map[POSITION] = "TimeTrait.currentTime"; - _map[IS_PLAYING] = "PlayTrait.playState"; - _map[IS_PAUSED] = "PlayTrait.playState"; - _map[CONTENT_WIDTH] = "DisplayObjectTrait.mediaWidth"; - _map[CONTENT_HEIGHT]= "DisplayObjectTrait.mediaHeight"; - - // Events - _map[ON_PLAY] = "org.osmf.events.PlayEvent.PLAY_STATE_CHANGE"; - _map[ON_STOP] = "org.osmf.events.PlayEvent.PLAY_STATE_CHANGE"; - _map[ON_PAUSE] = "org.osmf.events.PlayEvent.PLAY_STATE_CHANGE"; - _map[ON_MUTE] = "org.osmf.events.AudioEvent.MUTED_CHANGE"; - _map[ON_VOLUME_CHANGE] = "org.osmf.events.AudioEvent.VOLUME_CHANGE"; - _map[ON_SEEK] = "org.osmf.events.SeekEvent.SEEKING_CHANGE"; - _map[ON_ITEM_START] = "org.osmf.events.PlayEvent.PLAY_STATE_CHANGE"; - _map[ON_ITEM_END] = "org.osmf.events.TimeEvent.DURATION_REACHED"; - } - - /** - * Given one of the MAST property or event names, - * returns the matching OSMF trait or event respectively. - * - * @param conditionName The MAST condition name which maps - * to OSMF trait or event name. - */ - public function lookup(conditionName:String):String - { - return _map[conditionName]; - } - - private var _map:Dictionary; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.mast.adapter +{ + import flash.utils.Dictionary; + + /** + * The purpose of this class is to map the OSMF + * properties and events to the MAST properties + * and events. + */ + public class MASTAdapter + { + // Properties + + /** + * The duration of the current content. + */ + public static const DURATION:String = "duration"; + + /** + * The playhead postion of the current content. + */ + public static const POSITION:String = "position"; + + /** + * True if the content is currently rendering in fullscreen mode. + */ + public static const FULLSCREEN:String = "fullScreen"; + + /** + * True if the content is currently playing. + */ + public static const IS_PLAYING:String = "isPlaying"; + + /** + * True if the content is currently paused. + */ + public static const IS_PAUSED:String = "isPaused"; + + /** + * The native width of the current content. + */ + public static const CONTENT_WIDTH:String = "contentWidth"; + + /** + * The native height of the current content. + */ + public static const CONTENT_HEIGHT:String = "contentHeight"; + + // events + + /** + * Defined as anytime the play command is issued, even after a pause + */ + public static const ON_PLAY:String = "OnPlay"; + + /** + * The stop command is given + */ + public static const ON_STOP:String = "OnStop"; + + /** + * The pause command is given + */ + public static const ON_PAUSE:String = "OnPause"; + + /** + * The player was muted + */ + public static const ON_MUTE:String = "OnMute"; + + /** + * Volume was changed + */ + public static const ON_VOLUME_CHANGE:String = "OnVolumeChange"; + + /** + * The player has stopped naturally, with no new content + */ + public static const ON_END:String = "OnEnd"; + + /** + * The player was manually seeked + */ + public static const ON_SEEK:String = "OnSeek"; + + /** + * A new item is being started + */ + public static const ON_ITEM_START:String = "OnItemStart"; + + /** + * An item has ended + */ + public static const ON_ITEM_END:String = "OnItemEnd"; + + /** + * Constructor. + */ + public function MASTAdapter() + { + _map = new Dictionary(); + + // Properties + _map[DURATION] = "TimeTrait.duration"; + _map[POSITION] = "TimeTrait.currentTime"; + _map[IS_PLAYING] = "PlayTrait.playState"; + _map[IS_PAUSED] = "PlayTrait.playState"; + _map[CONTENT_WIDTH] = "DisplayObjectTrait.mediaWidth"; + _map[CONTENT_HEIGHT]= "DisplayObjectTrait.mediaHeight"; + + // Events + _map[ON_PLAY] = "org.osmf.events.PlayEvent.PLAY_STATE_CHANGE"; + _map[ON_STOP] = "org.osmf.events.PlayEvent.PLAY_STATE_CHANGE"; + _map[ON_PAUSE] = "org.osmf.events.PlayEvent.PLAY_STATE_CHANGE"; + _map[ON_MUTE] = "org.osmf.events.AudioEvent.MUTED_CHANGE"; + _map[ON_VOLUME_CHANGE] = "org.osmf.events.AudioEvent.VOLUME_CHANGE"; + _map[ON_SEEK] = "org.osmf.events.SeekEvent.SEEKING_CHANGE"; + _map[ON_ITEM_START] = "org.osmf.events.PlayEvent.PLAY_STATE_CHANGE"; + _map[ON_ITEM_END] = "org.osmf.events.TimeEvent.DURATION_REACHED"; + } + + /** + * Given one of the MAST property or event names, + * returns the matching OSMF trait or event respectively. + * + * @param conditionName The MAST condition name which maps + * to OSMF trait or event name. + */ + public function lookup(conditionName:String):String + { + return _map[conditionName]; + } + + private var _map:Dictionary; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTDocumentProcessedEvent.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTDocumentProcessedEvent.as index fe01685..1143378 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTDocumentProcessedEvent.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTDocumentProcessedEvent.as @@ -1,85 +1,85 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* -*****************************************************/ -package org.osmf.mast.loader -{ - import __AS3__.vec.Vector; - - import flash.events.Event; - - import org.osmf.mast.model.MASTCondition; - import org.osmf.media.MediaElement; - - /** - * This event is dispatched when a MAST payload has been loaded. It - * contains a Vector of MediaElements that were loaded from the payload - * and the MASTCondition object that caused the payload to be loaded. - */ - public class MASTDocumentProcessedEvent extends Event - { - public static const PROCESSED:String = "processed"; - - /** - * Constructor. - * - * @param inlineElements A Vector of MediaElements loaded from the payload. - * @param condition The MASTCondition object that caused the payload to be loaded. - */ - public function MASTDocumentProcessedEvent(inlineElements:Vector., condition:MASTCondition, - bubbles:Boolean=false, cancelable:Boolean=false) - { - super(PROCESSED, bubbles, cancelable); - - _inlineElements = inlineElements; - _condition = condition; - } - - /** - * The MediaElements loaded from the MAST paylod. - */ - public function get inlineElements():Vector. - { - return _inlineElements; - } - - /** - * The MASTCondition object that caused the payload to be - * loaded. - */ - public function get condition():MASTCondition - { - return _condition; - } - - /** - * @inheritdoc - */ - override public function clone():Event - { - return new MASTDocumentProcessedEvent(_inlineElements, _condition, bubbles, cancelable); - } - - private var _inlineElements:Vector.; - private var _condition:MASTCondition; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* +*****************************************************/ +package org.osmf.mast.loader +{ + import __AS3__.vec.Vector; + + import flash.events.Event; + + import org.osmf.mast.model.MASTCondition; + import org.osmf.media.MediaElement; + + /** + * This event is dispatched when a MAST payload has been loaded. It + * contains a Vector of MediaElements that were loaded from the payload + * and the MASTCondition object that caused the payload to be loaded. + */ + public class MASTDocumentProcessedEvent extends Event + { + public static const PROCESSED:String = "processed"; + + /** + * Constructor. + * + * @param inlineElements A Vector of MediaElements loaded from the payload. + * @param condition The MASTCondition object that caused the payload to be loaded. + */ + public function MASTDocumentProcessedEvent(inlineElements:Vector., condition:MASTCondition, + bubbles:Boolean=false, cancelable:Boolean=false) + { + super(PROCESSED, bubbles, cancelable); + + _inlineElements = inlineElements; + _condition = condition; + } + + /** + * The MediaElements loaded from the MAST paylod. + */ + public function get inlineElements():Vector. + { + return _inlineElements; + } + + /** + * The MASTCondition object that caused the payload to be + * loaded. + */ + public function get condition():MASTCondition + { + return _condition; + } + + /** + * @inheritdoc + */ + override public function clone():Event + { + return new MASTDocumentProcessedEvent(_inlineElements, _condition, bubbles, cancelable); + } + + private var _inlineElements:Vector.; + private var _condition:MASTCondition; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTDocumentProcessor.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTDocumentProcessor.as index 7595bb2..c61d883 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTDocumentProcessor.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTDocumentProcessor.as @@ -1,189 +1,189 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* Eyewonder, LLC -* -*****************************************************/ -package org.osmf.mast.loader -{ - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.errors.IllegalOperationError; - import org.osmf.events.LoadEvent; - import org.osmf.mast.managers.MASTConditionManager; - import org.osmf.mast.model.*; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.URLResource; - import org.osmf.traits.LoadState; - import org.osmf.vast.loader.VASTLoadTrait; - import org.osmf.vast.loader.VASTLoader; - import org.osmf.vast.media.DefaultVASTMediaFileResolver; - import org.osmf.vast.media.IVASTMediaFileResolver; - import org.osmf.vast.media.VASTMediaGenerator; - import org.osmf.metadata.Metadata; - import org.osmf.media.MediaResourceBase; - - /** - * This class process a MAST document by working with the - * objects in the MAST object model. - * - * @see org.osmf.mast.model.MASTDocument - */ - public class MASTDocumentProcessor extends EventDispatcher - { - // Supported source formats - private static const SOURCE_FORMAT_VAST:String = "vast"; - - /** - * Constructor. - * - * @param mediaFactory Optional MediaFactory. If specified, then all MediaElements - * will be created through the factory. If not specified, then all MediaElements - * will be directly instantiated. - */ - public function MASTDocumentProcessor(mediaFactory:MediaFactory) - { - super(); - - this.mediaFactory = mediaFactory; - } - - /** - * Processes a MAST document represented as a MASTDocument - * object, the root of the MAST document object model. - * - * @param document The MASTDocument object to process. - * @param mediaElement The main content, usually a video, the - * MASTDocument object will work with. - * - * @return True if the condition causes a pending play request, - * such as a preroll ad. - */ - public function processDocument(document:MASTDocument, mediaElement:MediaElement):Boolean - { - var causesPendingPlayRequest:Boolean = false; - - // Set up a listener for each trigger. - for each (var trigger:MASTTrigger in document.triggers) - { - var condition:MASTCondition; - - for each (condition in trigger.startConditions) - { - if (processMASTCondition(trigger, condition, mediaElement, true)) - { - causesPendingPlayRequest = true; - - } - } - - for each (condition in trigger.endConditions) - { - processMASTCondition(trigger, condition, mediaElement, false); - } - } - - return causesPendingPlayRequest; - } - - /** - * Loads any payload (source) associated with a trigger. - *

      - * To add support for an additional payload, override this - * method. - *

      - */ - public function loadSources(trigger:MASTTrigger, condition:MASTCondition):void - { - for each (var source:MASTSource in trigger.sources) - { - if (source.format == SOURCE_FORMAT_VAST) - { - loadVastDocument(source, condition); - } - } - } - - /** - * Process a single condition object. - * - * @return True if the condition causes a pending play request, - * such as a preroll ad. - */ - private function processMASTCondition(trigger:MASTTrigger, condition:MASTCondition, - mediaElement:MediaElement, start:Boolean):Boolean - { - var conditionManager:MASTConditionManager = new MASTConditionManager(); - conditionManager.addEventListener(MASTConditionManager.CONDITION_TRUE, onConditionTrue); - var causesPendingPlayRequest:Boolean = conditionManager.setContext(mediaElement, condition, start); - - function onConditionTrue(event:Event):void - { - conditionManager.removeEventListener(MASTConditionManager.CONDITION_TRUE, onConditionTrue); - loadSources(trigger, condition); - } - - return causesPendingPlayRequest; - } - - /** - * Loads a VAST document specified in the MASTSource object. - * - * @param source The MASTSource object containing the VAST document to load. - * @param condition The MASTCondition object that is causing the source to be loaded. - */ - public function loadVastDocument(source:MASTSource, condition:MASTCondition):void - { - var loadTrait:VASTLoadTrait - = new VASTLoadTrait(new VASTLoader(), new URLResource(source.url)); - - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onLoadStateChange - ); - loadTrait.load(); - - - var placement:String = MASTTarget(source.targets[0]).id as String; - - function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - vastMediaGenerator = new VASTMediaGenerator(null, mediaFactory); - - if(placement == "nonlinear") - dispatchEvent(new MASTDocumentProcessedEvent(vastMediaGenerator.createMediaElements(loadTrait.vastDocument, VASTMediaGenerator.PLACEMENT_NONLINEAR), condition)); - else - dispatchEvent(new MASTDocumentProcessedEvent(vastMediaGenerator.createMediaElements(loadTrait.vastDocument, VASTMediaGenerator.PLACEMENT_LINEAR), condition)); - - } - } - } - private static const ERROR_MISSING_VAST_METADATA:String = "Media Element is missing VAST metadata"; - private static const ERROR_MISSING_RESOURCE:String = "Media Element is missing a valid resource"; - private var vastMediaGenerator:VASTMediaGenerator; - private var mediaFactory:MediaFactory; - - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* Eyewonder, LLC +* +*****************************************************/ +package org.osmf.mast.loader +{ + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.errors.IllegalOperationError; + import org.osmf.events.LoadEvent; + import org.osmf.mast.managers.MASTConditionManager; + import org.osmf.mast.model.*; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.URLResource; + import org.osmf.traits.LoadState; + import org.osmf.vast.loader.VASTLoadTrait; + import org.osmf.vast.loader.VASTLoader; + import org.osmf.vast.media.DefaultVASTMediaFileResolver; + import org.osmf.vast.media.IVASTMediaFileResolver; + import org.osmf.vast.media.VASTMediaGenerator; + import org.osmf.metadata.Metadata; + import org.osmf.media.MediaResourceBase; + + /** + * This class process a MAST document by working with the + * objects in the MAST object model. + * + * @see org.osmf.mast.model.MASTDocument + */ + public class MASTDocumentProcessor extends EventDispatcher + { + // Supported source formats + private static const SOURCE_FORMAT_VAST:String = "vast"; + + /** + * Constructor. + * + * @param mediaFactory Optional MediaFactory. If specified, then all MediaElements + * will be created through the factory. If not specified, then all MediaElements + * will be directly instantiated. + */ + public function MASTDocumentProcessor(mediaFactory:MediaFactory) + { + super(); + + this.mediaFactory = mediaFactory; + } + + /** + * Processes a MAST document represented as a MASTDocument + * object, the root of the MAST document object model. + * + * @param document The MASTDocument object to process. + * @param mediaElement The main content, usually a video, the + * MASTDocument object will work with. + * + * @return True if the condition causes a pending play request, + * such as a preroll ad. + */ + public function processDocument(document:MASTDocument, mediaElement:MediaElement):Boolean + { + var causesPendingPlayRequest:Boolean = false; + + // Set up a listener for each trigger. + for each (var trigger:MASTTrigger in document.triggers) + { + var condition:MASTCondition; + + for each (condition in trigger.startConditions) + { + if (processMASTCondition(trigger, condition, mediaElement, true)) + { + causesPendingPlayRequest = true; + + } + } + + for each (condition in trigger.endConditions) + { + processMASTCondition(trigger, condition, mediaElement, false); + } + } + + return causesPendingPlayRequest; + } + + /** + * Loads any payload (source) associated with a trigger. + *

      + * To add support for an additional payload, override this + * method. + *

      + */ + public function loadSources(trigger:MASTTrigger, condition:MASTCondition):void + { + for each (var source:MASTSource in trigger.sources) + { + if (source.format == SOURCE_FORMAT_VAST) + { + loadVastDocument(source, condition); + } + } + } + + /** + * Process a single condition object. + * + * @return True if the condition causes a pending play request, + * such as a preroll ad. + */ + private function processMASTCondition(trigger:MASTTrigger, condition:MASTCondition, + mediaElement:MediaElement, start:Boolean):Boolean + { + var conditionManager:MASTConditionManager = new MASTConditionManager(); + conditionManager.addEventListener(MASTConditionManager.CONDITION_TRUE, onConditionTrue); + var causesPendingPlayRequest:Boolean = conditionManager.setContext(mediaElement, condition, start); + + function onConditionTrue(event:Event):void + { + conditionManager.removeEventListener(MASTConditionManager.CONDITION_TRUE, onConditionTrue); + loadSources(trigger, condition); + } + + return causesPendingPlayRequest; + } + + /** + * Loads a VAST document specified in the MASTSource object. + * + * @param source The MASTSource object containing the VAST document to load. + * @param condition The MASTCondition object that is causing the source to be loaded. + */ + public function loadVastDocument(source:MASTSource, condition:MASTCondition):void + { + var loadTrait:VASTLoadTrait + = new VASTLoadTrait(new VASTLoader(), new URLResource(source.url)); + + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onLoadStateChange + ); + loadTrait.load(); + + + var placement:String = MASTTarget(source.targets[0]).id as String; + + function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + vastMediaGenerator = new VASTMediaGenerator(null, mediaFactory); + + if(placement == "nonlinear") + dispatchEvent(new MASTDocumentProcessedEvent(vastMediaGenerator.createMediaElements(loadTrait.vastDocument, VASTMediaGenerator.PLACEMENT_NONLINEAR), condition)); + else + dispatchEvent(new MASTDocumentProcessedEvent(vastMediaGenerator.createMediaElements(loadTrait.vastDocument, VASTMediaGenerator.PLACEMENT_LINEAR), condition)); + + } + } + } + private static const ERROR_MISSING_VAST_METADATA:String = "Media Element is missing VAST metadata"; + private static const ERROR_MISSING_RESOURCE:String = "Media Element is missing a valid resource"; + private var vastMediaGenerator:VASTMediaGenerator; + private var mediaFactory:MediaFactory; + + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTLoadTrait.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTLoadTrait.as index 6e4e569..b944ec1 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTLoadTrait.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTLoadTrait.as @@ -1,51 +1,51 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -******************************************************/ -package org.osmf.mast.loader -{ - import org.osmf.mast.model.MASTDocument; - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - - public class MASTLoadTrait extends LoadTrait - { - public function MASTLoadTrait(loader:LoaderBase, resource:MediaResourceBase) - { - super(loader, resource); - } - - /** - * The MASTDocument object. - */ - public function get document():MASTDocument - { - return _document; - } - - public function set document(value:MASTDocument):void - { - _document = value; - } - - private var _document:MASTDocument; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +******************************************************/ +package org.osmf.mast.loader +{ + import org.osmf.mast.model.MASTDocument; + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + + public class MASTLoadTrait extends LoadTrait + { + public function MASTLoadTrait(loader:LoaderBase, resource:MediaResourceBase) + { + super(loader, resource); + } + + /** + * The MASTDocument object. + */ + public function get document():MASTDocument + { + return _document; + } + + public function set document(value:MASTDocument):void + { + _document = value; + } + + private var _document:MASTDocument; + } } \ No newline at end of file diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTLoader.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTLoader.as index cb3511e..e2ff316 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTLoader.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/loader/MASTLoader.as @@ -1,163 +1,163 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* -******************************************************/ -package org.osmf.mast.loader -{ - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaErrorEvent; - import org.osmf.mast.model.*; - import org.osmf.mast.parser.MASTParser; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.utils.HTTPLoader; - import org.osmf.utils.HTTPLoadTrait; - CONFIG::LOGGING - { - import org.osmf.logging.*; - } - - /** - * Loader for the MASTProxyElement. - **/ - public class MASTLoader extends LoaderBase - { - /** - * Constructor. - * - * @param The HTTPLoader to be used by this MASTLoader to retrieve - * the MAST document. If null, then a new one will be created on - * demand. - */ - public function MASTLoader(httpLoader:HTTPLoader=null) - { - super(); - - this.httpLoader = httpLoader != null ? httpLoader : new HTTPLoader(); - } - - /** - * @private - **/ - override public function canHandleResource(resource:MediaResourceBase):Boolean - { - return httpLoader.canHandleResource(resource); - } - - /** - * Loads a MAST document. - *

      Updates the LoadTrait's loadState property to LOADING - * while loading and to READY upon completing a successful load and parse of the - * MAST document.

      - * - * @see org.osmf.traits.LoadState - * @param LoadTrait The LoadTrait to be loaded. - */ - override protected function executeLoad(loadTrait:LoadTrait):void - { - updateLoadTrait(loadTrait, LoadState.LOADING); - - httpLoader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - - // Create a temporary LoadTrait for this purpose, so that our main - // LoadTrait doesn't reflect any of the state changes from the - // loading of the URL, and so that we can catch any errors. - var httpLoadTrait:HTTPLoadTrait = new HTTPLoadTrait(httpLoader, loadTrait.resource); - - httpLoadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - httpLoader.load(httpLoadTrait); - - function onHTTPLoaderStateChange(event:LoaderEvent):void - { - if (event.newState == LoadState.READY) - { - // This is a terminal state, so remove all listeners. - httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - var parser:MASTParser = new MASTParser(); - var mastDocument:MASTDocument; - - try - { - mastDocument = parser.parse(httpLoadTrait.urlLoader.data.toString()); - } - catch(e:Error) - { - updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); - throw e; - } - - MASTLoadTrait(loadTrait).document = mastDocument; - updateLoadTrait(loadTrait, LoadState.READY); - - } - else if (event.newState == LoadState.LOAD_ERROR) - { - // This is a terminal state, so remove the listener. But - // don't remove the error event listener, as that will be - // removed when the error event for this failure is - // dispatched. - httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - - updateLoadTrait(loadTrait, event.newState); - } - } - - function onLoadError(event:MediaErrorEvent):void - { - // Only remove this listener, as there will be a corresponding - // event for the load failure. - httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - loadTrait.dispatchEvent(event.clone()); - } - } - - /** - * Unloads the document. - * - *

      Updates the LoadTrait's loadState property to UNLOADING - * while unloading and to UNINITIALIZED upon completing a successful unload.

      - * - * @param LoadTrait LoadTrait to be unloaded. - * @see org.osmf.traits.LoadState - */ - override protected function executeUnload(loadTrait:LoadTrait):void - { - // Nothing to do. - updateLoadTrait(loadTrait, LoadState.UNLOADING); - updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); - } - - private var httpLoader:HTTPLoader; - - CONFIG::LOGGING - { - private static const logger:org.osmf.logging.Logger = org.osmf.logging.Log.getLogger("org.osmf.mast.loader.MASTLoader"); - } - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* +******************************************************/ +package org.osmf.mast.loader +{ + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaErrorEvent; + import org.osmf.mast.model.*; + import org.osmf.mast.parser.MASTParser; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.utils.HTTPLoader; + import org.osmf.utils.HTTPLoadTrait; + CONFIG::LOGGING + { + import org.osmf.logging.*; + } + + /** + * Loader for the MASTProxyElement. + **/ + public class MASTLoader extends LoaderBase + { + /** + * Constructor. + * + * @param The HTTPLoader to be used by this MASTLoader to retrieve + * the MAST document. If null, then a new one will be created on + * demand. + */ + public function MASTLoader(httpLoader:HTTPLoader=null) + { + super(); + + this.httpLoader = httpLoader != null ? httpLoader : new HTTPLoader(); + } + + /** + * @private + **/ + override public function canHandleResource(resource:MediaResourceBase):Boolean + { + return httpLoader.canHandleResource(resource); + } + + /** + * Loads a MAST document. + *

      Updates the LoadTrait's loadState property to LOADING + * while loading and to READY upon completing a successful load and parse of the + * MAST document.

      + * + * @see org.osmf.traits.LoadState + * @param LoadTrait The LoadTrait to be loaded. + */ + override protected function executeLoad(loadTrait:LoadTrait):void + { + updateLoadTrait(loadTrait, LoadState.LOADING); + + httpLoader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + + // Create a temporary LoadTrait for this purpose, so that our main + // LoadTrait doesn't reflect any of the state changes from the + // loading of the URL, and so that we can catch any errors. + var httpLoadTrait:HTTPLoadTrait = new HTTPLoadTrait(httpLoader, loadTrait.resource); + + httpLoadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + httpLoader.load(httpLoadTrait); + + function onHTTPLoaderStateChange(event:LoaderEvent):void + { + if (event.newState == LoadState.READY) + { + // This is a terminal state, so remove all listeners. + httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + var parser:MASTParser = new MASTParser(); + var mastDocument:MASTDocument; + + try + { + mastDocument = parser.parse(httpLoadTrait.urlLoader.data.toString()); + } + catch(e:Error) + { + updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); + throw e; + } + + MASTLoadTrait(loadTrait).document = mastDocument; + updateLoadTrait(loadTrait, LoadState.READY); + + } + else if (event.newState == LoadState.LOAD_ERROR) + { + // This is a terminal state, so remove the listener. But + // don't remove the error event listener, as that will be + // removed when the error event for this failure is + // dispatched. + httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + + updateLoadTrait(loadTrait, event.newState); + } + } + + function onLoadError(event:MediaErrorEvent):void + { + // Only remove this listener, as there will be a corresponding + // event for the load failure. + httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + loadTrait.dispatchEvent(event.clone()); + } + } + + /** + * Unloads the document. + * + *

      Updates the LoadTrait's loadState property to UNLOADING + * while unloading and to UNINITIALIZED upon completing a successful unload.

      + * + * @param LoadTrait LoadTrait to be unloaded. + * @see org.osmf.traits.LoadState + */ + override protected function executeUnload(loadTrait:LoadTrait):void + { + // Nothing to do. + updateLoadTrait(loadTrait, LoadState.UNLOADING); + updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); + } + + private var httpLoader:HTTPLoader; + + CONFIG::LOGGING + { + private static const logger:org.osmf.logging.Logger = org.osmf.logging.Log.getLogger("org.osmf.mast.loader.MASTLoader"); + } + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/managers/MASTConditionManager.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/managers/MASTConditionManager.as index 3ffebe7..94e3f61 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/managers/MASTConditionManager.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/managers/MASTConditionManager.as @@ -1,517 +1,517 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* -*****************************************************/ -package org.osmf.mast.managers -{ - import flash.errors.IllegalOperationError; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.TimerEvent; - import flash.utils.Timer; - import flash.utils.getDefinitionByName; - - import org.osmf.events.*; - import org.osmf.mast.adapter.MASTAdapter; - import org.osmf.mast.model.MASTCondition; - import org.osmf.mast.types.MASTConditionOperator; - import org.osmf.mast.types.MASTConditionType; - import org.osmf.media.MediaElement; - import org.osmf.traits.MediaTraitBase; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - CONFIG::LOGGING - { - import org.osmf.logging.*; - } - - /** - * Dispatched when the condition (and it's child conditions) - * evaluate to true - * - * @eventType flash.events.Event - */ - [Event(name="conditionTrue",type="flash.events.Event")] - - - /** - * Each MASTCondition has a MASTConditionManager which knows how to - * listen for events and check properties on a MediaElement. - */ - public class MASTConditionManager extends EventDispatcher - { - public static const CONDITION_TRUE:String = "conditionTrue"; - - public function MASTConditionManager() - { - super(); - } - - /** - * Set the MediaElement and the MASTCondition object this - * class will manage. - * - * @return True if the condition causes a pending play request, - * such as a preroll ad. - */ - public function setContext(mediaElement:MediaElement, condition:MASTCondition, startCondition:Boolean):Boolean - { - _condition = condition; - _mediaElement = mediaElement; - _mastAdapter = new MASTAdapter(); - - return processCondition(startCondition); - } - - /** - * Override this method to provide a custom interval for - * the property check timer. The default is 250 milliseconds. - * This is the timer interval for the time that checks - * property conditions every 'n' milliseconds. This method should - * return a value in milliseconds. - */ - protected function get propertyConditionCheckInterval():int - { - return DEFAULT_PROPERTY_COND_CHECK_INTERVAL; - } - - private function processCondition(startCondition:Boolean):Boolean - { - var causesPendingPlayRequest:Boolean = false; - - // If the condition causes a pending play request, such as OnItemStart, - // we don't need to set any event listeners, we just need to evaluate - // the condition and dispatch the CONDITION_TRUE event. - if (startCondition && conditionCausesPendingPlayRequest()) - { - causesPendingPlayRequest = true; - - if (this.evaluateChildConditions()) - { - onConditionTrue(); - } - } - else - { - // Ask the MASTAdapter class to give us the OSMF trait.property or event.type - var propOrEventName:String = _mastAdapter.lookup(_condition.name); - - if (propOrEventName == null) - { - throw new IllegalOperationError(UNKNOWN_TRAIT_OR_EVENT_ERROR); - } - - if (_condition.type == MASTConditionType.EVENT) - { - processEventCondition(propOrEventName); - } - else // PROPERTY - { - processPropertyCondition(propOrEventName); - } - } - - return causesPendingPlayRequest; - } - - private function processPropertyCondition(propName:String):void - { - var result:Array = propName.split(/\./); - var traitName:String = result[0]; - var traitProperty:String = result[1]; - - var traitType:String = getTraitTypeForTraitName(traitName); - if (traitType == null) - { - throw new IllegalOperationError(UNKNOWN_TRAIT_OR_EVENT_ERROR); - } - - listenForTraitProperty(traitType, traitProperty, _condition.value, _condition.operator); - } - - private function processEventCondition(eventName:String):void - { - // Get the event class name and the event type - var result:Array = eventName.match(/^(.*\.)(.*)$/); - var eventClassName:String = result[1]; - var eventType:String = result[2]; - - // Remove the trailing . from the event class name - eventClassName = eventClassName.replace(/\.$/, ""); - - var traitType:String = getTraitTypeForEventName(eventClassName); - if (traitType == null) - { - throw new IllegalOperationError("Unable to map an event condition in the MAST document to a trait that dispatches that event."); - } - - CONFIG::LOGGING - { - logger.debug("adding a listener for this event: " +eventName); - } - - listenForTraitEvent(traitType, getDefinitionByName(eventClassName), eventType) - } - - private function conditionCausesPendingPlayRequest():Boolean - { - return (_condition.type == MASTConditionType.EVENT && (conditionIsPreRoll() || conditionIsPostRoll(_condition))); - } - - private function conditionIsPreRoll():Boolean - { - return ((_condition.name == MASTAdapter.ON_ITEM_START) || (_condition.name == MASTAdapter.ON_PLAY)); - } - - public static function conditionIsPostRoll(cond:MASTCondition):Boolean - { - return ((cond.name == MASTAdapter.ON_ITEM_END) || (cond.name == MASTAdapter.ON_END) || (cond.name == MASTAdapter.ON_STOP)); - } - - - private function listenForTraitEvent(traitType:String, eventClass:Object, eventType:String):void - { - var trait:MediaTraitBase = _mediaElement.getTrait(traitType); - if (trait != null) - { - // The trait is present, add the listener. - trait.addEventListener(eventClass[eventType], evaluateEventCondition, false, 0, true); - _mediaElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); - } - else - { - // The trait is not present, we need to wait until it's added - // before adding the listener. (Ideally we would manage the - // add/remove listeners more cleanly, but for the prototype - // I'm just adding it as a closure.) - _mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - - function onTraitAdd(event:MediaElementEvent):void - { - if (event.traitType == traitType) - { - _mediaElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - - listenForTraitEvent(traitType, eventClass, eventType); - } - } - - function onTraitRemove(event:MediaElementEvent):void - { - if (event.traitType == traitType) - { - trait.removeEventListener(eventClass[eventType], onConditionTrue); - _mediaElement.removeEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); - - _mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - } - } - - private function listenForTraitProperty(traitType:String, propertyName:String, propertyValue:Object, operator:MASTConditionOperator):void - { - var trait:MediaTraitBase = _mediaElement.getTrait(traitType); - if (trait != null) - { - // The trait is present, add the listener. - addPropertyListener(_mediaElement, traitType, trait, propertyName, propertyValue, operator); - } - - // The trait is not present, we need to wait until it's added - // before adding the listener. - _mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - - function onTraitAdd(event:MediaElementEvent):void - { - if (event.traitType == traitType) - { - _mediaElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - listenForTraitProperty(traitType, propertyName, propertyValue, operator); - } - } - } - - private function addPropertyListener(mediaElement:MediaElement, traitType:String, trait:MediaTraitBase, propertyName:String, propertyValue:Object, operator:MASTConditionOperator):void - { - if (isConditionTrue(trait, propertyName, propertyValue, operator) && evaluateChildConditions()) - { - onConditionTrue(); - } - else - { - var timer:Timer = new Timer(propertyConditionCheckInterval); - timer.addEventListener(TimerEvent.TIMER, onPropertyListenerTimer); - timer.start(); - - function onPropertyListenerTimer(event:TimerEvent):void - { - if (mediaElement.getTrait(traitType) == trait) - { - if (isConditionTrue(trait, propertyName, propertyValue, operator) && evaluateChildConditions()) - { - timer.stop(); - timer.removeEventListener(TimerEvent.TIMER, onPropertyListenerTimer); - - onConditionTrue(); - } - } - else - { - timer.stop(); - timer.removeEventListener(TimerEvent.TIMER, onPropertyListenerTimer); - } - } - } - } - - private function onConditionTrue(event:Event=null):void - { - CONFIG::LOGGING - { - logger.debug("onConditionTrue() - dispatching: "+CONDITION_TRUE+" event for condition.name="+this._condition.name); - } - - dispatchEvent(new Event(CONDITION_TRUE)); - } - - private function evaluateEventCondition(event:Event):void - { - CONFIG::LOGGING - { - logger.debug("In evaluateEventCondition - event="+ event.toString()); - } - - // Now evaluate the condition and all child conditions - var conditionTrue:Boolean = false; - - switch (_condition.name) - { - case MASTAdapter.ON_PAUSE: - { - var playEvent:PlayEvent = event as PlayEvent; - if (playEvent.playState == PlayState.PAUSED) - { - conditionTrue = true; - } - } - break; - case MASTAdapter.ON_MUTE: - { - var mutedChangeEvent:AudioEvent = event as AudioEvent; - if (mutedChangeEvent.muted) - { - conditionTrue = true; - } - } - break; - case MASTAdapter.ON_VOLUME_CHANGE: - { - conditionTrue = true; - } - break; - case MASTAdapter.ON_SEEK: - { - var seekingChangeEvent:SeekEvent = event as SeekEvent; - if (seekingChangeEvent.seeking == true) - { - conditionTrue = true; - } - } - break; - } - - if (conditionTrue && evaluateChildConditions()) - { - onConditionTrue(); - } - } - - /** - * Evaluate child conditions for the MASTCondition - * associated with this class. Child conditions are - * an implicit boolean 'AND', so all of them must - * evaluate to true in order for the parent condition - * to evaluate to true. - * - * @returns true if all child conditions evaluate to true - */ - private function evaluateChildConditions():Boolean - { - var evaluation:Boolean = true; - - for each (var childCondition:MASTCondition in _condition.childConditions) - { - if (childCondition.type == MASTConditionType.EVENT) - { - // Event condition types are not allowed as child conditions - throw new IllegalOperationError(ILLEGAL_CHILD_CONDITION_ERROR); - } - - // If any child conditions evaluate to false, this condition is false - if (!evaluateChild(childCondition)) - { - evaluation = false; - break; - } - } - - return evaluation; - } - - /** - * A recursive function to evaluate a child condition and all of it's children. - */ - private function evaluateChild(childCond:MASTCondition):Boolean - { - var evaluation:Boolean = false; - var propertyName:String = _mastAdapter.lookup(childCond.name); - - if (propertyName == null) - { - throw new IllegalOperationError(UNKNOWN_TRAIT_OR_EVENT_ERROR); - } - - var result:Array = propertyName.split(/\./); - var traitName:String = result[0]; - var traitProperty:String = result[1]; - - var traitType:String = getTraitTypeForTraitName(traitName); - if (traitType == null) - { - throw new IllegalOperationError(UNKNOWN_TRAIT_OR_EVENT_ERROR); - } - - // If the trait is null here, we are not going to wait for it, that - // should have already happened. If it is not present here, it never - // will be. - var trait:MediaTraitBase = _mediaElement.getTrait(traitType); - if (trait != null) - { - evaluation = isConditionTrue(trait, traitProperty, childCond.value, childCond.operator); - } - - - if (evaluation) - { - // Evaluate children - for each (var cond:MASTCondition in childCond.childConditions) - { - evaluation = evaluateChild(cond); - } - } - - return evaluation; - } - - private function isConditionTrue(trait:MediaTraitBase, propertyName:String, propertyValue:Object, operator:MASTConditionOperator):Boolean - { - var property:* = trait[propertyName]; - if (property != undefined) - { - switch (operator) - { - case MASTConditionOperator.GTR: - return Number(property) > Number(propertyValue); - case MASTConditionOperator.LT: - return Number(property) < Number(propertyValue); - case MASTConditionOperator.GEQ: - return Number(property) >= Number(propertyValue); - case MASTConditionOperator.LEQ: - return Number(property) <= Number(propertyValue); - case MASTConditionOperator.MOD: - return Number(property) % Number(propertyValue) > 0; - case MASTConditionOperator.EQ: - return Number(propertyValue) == Number(property); - case MASTConditionOperator.NEQ: - return Number(propertyValue) != Number(property); - default: - throw new IllegalOperationError(UNKOWN_OPERATOR_ERROR); - } - } - - return false; - } - - private function getTraitTypeForTraitName(traitName:String):String - { - var traitType:String = null; - - switch (traitName) - { - case "TimeTrait": - traitType = MediaTraitType.TIME; - break; - case "PlayTrait": - traitType = MediaTraitType.PLAY; - break; - case "DisplayObjectTrait": - traitType = MediaTraitType.DISPLAY_OBJECT; - break; - } - - return traitType; - } - - private function getTraitTypeForEventName(eventName:String):String - { - var traitType:String = null; - - // Get the event class name without the package name - var result:Array = eventName.match(/^(.*\.)(.*)$/); - var eventClassName:String = result[2]; - - switch (eventClassName) - { - case "PlayEvent": - traitType = MediaTraitType.PLAY; - break; - case "AudioEvent": - traitType = MediaTraitType.AUDIO; - break; - case "SeekEvent": - traitType = MediaTraitType.SEEK; - break; - case "TimeEvent": - traitType = MediaTraitType.TIME; - break; - } - - - return traitType; - } - - private var _mediaElement:MediaElement; - private var _condition:MASTCondition; - private var _mastAdapter:MASTAdapter; - - private static const DEFAULT_PROPERTY_COND_CHECK_INTERVAL:int = 250; - private static const UNKNOWN_TRAIT_OR_EVENT_ERROR:String = "Unknown trait name or event name in MAST document"; - private static const ILLEGAL_CHILD_CONDITION_ERROR:String = "Child conditions cannot be Event conditions"; - private static const UNKOWN_OPERATOR_ERROR:String = "Unkown operator in MAST document"; - - CONFIG::LOGGING - { - private static const logger:org.osmf.logging.Logger = org.osmf.logging.Log.getLogger("org.osmf.mast.managers.MASTConditionManager"); - } - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* +*****************************************************/ +package org.osmf.mast.managers +{ + import flash.errors.IllegalOperationError; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.TimerEvent; + import flash.utils.Timer; + import flash.utils.getDefinitionByName; + + import org.osmf.events.*; + import org.osmf.mast.adapter.MASTAdapter; + import org.osmf.mast.model.MASTCondition; + import org.osmf.mast.types.MASTConditionOperator; + import org.osmf.mast.types.MASTConditionType; + import org.osmf.media.MediaElement; + import org.osmf.traits.MediaTraitBase; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + CONFIG::LOGGING + { + import org.osmf.logging.*; + } + + /** + * Dispatched when the condition (and it's child conditions) + * evaluate to true + * + * @eventType flash.events.Event + */ + [Event(name="conditionTrue",type="flash.events.Event")] + + + /** + * Each MASTCondition has a MASTConditionManager which knows how to + * listen for events and check properties on a MediaElement. + */ + public class MASTConditionManager extends EventDispatcher + { + public static const CONDITION_TRUE:String = "conditionTrue"; + + public function MASTConditionManager() + { + super(); + } + + /** + * Set the MediaElement and the MASTCondition object this + * class will manage. + * + * @return True if the condition causes a pending play request, + * such as a preroll ad. + */ + public function setContext(mediaElement:MediaElement, condition:MASTCondition, startCondition:Boolean):Boolean + { + _condition = condition; + _mediaElement = mediaElement; + _mastAdapter = new MASTAdapter(); + + return processCondition(startCondition); + } + + /** + * Override this method to provide a custom interval for + * the property check timer. The default is 250 milliseconds. + * This is the timer interval for the time that checks + * property conditions every 'n' milliseconds. This method should + * return a value in milliseconds. + */ + protected function get propertyConditionCheckInterval():int + { + return DEFAULT_PROPERTY_COND_CHECK_INTERVAL; + } + + private function processCondition(startCondition:Boolean):Boolean + { + var causesPendingPlayRequest:Boolean = false; + + // If the condition causes a pending play request, such as OnItemStart, + // we don't need to set any event listeners, we just need to evaluate + // the condition and dispatch the CONDITION_TRUE event. + if (startCondition && conditionCausesPendingPlayRequest()) + { + causesPendingPlayRequest = true; + + if (this.evaluateChildConditions()) + { + onConditionTrue(); + } + } + else + { + // Ask the MASTAdapter class to give us the OSMF trait.property or event.type + var propOrEventName:String = _mastAdapter.lookup(_condition.name); + + if (propOrEventName == null) + { + throw new IllegalOperationError(UNKNOWN_TRAIT_OR_EVENT_ERROR); + } + + if (_condition.type == MASTConditionType.EVENT) + { + processEventCondition(propOrEventName); + } + else // PROPERTY + { + processPropertyCondition(propOrEventName); + } + } + + return causesPendingPlayRequest; + } + + private function processPropertyCondition(propName:String):void + { + var result:Array = propName.split(/\./); + var traitName:String = result[0]; + var traitProperty:String = result[1]; + + var traitType:String = getTraitTypeForTraitName(traitName); + if (traitType == null) + { + throw new IllegalOperationError(UNKNOWN_TRAIT_OR_EVENT_ERROR); + } + + listenForTraitProperty(traitType, traitProperty, _condition.value, _condition.operator); + } + + private function processEventCondition(eventName:String):void + { + // Get the event class name and the event type + var result:Array = eventName.match(/^(.*\.)(.*)$/); + var eventClassName:String = result[1]; + var eventType:String = result[2]; + + // Remove the trailing . from the event class name + eventClassName = eventClassName.replace(/\.$/, ""); + + var traitType:String = getTraitTypeForEventName(eventClassName); + if (traitType == null) + { + throw new IllegalOperationError("Unable to map an event condition in the MAST document to a trait that dispatches that event."); + } + + CONFIG::LOGGING + { + logger.debug("adding a listener for this event: " +eventName); + } + + listenForTraitEvent(traitType, getDefinitionByName(eventClassName), eventType) + } + + private function conditionCausesPendingPlayRequest():Boolean + { + return (_condition.type == MASTConditionType.EVENT && (conditionIsPreRoll() || conditionIsPostRoll(_condition))); + } + + private function conditionIsPreRoll():Boolean + { + return ((_condition.name == MASTAdapter.ON_ITEM_START) || (_condition.name == MASTAdapter.ON_PLAY)); + } + + public static function conditionIsPostRoll(cond:MASTCondition):Boolean + { + return ((cond.name == MASTAdapter.ON_ITEM_END) || (cond.name == MASTAdapter.ON_END) || (cond.name == MASTAdapter.ON_STOP)); + } + + + private function listenForTraitEvent(traitType:String, eventClass:Object, eventType:String):void + { + var trait:MediaTraitBase = _mediaElement.getTrait(traitType); + if (trait != null) + { + // The trait is present, add the listener. + trait.addEventListener(eventClass[eventType], evaluateEventCondition, false, 0, true); + _mediaElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); + } + else + { + // The trait is not present, we need to wait until it's added + // before adding the listener. (Ideally we would manage the + // add/remove listeners more cleanly, but for the prototype + // I'm just adding it as a closure.) + _mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + + function onTraitAdd(event:MediaElementEvent):void + { + if (event.traitType == traitType) + { + _mediaElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + + listenForTraitEvent(traitType, eventClass, eventType); + } + } + + function onTraitRemove(event:MediaElementEvent):void + { + if (event.traitType == traitType) + { + trait.removeEventListener(eventClass[eventType], onConditionTrue); + _mediaElement.removeEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); + + _mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + } + } + + private function listenForTraitProperty(traitType:String, propertyName:String, propertyValue:Object, operator:MASTConditionOperator):void + { + var trait:MediaTraitBase = _mediaElement.getTrait(traitType); + if (trait != null) + { + // The trait is present, add the listener. + addPropertyListener(_mediaElement, traitType, trait, propertyName, propertyValue, operator); + } + + // The trait is not present, we need to wait until it's added + // before adding the listener. + _mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + + function onTraitAdd(event:MediaElementEvent):void + { + if (event.traitType == traitType) + { + _mediaElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + listenForTraitProperty(traitType, propertyName, propertyValue, operator); + } + } + } + + private function addPropertyListener(mediaElement:MediaElement, traitType:String, trait:MediaTraitBase, propertyName:String, propertyValue:Object, operator:MASTConditionOperator):void + { + if (isConditionTrue(trait, propertyName, propertyValue, operator) && evaluateChildConditions()) + { + onConditionTrue(); + } + else + { + var timer:Timer = new Timer(propertyConditionCheckInterval); + timer.addEventListener(TimerEvent.TIMER, onPropertyListenerTimer); + timer.start(); + + function onPropertyListenerTimer(event:TimerEvent):void + { + if (mediaElement.getTrait(traitType) == trait) + { + if (isConditionTrue(trait, propertyName, propertyValue, operator) && evaluateChildConditions()) + { + timer.stop(); + timer.removeEventListener(TimerEvent.TIMER, onPropertyListenerTimer); + + onConditionTrue(); + } + } + else + { + timer.stop(); + timer.removeEventListener(TimerEvent.TIMER, onPropertyListenerTimer); + } + } + } + } + + private function onConditionTrue(event:Event=null):void + { + CONFIG::LOGGING + { + logger.debug("onConditionTrue() - dispatching: "+CONDITION_TRUE+" event for condition.name="+this._condition.name); + } + + dispatchEvent(new Event(CONDITION_TRUE)); + } + + private function evaluateEventCondition(event:Event):void + { + CONFIG::LOGGING + { + logger.debug("In evaluateEventCondition - event="+ event.toString()); + } + + // Now evaluate the condition and all child conditions + var conditionTrue:Boolean = false; + + switch (_condition.name) + { + case MASTAdapter.ON_PAUSE: + { + var playEvent:PlayEvent = event as PlayEvent; + if (playEvent.playState == PlayState.PAUSED) + { + conditionTrue = true; + } + } + break; + case MASTAdapter.ON_MUTE: + { + var mutedChangeEvent:AudioEvent = event as AudioEvent; + if (mutedChangeEvent.muted) + { + conditionTrue = true; + } + } + break; + case MASTAdapter.ON_VOLUME_CHANGE: + { + conditionTrue = true; + } + break; + case MASTAdapter.ON_SEEK: + { + var seekingChangeEvent:SeekEvent = event as SeekEvent; + if (seekingChangeEvent.seeking == true) + { + conditionTrue = true; + } + } + break; + } + + if (conditionTrue && evaluateChildConditions()) + { + onConditionTrue(); + } + } + + /** + * Evaluate child conditions for the MASTCondition + * associated with this class. Child conditions are + * an implicit boolean 'AND', so all of them must + * evaluate to true in order for the parent condition + * to evaluate to true. + * + * @returns true if all child conditions evaluate to true + */ + private function evaluateChildConditions():Boolean + { + var evaluation:Boolean = true; + + for each (var childCondition:MASTCondition in _condition.childConditions) + { + if (childCondition.type == MASTConditionType.EVENT) + { + // Event condition types are not allowed as child conditions + throw new IllegalOperationError(ILLEGAL_CHILD_CONDITION_ERROR); + } + + // If any child conditions evaluate to false, this condition is false + if (!evaluateChild(childCondition)) + { + evaluation = false; + break; + } + } + + return evaluation; + } + + /** + * A recursive function to evaluate a child condition and all of it's children. + */ + private function evaluateChild(childCond:MASTCondition):Boolean + { + var evaluation:Boolean = false; + var propertyName:String = _mastAdapter.lookup(childCond.name); + + if (propertyName == null) + { + throw new IllegalOperationError(UNKNOWN_TRAIT_OR_EVENT_ERROR); + } + + var result:Array = propertyName.split(/\./); + var traitName:String = result[0]; + var traitProperty:String = result[1]; + + var traitType:String = getTraitTypeForTraitName(traitName); + if (traitType == null) + { + throw new IllegalOperationError(UNKNOWN_TRAIT_OR_EVENT_ERROR); + } + + // If the trait is null here, we are not going to wait for it, that + // should have already happened. If it is not present here, it never + // will be. + var trait:MediaTraitBase = _mediaElement.getTrait(traitType); + if (trait != null) + { + evaluation = isConditionTrue(trait, traitProperty, childCond.value, childCond.operator); + } + + + if (evaluation) + { + // Evaluate children + for each (var cond:MASTCondition in childCond.childConditions) + { + evaluation = evaluateChild(cond); + } + } + + return evaluation; + } + + private function isConditionTrue(trait:MediaTraitBase, propertyName:String, propertyValue:Object, operator:MASTConditionOperator):Boolean + { + var property:* = trait[propertyName]; + if (property != undefined) + { + switch (operator) + { + case MASTConditionOperator.GTR: + return Number(property) > Number(propertyValue); + case MASTConditionOperator.LT: + return Number(property) < Number(propertyValue); + case MASTConditionOperator.GEQ: + return Number(property) >= Number(propertyValue); + case MASTConditionOperator.LEQ: + return Number(property) <= Number(propertyValue); + case MASTConditionOperator.MOD: + return Number(property) % Number(propertyValue) > 0; + case MASTConditionOperator.EQ: + return Number(propertyValue) == Number(property); + case MASTConditionOperator.NEQ: + return Number(propertyValue) != Number(property); + default: + throw new IllegalOperationError(UNKOWN_OPERATOR_ERROR); + } + } + + return false; + } + + private function getTraitTypeForTraitName(traitName:String):String + { + var traitType:String = null; + + switch (traitName) + { + case "TimeTrait": + traitType = MediaTraitType.TIME; + break; + case "PlayTrait": + traitType = MediaTraitType.PLAY; + break; + case "DisplayObjectTrait": + traitType = MediaTraitType.DISPLAY_OBJECT; + break; + } + + return traitType; + } + + private function getTraitTypeForEventName(eventName:String):String + { + var traitType:String = null; + + // Get the event class name without the package name + var result:Array = eventName.match(/^(.*\.)(.*)$/); + var eventClassName:String = result[2]; + + switch (eventClassName) + { + case "PlayEvent": + traitType = MediaTraitType.PLAY; + break; + case "AudioEvent": + traitType = MediaTraitType.AUDIO; + break; + case "SeekEvent": + traitType = MediaTraitType.SEEK; + break; + case "TimeEvent": + traitType = MediaTraitType.TIME; + break; + } + + + return traitType; + } + + private var _mediaElement:MediaElement; + private var _condition:MASTCondition; + private var _mastAdapter:MASTAdapter; + + private static const DEFAULT_PROPERTY_COND_CHECK_INTERVAL:int = 250; + private static const UNKNOWN_TRAIT_OR_EVENT_ERROR:String = "Unknown trait name or event name in MAST document"; + private static const ILLEGAL_CHILD_CONDITION_ERROR:String = "Child conditions cannot be Event conditions"; + private static const UNKOWN_OPERATOR_ERROR:String = "Unkown operator in MAST document"; + + CONFIG::LOGGING + { + private static const logger:org.osmf.logging.Logger = org.osmf.logging.Log.getLogger("org.osmf.mast.managers.MASTConditionManager"); + } + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/media/MASTProxyElement.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/media/MASTProxyElement.as index 57d19e1..72b99ce 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/media/MASTProxyElement.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/media/MASTProxyElement.as @@ -1,392 +1,392 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* Eyewonder, LLC -* -******************************************************/ -package org.osmf.mast.media -{ - import flash.errors.IllegalOperationError; - import flash.events.MouseEvent; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.VideoElement; - import org.osmf.elements.ProxyElement; - import org.osmf.elements.SerialElement; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.events.TimeEvent; - import org.osmf.mast.MASTPluginInfo; - import org.osmf.mast.loader.MASTDocumentProcessedEvent; - import org.osmf.mast.loader.MASTDocumentProcessor; - import org.osmf.mast.loader.MASTLoadTrait; - import org.osmf.mast.loader.MASTLoader; - import org.osmf.mast.managers.MASTConditionManager; - import org.osmf.mast.model.*; - import org.osmf.mast.traits.MASTPlayTrait; - import org.osmf.mast.types.MASTConditionType; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.TimeTrait; - import org.osmf.vast.media.CompanionElement; - import org.osmf.vast.media.VASTTrackingProxyElement; - import org.osmf.vast.metadata.VASTMetadata; - import org.osmf.vpaid.elements.VPAIDElement; - import org.osmf.vpaid.metadata.VPAIDMetadata; - - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } - - /** - * The MASTProxyElement class is a wrapper for the media supplied. - * It's purpose is to override the loadable and playable traits to - * allow the processing of a MAST document and to insert the media - * elements found in the MAST payload. - */ - public class MASTProxyElement extends ProxyElement - { - /** - * Constructor. - * - * @param proxiedElement The MediaElement to proxy. - * @param mediaFactory Optional MediaFactory. If specified, then all - * MediaElements will be created through the factory. If not specified, - * then all MediaElements will be directly instantiated. - **/ - public function MASTProxyElement(proxiedElement:MediaElement=null, mediaFactory:MediaFactory=null) - { - super(proxiedElement); - - this.mediaFactory = mediaFactory; - } - - /** - * @inheritDoc - */ - override public function set proxiedElement(value:MediaElement):void - { - var serialElement:SerialElement; - - if (value != null && - !(value is SerialElement)) - { - // Wrap any child in a SerialElement. - serialElement = new SerialElement(); - serialElement.addChild(value); - - value = serialElement; - } - - super.proxiedElement = value; - - if (value != null) - { - // Override the LoadTrait with our own custom LoadTrait, - // which retrieves the MAST document, parses it, and sets up - // the triggers in relation to our wrapped MediaElement. - // - - // Get the MAST url resource from the metadata of the element - // that is wrapped. - serialElement = super.proxiedElement as SerialElement; - var mediaElement:MediaElement = serialElement.getChildAt(0); - - var tempResource:MediaResourceBase = (mediaElement && mediaElement.resource != null) ? mediaElement.resource : resource; - if (tempResource == null) - { - throw new IllegalOperationError(ERROR_MISSING_RESOURCE); - } - - var metadata:Metadata = tempResource.getMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE) as Metadata; - if (metadata == null) - { - throw new IllegalOperationError(ERROR_MISSING_MAST_METADATA); - } - - var mastURL:String = metadata.getValue(MASTPluginInfo.MAST_METADATA_KEY_URI); - - loadTrait = new MASTLoadTrait(new MASTLoader(), new URLResource(mastURL)); - - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onLoadStateChange - ); - - addTrait(MediaTraitType.LOAD, loadTrait); - - // Override the PlayTrait so we can do any necessary - // pre-processing, such as a payload that would cause a - // pre-roll. - - var playTrait:PlayTrait = new MASTPlayTrait(); - addTrait(MediaTraitType.PLAY, playTrait); - } - } - - private function removeCustomPlayTrait():void - { - var playTrait:MASTPlayTrait = this.getTrait(MediaTraitType.PLAY) as MASTPlayTrait; - - if (playTrait) - { - removeTrait(MediaTraitType.PLAY); - - if (playTrait.playRequestPending) - { - // Call play on the original trait - var orgPlayTrait:PlayTrait = getTrait(MediaTraitType.PLAY) as PlayTrait; - - if (orgPlayTrait == null) - { - // Trait is not present yet, we need to wait for it to be added - addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - else - { - - orgPlayTrait.play(); - } - } - } - } - - private function onTraitAdd(event:MediaElementEvent):void - { - removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - if (event.traitType == MediaTraitType.PLAY) - { - var playTrait:PlayTrait = getTrait(MediaTraitType.PLAY) as PlayTrait; - playTrait.play(); - } - } - - private function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - var processor:MASTDocumentProcessor = new MASTDocumentProcessor(mediaFactory); - processor.addEventListener(MASTDocumentProcessedEvent.PROCESSED, onDocumentProcessed, false, 0, true); - var mediaElement:MediaElement = (proxiedElement as SerialElement).getChildAt(0); - - var causesPendingPlayRequest:Boolean = processor.processDocument(loadTrait.document, mediaElement); - - // If there was no condition that causes a pending play request - // remove the custom IPlayable - if (!causesPendingPlayRequest) - { - removeCustomPlayTrait(); - } - - // Our work is done, remove the custom ILoadable. This will - // expose the base ILoadable, which we can then use to do - // the actual load. - removeTrait(MediaTraitType.LOAD); - var loadTrait:LoadTrait = getTrait(MediaTraitType.LOAD) as LoadTrait; - if (loadTrait) - { - loadTrait.load(); - } - } - else if (event.loadState == LoadState.LOAD_ERROR) - { - dispatchEvent(event.clone()); - } - } - - private function onDocumentProcessed(event:MASTDocumentProcessedEvent):void - { - var serialElement:SerialElement = proxiedElement as SerialElement; - var parellelElement:ParallelElement; - // Each inline element needs to be inserted into the location that - // will cause it to be the current (or next) item. - for each (var inlineElement:MediaElement in event.inlineElements) - { - var insertionIndex:int = getInsertionIndex(serialElement, event.condition); - var tempMediaElement:MediaElement = null; - - var nonlinear:Boolean; - var mediaElement:MediaElement; - if (inlineElement is VASTTrackingProxyElement) - { - mediaElement = ProxyElement(ProxyElement(inlineElement).proxiedElement).proxiedElement; - } - - //Check to see if we have a nonlinear VPAIDElemet - if(mediaElement is VPAIDElement) - { - - nonlinear = mediaElement.getMetadata(VPAIDMetadata.NAMESPACE).getValue(VPAIDMetadata.NON_LINEAR_CREATIVE); - // Quick solution to pass mast container info over to VPAIDElement. There may be a better way (metadata maybe?) - try{ - if ((mediaElement as VPAIDElement).MASTWidth == -1) - { - (mediaElement as VPAIDElement).MASTWidth = container["width"]; - (mediaElement as VPAIDElement).MASTHeight = container["height"]; - } - } - catch(error:Error) {} - } - if(nonlinear) - { - //Currently we support running only 1 nonlinear Ad per ad call. - if (insertionIndex == 0) - { - //store content video element - tempMediaElement = serialElement.getChildAt(0); - - parellelElement = new ParallelElement(); - parellelElement.addChild(tempMediaElement); - parellelElement.addChild(mediaElement); - - //serialElement.addChild(parellelElement); - } - }else{ - - var companionElement:Boolean = inlineElement is CompanionElement; - if(!companionElement) - { - // If we are inserting at zero, we need to remove the original and then - // add it again to force SerialElement to update it's listening index - if (insertionIndex == 0) - { - tempMediaElement = serialElement.removeChildAt(0); - } - - if (!(mediaElement is VPAIDElement)) - { - mediaContainer = container as MediaContainer; - mediaContainer.buttonMode = true; - mediaContainer.addEventListener(MouseEvent.MOUSE_UP, onContainerClick); - - if(mediaElement is VideoElement) - { - - if(mediaElement.hasTrait(MediaTraitType.TIME)) - { - - var timeTrait:TimeTrait = mediaElement.getTrait(MediaTraitType.TIME) as TimeTrait; - timeTrait.addEventListener(TimeEvent.COMPLETE, onTimeComplete); - - } - } - - - } - serialElement.addChildAt(inlineElement, insertionIndex); - - if (tempMediaElement != null) - { - serialElement.addChild(tempMediaElement); - } - } - } - //Currently we support running only 1 nonlinear Ad per ad call. There are sizing issues with adding multiple - //parallel elements to a serial element that need to be resolved. Future revisions will allow running multiple nonlinear Ads - if(parellelElement) - { - super.proxiedElement = parellelElement; - } - - - } - // Now we can remove the custom PlayTrait - this.removeCustomPlayTrait(); - } - - private function onTimeComplete(e:TimeEvent):void - { - - mediaContainer.buttonMode = false; - mediaContainer.removeEventListener(MouseEvent.MOUSE_UP, onContainerClick); - } - - private function onContainerClick(event:MouseEvent):void - { - var vastMetadata:Metadata = proxiedElement.getMetadata(VASTMetadata.NAMESPACE); - if(vastMetadata) - vastMetadata.addValue(VASTMetadata.CLICKTHRU, event); - } - - private function getInsertionIndex(serialElement:SerialElement, condition:MASTCondition):int - { - // Generally, the insertion index is the index of the current - // child, so that the inserted child becomes the new current child. - var index:int = 0; - - if ((condition.type == MASTConditionType.EVENT) && (MASTConditionManager.conditionIsPostRoll(condition))) - { - index++; - } - else - { - // However, if our current child is in the midst of playback, we - // don't want to interrupt it, so we insert immediately after the - // current child. - var currentChild:MediaElement = serialElement.getChildAt(index); - if (currentChild != null) - { - // Treat it as playing if it's playing or has a positive currentTime. - var timeTrait:TimeTrait = currentChild.getTrait(MediaTraitType.TIME) as TimeTrait; - if (timeTrait != null && timeTrait.currentTime > 0) - { - index++; - } - else - { - var playTrait:PlayTrait = currentChild.getTrait(MediaTraitType.PLAY) as PlayTrait; - if (playTrait != null && playTrait.playState == PlayState.PLAYING) - { - index++; - } - } - } - } - - CONFIG::LOGGING - { - logger.debug("MASTProxyElement - getInsertionIndex() about to return "+index); - } - return index; - } - - private var loadTrait:MASTLoadTrait; - private var mediaFactory:MediaFactory; - private var mediaContainer:MediaContainer; - private static const ERROR_MISSING_MAST_METADATA:String = "Media Element is missing MAST metadata"; - private static const ERROR_MISSING_RESOURCE:String = "Media Element is missing a valid resource"; - - CONFIG::LOGGING - private static const logger:Logger = Log.getLogger("org.osmf.mast.media.MASTProxyElement"); - - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* Eyewonder, LLC +* +******************************************************/ +package org.osmf.mast.media +{ + import flash.errors.IllegalOperationError; + import flash.events.MouseEvent; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.VideoElement; + import org.osmf.elements.ProxyElement; + import org.osmf.elements.SerialElement; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.events.TimeEvent; + import org.osmf.mast.MASTPluginInfo; + import org.osmf.mast.loader.MASTDocumentProcessedEvent; + import org.osmf.mast.loader.MASTDocumentProcessor; + import org.osmf.mast.loader.MASTLoadTrait; + import org.osmf.mast.loader.MASTLoader; + import org.osmf.mast.managers.MASTConditionManager; + import org.osmf.mast.model.*; + import org.osmf.mast.traits.MASTPlayTrait; + import org.osmf.mast.types.MASTConditionType; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.TimeTrait; + import org.osmf.vast.media.CompanionElement; + import org.osmf.vast.media.VASTTrackingProxyElement; + import org.osmf.vast.metadata.VASTMetadata; + import org.osmf.vpaid.elements.VPAIDElement; + import org.osmf.vpaid.metadata.VPAIDMetadata; + + CONFIG::LOGGING + { + import org.osmf.logging.Logger; + import org.osmf.logging.Log; + } + + /** + * The MASTProxyElement class is a wrapper for the media supplied. + * It's purpose is to override the loadable and playable traits to + * allow the processing of a MAST document and to insert the media + * elements found in the MAST payload. + */ + public class MASTProxyElement extends ProxyElement + { + /** + * Constructor. + * + * @param proxiedElement The MediaElement to proxy. + * @param mediaFactory Optional MediaFactory. If specified, then all + * MediaElements will be created through the factory. If not specified, + * then all MediaElements will be directly instantiated. + **/ + public function MASTProxyElement(proxiedElement:MediaElement=null, mediaFactory:MediaFactory=null) + { + super(proxiedElement); + + this.mediaFactory = mediaFactory; + } + + /** + * @inheritDoc + */ + override public function set proxiedElement(value:MediaElement):void + { + var serialElement:SerialElement; + + if (value != null && + !(value is SerialElement)) + { + // Wrap any child in a SerialElement. + serialElement = new SerialElement(); + serialElement.addChild(value); + + value = serialElement; + } + + super.proxiedElement = value; + + if (value != null) + { + // Override the LoadTrait with our own custom LoadTrait, + // which retrieves the MAST document, parses it, and sets up + // the triggers in relation to our wrapped MediaElement. + // + + // Get the MAST url resource from the metadata of the element + // that is wrapped. + serialElement = super.proxiedElement as SerialElement; + var mediaElement:MediaElement = serialElement.getChildAt(0); + + var tempResource:MediaResourceBase = (mediaElement && mediaElement.resource != null) ? mediaElement.resource : resource; + if (tempResource == null) + { + throw new IllegalOperationError(ERROR_MISSING_RESOURCE); + } + + var metadata:Metadata = tempResource.getMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE) as Metadata; + if (metadata == null) + { + throw new IllegalOperationError(ERROR_MISSING_MAST_METADATA); + } + + var mastURL:String = metadata.getValue(MASTPluginInfo.MAST_METADATA_KEY_URI); + + loadTrait = new MASTLoadTrait(new MASTLoader(), new URLResource(mastURL)); + + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onLoadStateChange + ); + + addTrait(MediaTraitType.LOAD, loadTrait); + + // Override the PlayTrait so we can do any necessary + // pre-processing, such as a payload that would cause a + // pre-roll. + + var playTrait:PlayTrait = new MASTPlayTrait(); + addTrait(MediaTraitType.PLAY, playTrait); + } + } + + private function removeCustomPlayTrait():void + { + var playTrait:MASTPlayTrait = this.getTrait(MediaTraitType.PLAY) as MASTPlayTrait; + + if (playTrait) + { + removeTrait(MediaTraitType.PLAY); + + if (playTrait.playRequestPending) + { + // Call play on the original trait + var orgPlayTrait:PlayTrait = getTrait(MediaTraitType.PLAY) as PlayTrait; + + if (orgPlayTrait == null) + { + // Trait is not present yet, we need to wait for it to be added + addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + else + { + + orgPlayTrait.play(); + } + } + } + } + + private function onTraitAdd(event:MediaElementEvent):void + { + removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + if (event.traitType == MediaTraitType.PLAY) + { + var playTrait:PlayTrait = getTrait(MediaTraitType.PLAY) as PlayTrait; + playTrait.play(); + } + } + + private function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + var processor:MASTDocumentProcessor = new MASTDocumentProcessor(mediaFactory); + processor.addEventListener(MASTDocumentProcessedEvent.PROCESSED, onDocumentProcessed, false, 0, true); + var mediaElement:MediaElement = (proxiedElement as SerialElement).getChildAt(0); + + var causesPendingPlayRequest:Boolean = processor.processDocument(loadTrait.document, mediaElement); + + // If there was no condition that causes a pending play request + // remove the custom IPlayable + if (!causesPendingPlayRequest) + { + removeCustomPlayTrait(); + } + + // Our work is done, remove the custom ILoadable. This will + // expose the base ILoadable, which we can then use to do + // the actual load. + removeTrait(MediaTraitType.LOAD); + var loadTrait:LoadTrait = getTrait(MediaTraitType.LOAD) as LoadTrait; + if (loadTrait) + { + loadTrait.load(); + } + } + else if (event.loadState == LoadState.LOAD_ERROR) + { + dispatchEvent(event.clone()); + } + } + + private function onDocumentProcessed(event:MASTDocumentProcessedEvent):void + { + var serialElement:SerialElement = proxiedElement as SerialElement; + var parellelElement:ParallelElement; + // Each inline element needs to be inserted into the location that + // will cause it to be the current (or next) item. + for each (var inlineElement:MediaElement in event.inlineElements) + { + var insertionIndex:int = getInsertionIndex(serialElement, event.condition); + var tempMediaElement:MediaElement = null; + + var nonlinear:Boolean; + var mediaElement:MediaElement; + if (inlineElement is VASTTrackingProxyElement) + { + mediaElement = ProxyElement(ProxyElement(inlineElement).proxiedElement).proxiedElement; + } + + //Check to see if we have a nonlinear VPAIDElemet + if(mediaElement is VPAIDElement) + { + + nonlinear = mediaElement.getMetadata(VPAIDMetadata.NAMESPACE).getValue(VPAIDMetadata.NON_LINEAR_CREATIVE); + // Quick solution to pass mast container info over to VPAIDElement. There may be a better way (metadata maybe?) + try{ + if ((mediaElement as VPAIDElement).MASTWidth == -1) + { + (mediaElement as VPAIDElement).MASTWidth = container["width"]; + (mediaElement as VPAIDElement).MASTHeight = container["height"]; + } + } + catch(error:Error) {} + } + if(nonlinear) + { + //Currently we support running only 1 nonlinear Ad per ad call. + if (insertionIndex == 0) + { + //store content video element + tempMediaElement = serialElement.getChildAt(0); + + parellelElement = new ParallelElement(); + parellelElement.addChild(tempMediaElement); + parellelElement.addChild(mediaElement); + + //serialElement.addChild(parellelElement); + } + }else{ + + var companionElement:Boolean = inlineElement is CompanionElement; + if(!companionElement) + { + // If we are inserting at zero, we need to remove the original and then + // add it again to force SerialElement to update it's listening index + if (insertionIndex == 0) + { + tempMediaElement = serialElement.removeChildAt(0); + } + + if (!(mediaElement is VPAIDElement)) + { + mediaContainer = container as MediaContainer; + mediaContainer.buttonMode = true; + mediaContainer.addEventListener(MouseEvent.MOUSE_UP, onContainerClick); + + if(mediaElement is VideoElement) + { + + if(mediaElement.hasTrait(MediaTraitType.TIME)) + { + + var timeTrait:TimeTrait = mediaElement.getTrait(MediaTraitType.TIME) as TimeTrait; + timeTrait.addEventListener(TimeEvent.COMPLETE, onTimeComplete); + + } + } + + + } + serialElement.addChildAt(inlineElement, insertionIndex); + + if (tempMediaElement != null) + { + serialElement.addChild(tempMediaElement); + } + } + } + //Currently we support running only 1 nonlinear Ad per ad call. There are sizing issues with adding multiple + //parallel elements to a serial element that need to be resolved. Future revisions will allow running multiple nonlinear Ads + if(parellelElement) + { + super.proxiedElement = parellelElement; + } + + + } + // Now we can remove the custom PlayTrait + this.removeCustomPlayTrait(); + } + + private function onTimeComplete(e:TimeEvent):void + { + + mediaContainer.buttonMode = false; + mediaContainer.removeEventListener(MouseEvent.MOUSE_UP, onContainerClick); + } + + private function onContainerClick(event:MouseEvent):void + { + var vastMetadata:Metadata = proxiedElement.getMetadata(VASTMetadata.NAMESPACE); + if(vastMetadata) + vastMetadata.addValue(VASTMetadata.CLICKTHRU, event); + } + + private function getInsertionIndex(serialElement:SerialElement, condition:MASTCondition):int + { + // Generally, the insertion index is the index of the current + // child, so that the inserted child becomes the new current child. + var index:int = 0; + + if ((condition.type == MASTConditionType.EVENT) && (MASTConditionManager.conditionIsPostRoll(condition))) + { + index++; + } + else + { + // However, if our current child is in the midst of playback, we + // don't want to interrupt it, so we insert immediately after the + // current child. + var currentChild:MediaElement = serialElement.getChildAt(index); + if (currentChild != null) + { + // Treat it as playing if it's playing or has a positive currentTime. + var timeTrait:TimeTrait = currentChild.getTrait(MediaTraitType.TIME) as TimeTrait; + if (timeTrait != null && timeTrait.currentTime > 0) + { + index++; + } + else + { + var playTrait:PlayTrait = currentChild.getTrait(MediaTraitType.PLAY) as PlayTrait; + if (playTrait != null && playTrait.playState == PlayState.PLAYING) + { + index++; + } + } + } + } + + CONFIG::LOGGING + { + logger.debug("MASTProxyElement - getInsertionIndex() about to return "+index); + } + return index; + } + + private var loadTrait:MASTLoadTrait; + private var mediaFactory:MediaFactory; + private var mediaContainer:MediaContainer; + private static const ERROR_MISSING_MAST_METADATA:String = "Media Element is missing MAST metadata"; + private static const ERROR_MISSING_RESOURCE:String = "Media Element is missing a valid resource"; + + CONFIG::LOGGING + private static const logger:Logger = Log.getLogger("org.osmf.mast.media.MASTProxyElement"); + + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTCondition.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTCondition.as index c63f8ce..48be60d 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTCondition.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTCondition.as @@ -1,108 +1,108 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* -*****************************************************/ -package org.osmf.mast.model -{ - import __AS3__.vec.Vector; - - import org.osmf.mast.types.MASTConditionOperator; - import org.osmf.mast.types.MASTConditionType; - - /** - * Condition defined in a MAST document. - **/ - public class MASTCondition - { - /** - * Constructor. - * - * @param type Specifies the type of condition as defined by the constants in the MASTConditionType class. - * @param name The name of the property or event to be used in evaluation. - * @param value The value that a property will be evaluated against. - * @param operator The operator to use during evaluation as defined by the constants in the MASTConditionOperator class. - * @param childConditions Any child conditions present in the MAST document. - */ - public function MASTCondition(type:MASTConditionType, name:String, value:String=null, - operator:MASTConditionOperator=null, childConditions:Vector.=null) - { - // EVENT conditions don't take most other params. - if (type == MASTConditionType.EVENT && ((name == null) || (name.length == 0))) - { - throw new ArgumentError(); - } - // PROPERTY conditions do take most other params. - else if (type == MASTConditionType.PROPERTY && (((value == null) || (value.length == 0)) || operator == null)) - { - throw new ArgumentError(); - } - - _type = type; - _name = name; - _value = value; - _operator = operator; - _childConditions = childConditions; - } - - /** - * The type of condition as defined by the constants - * in the MASTConditionType class. - */ - public function get type():MASTConditionType - { - return _type; - } - - public function get name():String - { - return _name; - } - - /** - * The value that a property condition will be evaluated against. - */ - public function get value():Object - { - return _value; - } - - /** - * The operator to use during evaluation as defined by the constants - * in the MASTConditionOperator class. - */ - public function get operator():MASTConditionOperator - { - return _operator; - } - - public function get childConditions():Vector. - { - return _childConditions; - } - - private var _type:MASTConditionType; - private var _name:String; - private var _value:String; - private var _operator:MASTConditionOperator; - private var _childConditions:Vector.; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* +*****************************************************/ +package org.osmf.mast.model +{ + import __AS3__.vec.Vector; + + import org.osmf.mast.types.MASTConditionOperator; + import org.osmf.mast.types.MASTConditionType; + + /** + * Condition defined in a MAST document. + **/ + public class MASTCondition + { + /** + * Constructor. + * + * @param type Specifies the type of condition as defined by the constants in the MASTConditionType class. + * @param name The name of the property or event to be used in evaluation. + * @param value The value that a property will be evaluated against. + * @param operator The operator to use during evaluation as defined by the constants in the MASTConditionOperator class. + * @param childConditions Any child conditions present in the MAST document. + */ + public function MASTCondition(type:MASTConditionType, name:String, value:String=null, + operator:MASTConditionOperator=null, childConditions:Vector.=null) + { + // EVENT conditions don't take most other params. + if (type == MASTConditionType.EVENT && ((name == null) || (name.length == 0))) + { + throw new ArgumentError(); + } + // PROPERTY conditions do take most other params. + else if (type == MASTConditionType.PROPERTY && (((value == null) || (value.length == 0)) || operator == null)) + { + throw new ArgumentError(); + } + + _type = type; + _name = name; + _value = value; + _operator = operator; + _childConditions = childConditions; + } + + /** + * The type of condition as defined by the constants + * in the MASTConditionType class. + */ + public function get type():MASTConditionType + { + return _type; + } + + public function get name():String + { + return _name; + } + + /** + * The value that a property condition will be evaluated against. + */ + public function get value():Object + { + return _value; + } + + /** + * The operator to use during evaluation as defined by the constants + * in the MASTConditionOperator class. + */ + public function get operator():MASTConditionOperator + { + return _operator; + } + + public function get childConditions():Vector. + { + return _childConditions; + } + + private var _type:MASTConditionType; + private var _name:String; + private var _value:String; + private var _operator:MASTConditionOperator; + private var _childConditions:Vector.; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTDocument.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTDocument.as index bbd4ea0..37e5207 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTDocument.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTDocument.as @@ -1,69 +1,69 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* -*****************************************************/ -package org.osmf.mast.model -{ - import __AS3__.vec.Vector; - - /** - * This class represents the top level of the MAST - * document object model. - */ - public class MASTDocument - { - /** - * Constructor. - * - * @param version The MAST document version number if - * available in the document. - */ - public function MASTDocument(version:Number) - { - _version = version; - } - - /** - * The collection of triggers from the MAST document. - */ - public function get triggers():Vector. - { - return _triggers; - } - - /** - * Adds a MASTTrigger object to the collection of MAST triggers. - */ - public function addTrigger(value:MASTTrigger):void - { - if (_triggers == null) - { - _triggers = new Vector.(); - } - - _triggers.push(value); - } - - private var _triggers:Vector.; - private var _version:Number; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* +*****************************************************/ +package org.osmf.mast.model +{ + import __AS3__.vec.Vector; + + /** + * This class represents the top level of the MAST + * document object model. + */ + public class MASTDocument + { + /** + * Constructor. + * + * @param version The MAST document version number if + * available in the document. + */ + public function MASTDocument(version:Number) + { + _version = version; + } + + /** + * The collection of triggers from the MAST document. + */ + public function get triggers():Vector. + { + return _triggers; + } + + /** + * Adds a MASTTrigger object to the collection of MAST triggers. + */ + public function addTrigger(value:MASTTrigger):void + { + if (_triggers == null) + { + _triggers = new Vector.(); + } + + _triggers.push(value); + } + + private var _triggers:Vector.; + private var _version:Number; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTSource.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTSource.as index 3523660..8d4ea89 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTSource.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTSource.as @@ -1,128 +1,128 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* -*****************************************************/ -package org.osmf.mast.model -{ - import __AS3__.vec.Vector; - - /** - * The MASTSource class represents a source element in a MAST - * document. - */ - public class MASTSource - { - /** - * Constructor. - * - * @param url The source document to act upon when triggered - * @param format The format of the source document, i.e., "vast" - * @param targets A vector of targets specified in the source element - * @param altReference The ID of the source to act upon when triggered - * @param sources The Child sources - */ - public function MASTSource(url:String, format:String, targets:Vector.=null, - altReference:String=null, sources:Vector.=null) - { - _url = url; - _format = format; - _targets = targets; - _altReference = altReference; - _sources = sources; - } - - /** - * The URL to retrieve a source from, for example a link to a VAST document - */ - public function get url():String - { - return _url; - } - - /** - * This is used to key the source against a resource already known by the - * player. To prevent collisions it can be keyed with the URL when possible. - */ - public function get altReference():String - { - return _altReference; - } - - /** - * The format this source is in, to be used to determine a handler for the - * payload. Examples would be 'vast', 'uif', etc. - */ - public function get format():String - { - return _format; - } - - /** - * Child sources of this source. - */ - public function get sources():Vector. - { - return _sources; - } - - /** - * Child targets of this source. - */ - public function get targets():Vector. - { - return _targets; - } - - /** - * Adds a child source to this source. - */ - public function addChildSource(value:MASTSource):void - { - if (_sources == null) - { - _sources = new Vector.(); - } - - _sources.push(value); - } - - /** - * Adds a child target to this source. - */ - public function addTarget(val:MASTTarget):void - { - if (_targets == null) - { - _targets = new Vector.(); - } - - _targets.push(val); - } - - private var _url:String; - private var _altReference:String; - private var _format:String; - private var _sources:Vector.; - private var _targets:Vector.; - - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* +*****************************************************/ +package org.osmf.mast.model +{ + import __AS3__.vec.Vector; + + /** + * The MASTSource class represents a source element in a MAST + * document. + */ + public class MASTSource + { + /** + * Constructor. + * + * @param url The source document to act upon when triggered + * @param format The format of the source document, i.e., "vast" + * @param targets A vector of targets specified in the source element + * @param altReference The ID of the source to act upon when triggered + * @param sources The Child sources + */ + public function MASTSource(url:String, format:String, targets:Vector.=null, + altReference:String=null, sources:Vector.=null) + { + _url = url; + _format = format; + _targets = targets; + _altReference = altReference; + _sources = sources; + } + + /** + * The URL to retrieve a source from, for example a link to a VAST document + */ + public function get url():String + { + return _url; + } + + /** + * This is used to key the source against a resource already known by the + * player. To prevent collisions it can be keyed with the URL when possible. + */ + public function get altReference():String + { + return _altReference; + } + + /** + * The format this source is in, to be used to determine a handler for the + * payload. Examples would be 'vast', 'uif', etc. + */ + public function get format():String + { + return _format; + } + + /** + * Child sources of this source. + */ + public function get sources():Vector. + { + return _sources; + } + + /** + * Child targets of this source. + */ + public function get targets():Vector. + { + return _targets; + } + + /** + * Adds a child source to this source. + */ + public function addChildSource(value:MASTSource):void + { + if (_sources == null) + { + _sources = new Vector.(); + } + + _sources.push(value); + } + + /** + * Adds a child target to this source. + */ + public function addTarget(val:MASTTarget):void + { + if (_targets == null) + { + _targets = new Vector.(); + } + + _targets.push(val); + } + + private var _url:String; + private var _altReference:String; + private var _format:String; + private var _sources:Vector.; + private var _targets:Vector.; + + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTTarget.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTTarget.as index 499848b..dda8660 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTTarget.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTTarget.as @@ -1,87 +1,87 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* -*****************************************************/ -package org.osmf.mast.model -{ - import __AS3__.vec.Vector; - - /** - * Represents a target object in a MAST document. - */ - public class MASTTarget - { - /** - * Constructor. - * - * @param id The type of target, can be used for keying particular payload items to a target. - * @param regionName A named region / container or other target that can be used by a player. - */ - public function MASTTarget(id:String, regionName:String) - { - _id = id; - _regionName = regionName; - - } - - /** - * The type of target, can be used for keying particular payload items to a target. - */ - public function get id():String - { - return _id; - } - - /** - * A named region / container or other target that can be used by a player. - */ - public function get regionName():String - { - return _regionName; - } - - /** - * Child targets for this target. - */ - public function get targets():Vector. - { - return _targets; - } - - /** - * Adds a child target to this target. - */ - public function addChildTarget(value:MASTTarget):void - { - if (_targets == null) - { - _targets = new Vector.(); - } - - _targets.push(value); - } - - private var _id:String; - private var _regionName:String; - private var _targets:Vector.; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* +*****************************************************/ +package org.osmf.mast.model +{ + import __AS3__.vec.Vector; + + /** + * Represents a target object in a MAST document. + */ + public class MASTTarget + { + /** + * Constructor. + * + * @param id The type of target, can be used for keying particular payload items to a target. + * @param regionName A named region / container or other target that can be used by a player. + */ + public function MASTTarget(id:String, regionName:String) + { + _id = id; + _regionName = regionName; + + } + + /** + * The type of target, can be used for keying particular payload items to a target. + */ + public function get id():String + { + return _id; + } + + /** + * A named region / container or other target that can be used by a player. + */ + public function get regionName():String + { + return _regionName; + } + + /** + * Child targets for this target. + */ + public function get targets():Vector. + { + return _targets; + } + + /** + * Adds a child target to this target. + */ + public function addChildTarget(value:MASTTarget):void + { + if (_targets == null) + { + _targets = new Vector.(); + } + + _targets.push(value); + } + + private var _id:String; + private var _regionName:String; + private var _targets:Vector.; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTTrigger.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTTrigger.as index 28b8068..678fb70 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTTrigger.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/model/MASTTrigger.as @@ -1,128 +1,128 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -* Contributor(s): Akamai Technologies -* -*****************************************************/ -package org.osmf.mast.model -{ - import __AS3__.vec.Vector; - - /** - * Trigger defined in a MAST document. - **/ - public class MASTTrigger - { - /** - * Constructor. - * - * @param id A reference for this trigger. - * @param description User provided description, for reference purposes only - */ - public function MASTTrigger( id:String, description:String) - { - _id = id; - _description = description; - } - - /** - * Reference for this trigger. - */ - public function get id():String - { - return _id; - } - - /** - * Description for this trigger. - */ - public function get description():String - { - return _description; - } - - /** - * Collection of start conditions for this trigger. - */ - public function get startConditions():Vector. - { - return _startConditions; - } - - public function set startConditions(value:Vector.):void - { - if (_startConditions == null) - { - _startConditions = new Vector.(); - } - - _startConditions = _startConditions.concat(value); - } - - /** - * Collection of end conditions for this trigger. - */ - public function get endConditions():Vector. - { - return _endConditions; - } - - /** - * Adds an end condition to the collection of end collections. - */ - public function set endConditions(value:Vector.):void - { - if (_endConditions == null) - { - _endConditions = new Vector.(); - } - - _endConditions = _endConditions.concat(value); - } - - /** - * Collection of MAST sources for this trigger. - */ - public function get sources():Vector. - { - return _sources; - } - - - /** - * Adds a source to the collection of sources. - */ - public function addSource(value:MASTSource):void - { - if (_sources == null) - { - _sources = new Vector.(); - } - - _sources.push(value); - } - - private var _id:String; - private var _description:String; - private var _startConditions:Vector.; - private var _endConditions:Vector.; - private var _sources:Vector.; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +* Contributor(s): Akamai Technologies +* +*****************************************************/ +package org.osmf.mast.model +{ + import __AS3__.vec.Vector; + + /** + * Trigger defined in a MAST document. + **/ + public class MASTTrigger + { + /** + * Constructor. + * + * @param id A reference for this trigger. + * @param description User provided description, for reference purposes only + */ + public function MASTTrigger( id:String, description:String) + { + _id = id; + _description = description; + } + + /** + * Reference for this trigger. + */ + public function get id():String + { + return _id; + } + + /** + * Description for this trigger. + */ + public function get description():String + { + return _description; + } + + /** + * Collection of start conditions for this trigger. + */ + public function get startConditions():Vector. + { + return _startConditions; + } + + public function set startConditions(value:Vector.):void + { + if (_startConditions == null) + { + _startConditions = new Vector.(); + } + + _startConditions = _startConditions.concat(value); + } + + /** + * Collection of end conditions for this trigger. + */ + public function get endConditions():Vector. + { + return _endConditions; + } + + /** + * Adds an end condition to the collection of end collections. + */ + public function set endConditions(value:Vector.):void + { + if (_endConditions == null) + { + _endConditions = new Vector.(); + } + + _endConditions = _endConditions.concat(value); + } + + /** + * Collection of MAST sources for this trigger. + */ + public function get sources():Vector. + { + return _sources; + } + + + /** + * Adds a source to the collection of sources. + */ + public function addSource(value:MASTSource):void + { + if (_sources == null) + { + _sources = new Vector.(); + } + + _sources.push(value); + } + + private var _id:String; + private var _description:String; + private var _startConditions:Vector.; + private var _endConditions:Vector.; + private var _sources:Vector.; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/parser/MASTParser.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/parser/MASTParser.as index ab343b4..203877d 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/parser/MASTParser.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/parser/MASTParser.as @@ -21,12 +21,12 @@ *****************************************************/ package org.osmf.mast.parser { - import __AS3__.vec.Vector; - - import flash.events.EventDispatcher; - - import org.osmf.mast.model.*; - import org.osmf.mast.types.MASTConditionOperator; + import __AS3__.vec.Vector; + + import flash.events.EventDispatcher; + + import org.osmf.mast.model.*; + import org.osmf.mast.types.MASTConditionOperator; import org.osmf.mast.types.MASTConditionType; CONFIG::LOGGING { diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/traits/MASTPlayTrait.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/traits/MASTPlayTrait.as index 5dfae25..25834b7 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/traits/MASTPlayTrait.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/traits/MASTPlayTrait.as @@ -1,70 +1,70 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.mast.traits -{ - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - - /** - * The purpose of this class is to provide a PlayTrait - * that can inform another class that a play request - * is pending. For example if a proxy class were to - * override the PlayTrait, it could use this class - * to determine whether or not to call play() on the original - * PlayTrait when removing this trait. - */ - public class MASTPlayTrait extends PlayTrait - { - /** - * @inheritDoc - */ - public function MASTPlayTrait() - { - super(); - - _playRequestPending = false; - } - - /** - * Returns true if a play request was made on this trait. - */ - public function get playRequestPending():Boolean - { - return _playRequestPending; - } - - /** - * @inheritDoc - */ - override protected function playStateChangeStart(newPlayState:String):void - { - _playRequestPending = false; - - if (newPlayState == PlayState.PLAYING) - { - _playRequestPending = true; - } - } - - private var _playRequestPending:Boolean; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.mast.traits +{ + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + + /** + * The purpose of this class is to provide a PlayTrait + * that can inform another class that a play request + * is pending. For example if a proxy class were to + * override the PlayTrait, it could use this class + * to determine whether or not to call play() on the original + * PlayTrait when removing this trait. + */ + public class MASTPlayTrait extends PlayTrait + { + /** + * @inheritDoc + */ + public function MASTPlayTrait() + { + super(); + + _playRequestPending = false; + } + + /** + * Returns true if a play request was made on this trait. + */ + public function get playRequestPending():Boolean + { + return _playRequestPending; + } + + /** + * @inheritDoc + */ + override protected function playStateChangeStart(newPlayState:String):void + { + _playRequestPending = false; + + if (newPlayState == PlayState.PLAYING) + { + _playRequestPending = true; + } + } + + private var _playRequestPending:Boolean; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/types/MASTConditionOperator.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/types/MASTConditionOperator.as index 7772b72..d22f821 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/types/MASTConditionOperator.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/types/MASTConditionOperator.as @@ -1,56 +1,56 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.mast.types -{ - /** - * This class represents the valid operator values for a MAST - * document. - */ - public class MASTConditionOperator - { - public static const EQ:MASTConditionOperator = new MASTConditionOperator("EQ"); - public static const NEQ:MASTConditionOperator = new MASTConditionOperator("NEQ"); - public static const GTR:MASTConditionOperator = new MASTConditionOperator("GTR"); - public static const GEQ:MASTConditionOperator = new MASTConditionOperator("GEQ"); - public static const LT:MASTConditionOperator = new MASTConditionOperator("LT"); - public static const LEQ:MASTConditionOperator = new MASTConditionOperator("LEQ"); - public static const MOD:MASTConditionOperator = new MASTConditionOperator("MOD"); - - /** - * @private - **/ - public function MASTConditionOperator(operator:String) - { - _operator = operator; - } - - /** - * Returns string value of the operator. - */ - public function get operator():String - { - return _operator; - } - - private var _operator:String; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.mast.types +{ + /** + * This class represents the valid operator values for a MAST + * document. + */ + public class MASTConditionOperator + { + public static const EQ:MASTConditionOperator = new MASTConditionOperator("EQ"); + public static const NEQ:MASTConditionOperator = new MASTConditionOperator("NEQ"); + public static const GTR:MASTConditionOperator = new MASTConditionOperator("GTR"); + public static const GEQ:MASTConditionOperator = new MASTConditionOperator("GEQ"); + public static const LT:MASTConditionOperator = new MASTConditionOperator("LT"); + public static const LEQ:MASTConditionOperator = new MASTConditionOperator("LEQ"); + public static const MOD:MASTConditionOperator = new MASTConditionOperator("MOD"); + + /** + * @private + **/ + public function MASTConditionOperator(operator:String) + { + _operator = operator; + } + + /** + * Returns string value of the operator. + */ + public function get operator():String + { + return _operator; + } + + private var _operator:String; + } +} diff --git a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/types/MASTConditionType.as b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/types/MASTConditionType.as index 1dc1477..a1aa4a5 100644 --- a/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/types/MASTConditionType.as +++ b/lib/osmf/samples/MASTPlugin/src/org/osmf/mast/types/MASTConditionType.as @@ -1,51 +1,51 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.mast.types -{ - /** - * This class represents the valid condition types - * in a MAST document. - */ - public class MASTConditionType - { - public static const EVENT:MASTConditionType = new MASTConditionType("event"); - public static const PROPERTY:MASTConditionType = new MASTConditionType("property"); - - /** - * @private - **/ - public function MASTConditionType(type:String) - { - _type = type; - } - - /** - * Returns the condition type as a string. - */ - public function get type():String - { - return _type; - } - - private var _type:String; - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.mast.types +{ + /** + * This class represents the valid condition types + * in a MAST document. + */ + public class MASTConditionType + { + public static const EVENT:MASTConditionType = new MASTConditionType("event"); + public static const PROPERTY:MASTConditionType = new MASTConditionType("property"); + + /** + * @private + **/ + public function MASTConditionType(type:String) + { + _type = type; + } + + /** + * Returns the condition type as a string. + */ + public function get type():String + { + return _type; + } + + private var _type:String; + } +} diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/.actionScriptProperties b/lib/osmf/samples/MASTPluginIntegrationTest/.actionScriptProperties index 58a56c8..45fd86e 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/.actionScriptProperties +++ b/lib/osmf/samples/MASTPluginIntegrationTest/.actionScriptProperties @@ -1,21 +1,21 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/.flexProperties b/lib/osmf/samples/MASTPluginIntegrationTest/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/.flexProperties +++ b/lib/osmf/samples/MASTPluginIntegrationTest/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/MASTPluginIntegrationTest.mxml b/lib/osmf/samples/MASTPluginIntegrationTest/src/MASTPluginIntegrationTest.mxml index 833595c..f7bff48 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/MASTPluginIntegrationTest.mxml +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/MASTPluginIntegrationTest.mxml @@ -1,48 +1,48 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/MASTPluginIntegrationTests.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/MASTPluginIntegrationTests.as index 9b508ff..c605957 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/MASTPluginIntegrationTests.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/MASTPluginIntegrationTests.as @@ -1,27 +1,27 @@ -package org.osmf -{ - import flexunit.framework.TestSuite; - - import org.osmf.test.mast.loader.TestMASTLoader; - import org.osmf.test.mast.adapter.TestMASTAdapter; - import org.osmf.test.mast.media.TestMASTProxyElement; - import org.osmf.test.mast.managers.TestMASTConditionManager; - import org.osmf.test.mast.TestMASTPluginInfo; - import org.osmf.test.mast.parser.TestMASTParser; - - public class MASTPluginIntegrationTests extends TestSuite - { - public function MASTPluginIntegrationTests(param:Object=null) - { - super(param); - - addTestSuite(TestMASTLoader); - addTestSuite(TestMASTAdapter); - addTestSuite(TestMASTProxyElement); - addTestSuite(TestMASTPluginInfo); - addTestSuite(TestMASTParser); - addTestSuite(TestMASTConditionManager); - } - - } +package org.osmf +{ + import flexunit.framework.TestSuite; + + import org.osmf.test.mast.loader.TestMASTLoader; + import org.osmf.test.mast.adapter.TestMASTAdapter; + import org.osmf.test.mast.media.TestMASTProxyElement; + import org.osmf.test.mast.managers.TestMASTConditionManager; + import org.osmf.test.mast.TestMASTPluginInfo; + import org.osmf.test.mast.parser.TestMASTParser; + + public class MASTPluginIntegrationTests extends TestSuite + { + public function MASTPluginIntegrationTests(param:Object=null) + { + super(param); + + addTestSuite(TestMASTLoader); + addTestSuite(TestMASTAdapter); + addTestSuite(TestMASTProxyElement); + addTestSuite(TestMASTPluginInfo); + addTestSuite(TestMASTParser); + addTestSuite(TestMASTConditionManager); + } + + } } \ No newline at end of file diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/TestMASTPluginInfo.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/TestMASTPluginInfo.as index e629950..a543c50 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/TestMASTPluginInfo.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/TestMASTPluginInfo.as @@ -1,64 +1,64 @@ -package org.osmf.test.mast -{ - import flexunit.framework.TestCase; - - import org.osmf.mast.MASTPluginInfo; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.PluginInfo; - - public class TestMASTPluginInfo extends TestCase - { - public function testGetMediaInfoAt():void - { - var pluginInfo:PluginInfo = new MASTPluginInfo(); - - assertNotNull(pluginInfo); - - var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(0); - - assertNotNull(item); - } - - public function testGetMediaFactoryItemAtWithBadIndex():void - { - var pluginInfo:PluginInfo = new MASTPluginInfo(); - - assertNotNull(pluginInfo); - - try - { - var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(10); - fail(); - } - catch(error:RangeError) - { - } - } - - public function testIsFrameworkVersionSupported():void - { - var pluginInfo:PluginInfo = new MASTPluginInfo(); - assertNotNull(pluginInfo); - - assertEquals(true, pluginInfo.isFrameworkVersionSupported("1.0.0")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.0.1")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.5.1")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.7.0")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.8.0")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.4.9")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported(null)); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("abc")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("foo.bar")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("foobar.")); - } - - public function testNumMediaInfos():void - { - var pluginInfo:PluginInfo = new MASTPluginInfo(); - assertNotNull(pluginInfo); - - assertTrue(pluginInfo.numMediaFactoryItems > 0); - } - } -} +package org.osmf.test.mast +{ + import flexunit.framework.TestCase; + + import org.osmf.mast.MASTPluginInfo; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.PluginInfo; + + public class TestMASTPluginInfo extends TestCase + { + public function testGetMediaInfoAt():void + { + var pluginInfo:PluginInfo = new MASTPluginInfo(); + + assertNotNull(pluginInfo); + + var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(0); + + assertNotNull(item); + } + + public function testGetMediaFactoryItemAtWithBadIndex():void + { + var pluginInfo:PluginInfo = new MASTPluginInfo(); + + assertNotNull(pluginInfo); + + try + { + var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(10); + fail(); + } + catch(error:RangeError) + { + } + } + + public function testIsFrameworkVersionSupported():void + { + var pluginInfo:PluginInfo = new MASTPluginInfo(); + assertNotNull(pluginInfo); + + assertEquals(true, pluginInfo.isFrameworkVersionSupported("1.0.0")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.0.1")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.5.1")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.7.0")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.8.0")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.4.9")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported(null)); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("abc")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("foo.bar")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("foobar.")); + } + + public function testNumMediaInfos():void + { + var pluginInfo:PluginInfo = new MASTPluginInfo(); + assertNotNull(pluginInfo); + + assertTrue(pluginInfo.numMediaFactoryItems > 0); + } + } +} diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/adapter/TestMASTAdapter.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/adapter/TestMASTAdapter.as index bcae62d..c2f1ff5 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/adapter/TestMASTAdapter.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/adapter/TestMASTAdapter.as @@ -1,28 +1,28 @@ -package org.osmf.test.mast.adapter -{ - import flexunit.framework.TestCase; - - import org.osmf.mast.adapter.MASTAdapter; - - public class TestMASTAdapter extends TestCase - { - override public function setUp():void - { - _mastAdapter = new MASTAdapter(); - super.setUp(); - } - - override public function tearDown():void - { - super.tearDown(); - _mastAdapter = null; - } - - public function testLookup():void - { - assertEquals("TimeTrait.duration", _mastAdapter.lookup(MASTAdapter.DURATION)); - } - - private var _mastAdapter:MASTAdapter; - } -} +package org.osmf.test.mast.adapter +{ + import flexunit.framework.TestCase; + + import org.osmf.mast.adapter.MASTAdapter; + + public class TestMASTAdapter extends TestCase + { + override public function setUp():void + { + _mastAdapter = new MASTAdapter(); + super.setUp(); + } + + override public function tearDown():void + { + super.tearDown(); + _mastAdapter = null; + } + + public function testLookup():void + { + assertEquals("TimeTrait.duration", _mastAdapter.lookup(MASTAdapter.DURATION)); + } + + private var _mastAdapter:MASTAdapter; + } +} diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/loader/TestMASTLoader.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/loader/TestMASTLoader.as index 191b5af..452cf01 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/loader/TestMASTLoader.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/loader/TestMASTLoader.as @@ -1,175 +1,175 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.test.mast.loader -{ - import flash.events.*; - - import org.osmf.events.LoaderEvent; - import org.osmf.mast.loader.*; - import org.osmf.mast.model.*; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.test.mast.MASTTestConstants; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.traits.TestLoaderBase; - import org.osmf.utils.HTTPLoader; - import org.osmf.utils.MockHTTPLoader; - import org.osmf.utils.NullResource; - - public class TestMASTLoader extends TestLoaderBase - { - override public function setUp():void - { - eventDispatcher = new EventDispatcher(); - - // Change to HTTPLoader to run against the network. - httpLoader = new MockHTTPLoader(); - - super.setUp(); - } - - override public function tearDown():void - { - super.tearDown(); - - eventDispatcher = null; - httpLoader = null; - } - - public function testLoadWithValidMASTDocument():void - { - eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidMASTDocument); - loader.load(createLoadTrait(loader, SUCCESSFUL_RESOURCE)); - } - - private function onTestLoadWithValidMASTDocument(event:LoaderEvent):void - { - if (event.newState == LoadState.READY) - { - // Just check that we got a valid MAST DOM back - var document:MASTDocument = MASTLoadTrait(event.loadTrait).document; - assertTrue(document != null); - assertTrue(document.triggers.length == 1); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - - //--------------------------------------------------------------------- - - override protected function createInterfaceObject(... args):Object - { - return new MASTLoader(httpLoader); - } - - override protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - var mockLoader:MockHTTPLoader = httpLoader as MockHTTPLoader; - if (mockLoader) - { - if (resource == successfulResource) - { - mockLoader.setExpectationForURL - ( URLResource(resource).url - , true - , MASTTestConstants.MAST_DOCUMENT_CONTENTS - ); - } - else if (resource == failedResource) - { - mockLoader.setExpectationForURL - ( URLResource(resource).url - , false - , null - ); - } - else if (resource == unhandledResource) - { - mockLoader.setExpectationForURL - ( URLResource(resource).url - , false - , null - ); - } - } - return new MASTLoadTrait(loader, resource); - } - - override protected function get successfulResource():MediaResourceBase - { - return SUCCESSFUL_RESOURCE; - } - - override protected function get failedResource():MediaResourceBase - { - return FAILED_RESOURCE; - } - - override protected function get unhandledResource():MediaResourceBase - { - return UNHANDLED_RESOURCE; - } - - override public function testCanHandleResource():void - { - super.testCanHandleResource(); - - // Verify some valid resources. - assertTrue(loader.canHandleResource(new URLResource("http://example.com"))); - assertTrue(loader.canHandleResource(new URLResource("http://example.com/video.flv"))); - assertTrue(loader.canHandleResource(new URLResource("http://example.com/script.php?param=value"))); - assertTrue(loader.canHandleResource(new URLResource("https://example.com"))); - assertTrue(loader.canHandleResource(new URLResource("https://example.com/video.flv"))); - assertTrue(loader.canHandleResource(new URLResource("https://example.com/script.php?param=value"))); - assertTrue(loader.canHandleResource(new URLResource("assets/audio.mp3"))); - assertTrue(loader.canHandleResource(new URLResource("audio.mp3"))); - assertTrue(loader.canHandleResource(new URLResource("foo"))); - - // And some invalid ones. - assertFalse(loader.canHandleResource(new URLResource("file:///audio.mp3"))); - assertFalse(loader.canHandleResource(new URLResource("httpt://example.com"))); - assertFalse(loader.canHandleResource(new URLResource(""))); - assertFalse(loader.canHandleResource(new URLResource(null))); - assertFalse(loader.canHandleResource(new NullResource())); - assertFalse(loader.canHandleResource(null)); - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder - } - - private static const TEST_TIME:int = 8000; - - private var httpLoader:HTTPLoader; - private var eventDispatcher:EventDispatcher; - - private static const SUCCESSFUL_RESOURCE:URLResource = new URLResource(MASTTestConstants.MAST_DOCUMENT_URL); - private static const FAILED_RESOURCE:URLResource = new URLResource(MASTTestConstants.MISSING_MAST_DOCUMENT_URL); - private static const UNHANDLED_RESOURCE:URLResource = new URLResource("ftp://example.com"); - - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.test.mast.loader +{ + import flash.events.*; + + import org.osmf.events.LoaderEvent; + import org.osmf.mast.loader.*; + import org.osmf.mast.model.*; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.test.mast.MASTTestConstants; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.traits.TestLoaderBase; + import org.osmf.utils.HTTPLoader; + import org.osmf.utils.MockHTTPLoader; + import org.osmf.utils.NullResource; + + public class TestMASTLoader extends TestLoaderBase + { + override public function setUp():void + { + eventDispatcher = new EventDispatcher(); + + // Change to HTTPLoader to run against the network. + httpLoader = new MockHTTPLoader(); + + super.setUp(); + } + + override public function tearDown():void + { + super.tearDown(); + + eventDispatcher = null; + httpLoader = null; + } + + public function testLoadWithValidMASTDocument():void + { + eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidMASTDocument); + loader.load(createLoadTrait(loader, SUCCESSFUL_RESOURCE)); + } + + private function onTestLoadWithValidMASTDocument(event:LoaderEvent):void + { + if (event.newState == LoadState.READY) + { + // Just check that we got a valid MAST DOM back + var document:MASTDocument = MASTLoadTrait(event.loadTrait).document; + assertTrue(document != null); + assertTrue(document.triggers.length == 1); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + + //--------------------------------------------------------------------- + + override protected function createInterfaceObject(... args):Object + { + return new MASTLoader(httpLoader); + } + + override protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait + { + var mockLoader:MockHTTPLoader = httpLoader as MockHTTPLoader; + if (mockLoader) + { + if (resource == successfulResource) + { + mockLoader.setExpectationForURL + ( URLResource(resource).url + , true + , MASTTestConstants.MAST_DOCUMENT_CONTENTS + ); + } + else if (resource == failedResource) + { + mockLoader.setExpectationForURL + ( URLResource(resource).url + , false + , null + ); + } + else if (resource == unhandledResource) + { + mockLoader.setExpectationForURL + ( URLResource(resource).url + , false + , null + ); + } + } + return new MASTLoadTrait(loader, resource); + } + + override protected function get successfulResource():MediaResourceBase + { + return SUCCESSFUL_RESOURCE; + } + + override protected function get failedResource():MediaResourceBase + { + return FAILED_RESOURCE; + } + + override protected function get unhandledResource():MediaResourceBase + { + return UNHANDLED_RESOURCE; + } + + override public function testCanHandleResource():void + { + super.testCanHandleResource(); + + // Verify some valid resources. + assertTrue(loader.canHandleResource(new URLResource("http://example.com"))); + assertTrue(loader.canHandleResource(new URLResource("http://example.com/video.flv"))); + assertTrue(loader.canHandleResource(new URLResource("http://example.com/script.php?param=value"))); + assertTrue(loader.canHandleResource(new URLResource("https://example.com"))); + assertTrue(loader.canHandleResource(new URLResource("https://example.com/video.flv"))); + assertTrue(loader.canHandleResource(new URLResource("https://example.com/script.php?param=value"))); + assertTrue(loader.canHandleResource(new URLResource("assets/audio.mp3"))); + assertTrue(loader.canHandleResource(new URLResource("audio.mp3"))); + assertTrue(loader.canHandleResource(new URLResource("foo"))); + + // And some invalid ones. + assertFalse(loader.canHandleResource(new URLResource("file:///audio.mp3"))); + assertFalse(loader.canHandleResource(new URLResource("httpt://example.com"))); + assertFalse(loader.canHandleResource(new URLResource(""))); + assertFalse(loader.canHandleResource(new URLResource(null))); + assertFalse(loader.canHandleResource(new NullResource())); + assertFalse(loader.canHandleResource(null)); + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder + } + + private static const TEST_TIME:int = 8000; + + private var httpLoader:HTTPLoader; + private var eventDispatcher:EventDispatcher; + + private static const SUCCESSFUL_RESOURCE:URLResource = new URLResource(MASTTestConstants.MAST_DOCUMENT_URL); + private static const FAILED_RESOURCE:URLResource = new URLResource(MASTTestConstants.MISSING_MAST_DOCUMENT_URL); + private static const UNHANDLED_RESOURCE:URLResource = new URLResource("ftp://example.com"); + + } +} diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/managers/TestMASTConditionManager.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/managers/TestMASTConditionManager.as index 305a9cd..c585565 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/managers/TestMASTConditionManager.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/managers/TestMASTConditionManager.as @@ -1,149 +1,149 @@ -package org.osmf.test.mast.managers -{ - import flash.errors.*; - import flash.events.*; - import flash.utils.Timer; - import flash.utils.getDefinitionByName; - - import flexunit.framework.TestCase; - - import org.osmf.elements.VideoElement; - import org.osmf.events.MediaErrorEvent; - import org.osmf.events.MediaFactoryEvent; - import org.osmf.mast.MASTPluginInfo; - import org.osmf.mast.model.*; - import org.osmf.media.*; - import org.osmf.metadata.Metadata; - import org.osmf.net.NetLoader; - import org.osmf.traits.*; - import org.osmf.utils.*; - - public class TestMASTConditionManager extends TestCase - { - override public function setUp():void - { - super.setUp(); - - _eventDispatcher = new EventDispatcher(); - } - - override public function tearDown():void - { - _eventDispatcher = null; - _timer = null; - } - - public function testConditionManager():void - { - mediaFactory = new MediaFactory(); - mediaPlayer = new MediaPlayer(); - - loadPlugin(MAST_PLUGIN_INFOCLASS); - } - - private function loadPlugin(source:String):void - { - var pluginResource:MediaResourceBase; - if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file") - { - // This is a URL, create a URLResource - pluginResource = new URLResource(source); - } - else - { - // Assume this is a class - var pluginInfoRef:Class = getDefinitionByName(source) as Class; - pluginResource = new PluginInfoResource(new pluginInfoRef); - } - - loadPluginFromResource(pluginResource); - } - - private function loadPluginFromResource(pluginResource:MediaResourceBase):void - { - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); - mediaFactory.loadPlugin(pluginResource); - } - - private function onPluginLoaded(event:MediaFactoryEvent):void - { - trace(">>> Plugin successfully loaded."); - loadMainVideo(REMOTE_STREAM); - } - - private function onPluginLoadFailed(event:MediaFactoryEvent):void - { - trace(">>> Plugin failed to load."); - } - - private function loadMainVideo(url:String):void - { - var resource:URLResource = new URLResource(url); - // Assign to the resource the metadata that indicates that it should have a MAST - // document applied (and include the URL of that MAST document). - var metadata:Metadata = new Metadata(); - metadata.addValue(MASTPluginInfo.MAST_METADATA_KEY_URI, MAST_URL_TEST); - resource.addMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata); - - var mediaElement:MediaElement = mediaFactory.createMediaElement(resource); - - if (mediaElement == null) - { - var netLoader:NetLoader = new NetLoader(); - - // Add a default VideoElement - mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, createVideoElement)); - mediaElement = mediaFactory.createMediaElement(resource); - } - - mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true); - - _eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); - _timer = new Timer(30000, 1); - _timer.addEventListener(TimerEvent.TIMER, onTimer); - _timer.start(); - - mediaPlayer.media = mediaElement; - } - - private function createVideoElement():MediaElement - { - return new VideoElement(); - } - - private function onTimer(event:TimerEvent):void - { - _timer.removeEventListener(TimerEvent.TIMER, onTimer); - _eventDispatcher.dispatchEvent(new Event("testComplete")); - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - private function onMediaError(event:MediaErrorEvent):void - { - var errMsg:String = "Media error : ID="+event.error.errorID+" message="+event.error.message; - - trace(errMsg); - } - - private var mediaPlayer:MediaPlayer; - private var mediaFactory:MediaFactory; - private var _eventDispatcher:EventDispatcher; - private var _timer:Timer; - - private static const ASYNC_DELAY:Number = 90000; - - private static const MAST_PLUGIN_INFOCLASS:String = "org.osmf.mast.MASTPluginInfo"; - private static const loadTestRef:MASTPluginInfo = null; - - private static const MAST_URL_TEST:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_integration_test.xml"; - - private static const REMOTE_STREAM:String - = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - - } +package org.osmf.test.mast.managers +{ + import flash.errors.*; + import flash.events.*; + import flash.utils.Timer; + import flash.utils.getDefinitionByName; + + import flexunit.framework.TestCase; + + import org.osmf.elements.VideoElement; + import org.osmf.events.MediaErrorEvent; + import org.osmf.events.MediaFactoryEvent; + import org.osmf.mast.MASTPluginInfo; + import org.osmf.mast.model.*; + import org.osmf.media.*; + import org.osmf.metadata.Metadata; + import org.osmf.net.NetLoader; + import org.osmf.traits.*; + import org.osmf.utils.*; + + public class TestMASTConditionManager extends TestCase + { + override public function setUp():void + { + super.setUp(); + + _eventDispatcher = new EventDispatcher(); + } + + override public function tearDown():void + { + _eventDispatcher = null; + _timer = null; + } + + public function testConditionManager():void + { + mediaFactory = new MediaFactory(); + mediaPlayer = new MediaPlayer(); + + loadPlugin(MAST_PLUGIN_INFOCLASS); + } + + private function loadPlugin(source:String):void + { + var pluginResource:MediaResourceBase; + if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file") + { + // This is a URL, create a URLResource + pluginResource = new URLResource(source); + } + else + { + // Assume this is a class + var pluginInfoRef:Class = getDefinitionByName(source) as Class; + pluginResource = new PluginInfoResource(new pluginInfoRef); + } + + loadPluginFromResource(pluginResource); + } + + private function loadPluginFromResource(pluginResource:MediaResourceBase):void + { + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); + mediaFactory.loadPlugin(pluginResource); + } + + private function onPluginLoaded(event:MediaFactoryEvent):void + { + trace(">>> Plugin successfully loaded."); + loadMainVideo(REMOTE_STREAM); + } + + private function onPluginLoadFailed(event:MediaFactoryEvent):void + { + trace(">>> Plugin failed to load."); + } + + private function loadMainVideo(url:String):void + { + var resource:URLResource = new URLResource(url); + // Assign to the resource the metadata that indicates that it should have a MAST + // document applied (and include the URL of that MAST document). + var metadata:Metadata = new Metadata(); + metadata.addValue(MASTPluginInfo.MAST_METADATA_KEY_URI, MAST_URL_TEST); + resource.addMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata); + + var mediaElement:MediaElement = mediaFactory.createMediaElement(resource); + + if (mediaElement == null) + { + var netLoader:NetLoader = new NetLoader(); + + // Add a default VideoElement + mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, createVideoElement)); + mediaElement = mediaFactory.createMediaElement(resource); + } + + mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true); + + _eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); + _timer = new Timer(30000, 1); + _timer.addEventListener(TimerEvent.TIMER, onTimer); + _timer.start(); + + mediaPlayer.media = mediaElement; + } + + private function createVideoElement():MediaElement + { + return new VideoElement(); + } + + private function onTimer(event:TimerEvent):void + { + _timer.removeEventListener(TimerEvent.TIMER, onTimer); + _eventDispatcher.dispatchEvent(new Event("testComplete")); + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + private function onMediaError(event:MediaErrorEvent):void + { + var errMsg:String = "Media error : ID="+event.error.errorID+" message="+event.error.message; + + trace(errMsg); + } + + private var mediaPlayer:MediaPlayer; + private var mediaFactory:MediaFactory; + private var _eventDispatcher:EventDispatcher; + private var _timer:Timer; + + private static const ASYNC_DELAY:Number = 90000; + + private static const MAST_PLUGIN_INFOCLASS:String = "org.osmf.mast.MASTPluginInfo"; + private static const loadTestRef:MASTPluginInfo = null; + + private static const MAST_URL_TEST:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_integration_test.xml"; + + private static const REMOTE_STREAM:String + = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + + } } \ No newline at end of file diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/media/TestMASTProxyElement.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/media/TestMASTProxyElement.as index 4d3db75..37cdb4d 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/media/TestMASTProxyElement.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/media/TestMASTProxyElement.as @@ -1,189 +1,189 @@ -package org.osmf.test.mast.media -{ - import flash.errors.IllegalOperationError; - - import flexunit.framework.TestCase; - - import org.osmf.elements.VideoElement; - import org.osmf.events.LoadEvent; - import org.osmf.mast.MASTPluginInfo; - import org.osmf.mast.media.MASTProxyElement; - import org.osmf.media.MediaElement; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; +package org.osmf.test.mast.media +{ + import flash.errors.IllegalOperationError; + + import flexunit.framework.TestCase; + + import org.osmf.elements.VideoElement; + import org.osmf.events.LoadEvent; + import org.osmf.mast.MASTPluginInfo; + import org.osmf.mast.media.MASTProxyElement; + import org.osmf.media.MediaElement; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; import org.osmf.traits.PlayTrait; - - - public class TestMASTProxyElement extends TestCase - { - public function testConstructor():void - { - // Should throw an exception because there is no resource - try - { - new MASTProxyElement(new MediaElement()); - fail(); - } - catch(error:IllegalOperationError) - { - } - } - - public function testSetWrappedElement():void - { - var proxyElement:MASTProxyElement = new MASTProxyElement(); - - - // Should not throw an exception - try - { - proxyElement.proxiedElement = null; - } - catch(error:IllegalOperationError) - { - fail(); - } - } - - public function testWithNoMetadata():void - { - var resource:URLResource = new URLResource(REMOTE_STREAM); - var mediaElement:MediaElement = new MediaElement(); - mediaElement.resource = resource; - - try - { - new MASTProxyElement(mediaElement); - fail(); - } - catch(error:IllegalOperationError) - { - - } - } - - public function testWithMetadata():void - { - var mediaElement:VideoElement = new VideoElement(); - mediaElement.resource = createResourceWithMetadata(); - - try - { - new MASTProxyElement(mediaElement); - } - catch(error:IllegalOperationError) - { - fail(); - } - } - - public function testLoad():void - { - var mediaElement:MediaElement = new VideoElement(); - mediaElement.resource = createResourceWithMetadata(); - - var proxyElement:MASTProxyElement = null; - - try - { - proxyElement = new MASTProxyElement(mediaElement); - } - catch(error:IllegalOperationError) - { - fail(); - } - - var loadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.load(); - } - - public function testLoadAndPlay():void - { - doLoadAndPlay(); - doLoadAndPlay(false); - } - - public function testLoadFailure():void - { - var mediaElement:MediaElement = new VideoElement(); - var resource:URLResource = new URLResource(REMOTE_STREAM); - var metadata:Metadata = new Metadata(); - metadata.addValue(MASTPluginInfo.MAST_METADATA_KEY_URI, "http://foo.com/bogus/badfile.xml"); - resource.addMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata); - - mediaElement.resource = resource - - var proxyElement:MASTProxyElement = null; - - try - { - proxyElement = new MASTProxyElement(mediaElement); - } - catch(error:IllegalOperationError) - { - fail(); - } - - var loadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - loadTrait.load(); - - function onLoadStateChange(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - fail(); - } - else if (event.loadState == LoadState.LOAD_ERROR) - { - // expected - } - - } - - - } - - private function doLoadAndPlay(preroll:Boolean=true):void - { - var mediaElement:MediaElement = new VideoElement(); - mediaElement.resource = createResourceWithMetadata(preroll); - - var proxyElement:MASTProxyElement = null; - - try - { - proxyElement = new MASTProxyElement(mediaElement); - } - catch(error:IllegalOperationError) - { - fail(); - } - - var loadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - loadTrait.load(); - - var playTrait:PlayTrait = proxyElement.getTrait(MediaTraitType.PLAY) as PlayTrait; - playTrait.play(); - } - - private function createResourceWithMetadata(preroll:Boolean=true):URLResource - { - var resource:URLResource = new URLResource(REMOTE_STREAM); - - var metadata:Metadata = new Metadata(); - metadata.addValue(MASTPluginInfo.MAST_METADATA_KEY_URI, preroll ? MAST_URL_PREROLL : MAST_URL_POSTROLL); - resource.addMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata); - - return resource; - } - - private static const MAST_URL_PREROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemstart.xml"; - private static const MAST_URL_POSTROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemend.xml"; - - private static const REMOTE_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - } -} + + + public class TestMASTProxyElement extends TestCase + { + public function testConstructor():void + { + // Should throw an exception because there is no resource + try + { + new MASTProxyElement(new MediaElement()); + fail(); + } + catch(error:IllegalOperationError) + { + } + } + + public function testSetWrappedElement():void + { + var proxyElement:MASTProxyElement = new MASTProxyElement(); + + + // Should not throw an exception + try + { + proxyElement.proxiedElement = null; + } + catch(error:IllegalOperationError) + { + fail(); + } + } + + public function testWithNoMetadata():void + { + var resource:URLResource = new URLResource(REMOTE_STREAM); + var mediaElement:MediaElement = new MediaElement(); + mediaElement.resource = resource; + + try + { + new MASTProxyElement(mediaElement); + fail(); + } + catch(error:IllegalOperationError) + { + + } + } + + public function testWithMetadata():void + { + var mediaElement:VideoElement = new VideoElement(); + mediaElement.resource = createResourceWithMetadata(); + + try + { + new MASTProxyElement(mediaElement); + } + catch(error:IllegalOperationError) + { + fail(); + } + } + + public function testLoad():void + { + var mediaElement:MediaElement = new VideoElement(); + mediaElement.resource = createResourceWithMetadata(); + + var proxyElement:MASTProxyElement = null; + + try + { + proxyElement = new MASTProxyElement(mediaElement); + } + catch(error:IllegalOperationError) + { + fail(); + } + + var loadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.load(); + } + + public function testLoadAndPlay():void + { + doLoadAndPlay(); + doLoadAndPlay(false); + } + + public function testLoadFailure():void + { + var mediaElement:MediaElement = new VideoElement(); + var resource:URLResource = new URLResource(REMOTE_STREAM); + var metadata:Metadata = new Metadata(); + metadata.addValue(MASTPluginInfo.MAST_METADATA_KEY_URI, "http://foo.com/bogus/badfile.xml"); + resource.addMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata); + + mediaElement.resource = resource + + var proxyElement:MASTProxyElement = null; + + try + { + proxyElement = new MASTProxyElement(mediaElement); + } + catch(error:IllegalOperationError) + { + fail(); + } + + var loadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + loadTrait.load(); + + function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + fail(); + } + else if (event.loadState == LoadState.LOAD_ERROR) + { + // expected + } + + } + + + } + + private function doLoadAndPlay(preroll:Boolean=true):void + { + var mediaElement:MediaElement = new VideoElement(); + mediaElement.resource = createResourceWithMetadata(preroll); + + var proxyElement:MASTProxyElement = null; + + try + { + proxyElement = new MASTProxyElement(mediaElement); + } + catch(error:IllegalOperationError) + { + fail(); + } + + var loadTrait:LoadTrait = proxyElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + loadTrait.load(); + + var playTrait:PlayTrait = proxyElement.getTrait(MediaTraitType.PLAY) as PlayTrait; + playTrait.play(); + } + + private function createResourceWithMetadata(preroll:Boolean=true):URLResource + { + var resource:URLResource = new URLResource(REMOTE_STREAM); + + var metadata:Metadata = new Metadata(); + metadata.addValue(MASTPluginInfo.MAST_METADATA_KEY_URI, preroll ? MAST_URL_PREROLL : MAST_URL_POSTROLL); + resource.addMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata); + + return resource; + } + + private static const MAST_URL_PREROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemstart.xml"; + private static const MAST_URL_POSTROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemend.xml"; + + private static const REMOTE_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + } +} diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/parser/TestMASTParser.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/parser/TestMASTParser.as index 6081a92..2c14d99 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/parser/TestMASTParser.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/test/mast/parser/TestMASTParser.as @@ -1,59 +1,59 @@ -package org.osmf.test.mast.parser -{ - import __AS3__.vec.Vector; - - import flexunit.framework.TestCase; - - import org.osmf.mast.model.*; - import org.osmf.mast.parser.MASTParser; - import org.osmf.test.mast.MASTTestConstants; - - public class TestMASTParser extends TestCase - { - public function testParser():void - { - var parser:MASTParser = new MASTParser(); - var mastDocument:MASTDocument = parser.parse(MASTTestConstants.MAST_DOCUMENT_TEST_PARSER.toXMLString()); - - assertTrue(mastDocument.triggers.length > 0); - - for each (var trigger:MASTTrigger in mastDocument.triggers) - { - for each (var source:MASTSource in trigger.sources) - { - assertNotNull(source); - var altRef:String = source.altReference; - var sources:Vector. = source.sources; - for each( var target:MASTTarget in source.targets) - { - var id:String = target.id; - assertNotNull(id); - - var regionName:String = target.regionName; - assertNotNull(regionName); - - var targets:Vector. = target.targets; - } - } - } - } - - public function testParserWithBadFile():void - { - var parser:MASTParser = new MASTParser(); - - try - { - var mastDocument:MASTDocument = parser.parse(MASTTestConstants.MAST_DOCUMENT_TEST_PARSER_BAD_DATA.toXMLString()); - fail(); - } - catch (error:ArgumentError) - { - - } - - } - - - } -} +package org.osmf.test.mast.parser +{ + import __AS3__.vec.Vector; + + import flexunit.framework.TestCase; + + import org.osmf.mast.model.*; + import org.osmf.mast.parser.MASTParser; + import org.osmf.test.mast.MASTTestConstants; + + public class TestMASTParser extends TestCase + { + public function testParser():void + { + var parser:MASTParser = new MASTParser(); + var mastDocument:MASTDocument = parser.parse(MASTTestConstants.MAST_DOCUMENT_TEST_PARSER.toXMLString()); + + assertTrue(mastDocument.triggers.length > 0); + + for each (var trigger:MASTTrigger in mastDocument.triggers) + { + for each (var source:MASTSource in trigger.sources) + { + assertNotNull(source); + var altRef:String = source.altReference; + var sources:Vector. = source.sources; + for each( var target:MASTTarget in source.targets) + { + var id:String = target.id; + assertNotNull(id); + + var regionName:String = target.regionName; + assertNotNull(regionName); + + var targets:Vector. = target.targets; + } + } + } + } + + public function testParserWithBadFile():void + { + var parser:MASTParser = new MASTParser(); + + try + { + var mastDocument:MASTDocument = parser.parse(MASTTestConstants.MAST_DOCUMENT_TEST_PARSER_BAD_DATA.toXMLString()); + fail(); + } + catch (error:ArgumentError) + { + + } + + } + + + } +} diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as index 5435969..7f2c694 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as @@ -1,415 +1,415 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.traits -{ - import flash.errors.IllegalOperationError; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.TimerEvent; - import flash.utils.Timer; - - import flexunit.framework.TestCase; - - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.utils.SimpleResource; - - public class TestLoaderBase extends TestCase - { - override public function setUp():void - { - super.setUp(); - - _loader = createLoader(); - - eventDispatcher = new EventDispatcher(); - eventCount = 0; - mediaErrors = []; - doTwice = false; - } - - override public function tearDown():void - { - super.tearDown(); - - _loader = null; - eventDispatcher = null; - } - - protected function createInterfaceObject(... args):Object - { - return new LoaderBase(); - } - - //--------------------------------------------------------------------- - - public function testCanHandleResource():void - { - assertTrue(loader.canHandleResource(successfulResource) == true); - assertTrue(loader.canHandleResource(failedResource) == true); - assertTrue(loader.canHandleResource(unhandledResource) == false); - } - - public function testLoad():void - { - doTestLoad(); - } - - public function testLoadTwice():void - { - doTwice = true; - doTestLoad(); - } - - private function doTestLoad():void - { - eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestLoad(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - if (doTwice) - { - reload = true; - } - else - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Calling load a second time should throw an exception. - try - { - event.loader.load(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - public function testLoadWithFailure():void - { - doTestLoadWithFailure(); - } - - public function testLoadWithFailureThenReload():void - { - doTwice = true; - doTestLoadWithFailure(); - } - - private function doTestLoadWithFailure():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); - var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); - loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - loader.load(loadTrait); - } - - private function onTestLoadWithFailure(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - if (eventCount == 1 && doTwice) - { - reload = true; - } - else - { - markCompleteOnMediaError(1); - } - break; - case 2: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOAD_ERROR); - assertTrue(event.newState == LoadState.LOADING); - break; - case 3: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - markCompleteOnMediaError(2); - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Reloading should repeat the failure. - event.loader.load(event.loadTrait); - } - } - - private function markCompleteOnMediaError(numExpected:int):void - { - if (numExpected == mediaErrors.length) - { - // Just verify one of them. - verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - else - { - // Wait a bit, then check again. - var timer:Timer = new Timer(400); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(event:TimerEvent):void - { - timer.stop(); - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - markCompleteOnMediaError(numExpected); - } - } - } - - public function testLoadWithInvalidResource():void - { - try - { - loader.load(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - public function testUnload():void - { - doTestUnload(); - } - - public function testUnloadTwice():void - { - doTwice = true; - doTestUnload(); - } - - private function doTestUnload():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestUnload(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var doUnload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - // Now unload. - doUnload = true; - - break; - case 2: - assertTrue(event.oldState == LoadState.READY); - assertTrue(event.newState == LoadState.UNLOADING); - break; - case 3: - assertTrue(event.oldState == LoadState.UNLOADING); - assertTrue(event.newState == LoadState.UNINITIALIZED); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - break; - - default: - fail(); - } - - eventCount++; - - if (doUnload) - { - event.loader.unload(event.loadTrait); - - if (doTwice) - { - // Unloading a second time should throw an exception - // (but the first unload will complete). - try - { - event.loader.unload(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - } - } - - public function testUnloadWithInvalidResource():void - { - try - { - loader.unload(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - //--------------------------------------------------------------------- - - protected final function createLoader():LoaderBase - { - return createInterfaceObject() as LoaderBase; - } - - protected function setOverriddenLoader(value:LoaderBase):void - { - _loader = value; - } - - protected final function get loader():LoaderBase - { - return _loader; - } - - protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - return new LoadTrait(loader, resource); - } - - - protected function get successfulResource():MediaResourceBase - { - throw new Error("Subclass must override get successfulResource!"); - } - - protected function get failedResource():MediaResourceBase - { - throw new Error("Subclass must override get failedResource!"); - } - - protected function get unhandledResource():MediaResourceBase - { - throw new Error("Subclass must override get unhandledResource!"); - } - - protected function verifyMediaErrorOnLoadFailure(error:MediaError):void - { - // Subclasses can override to check the error's properties. - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - private function mustNotReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is NOT received. - fail(); - } - - private function onMediaError(event:MediaErrorEvent):void - { - mediaErrors.push(event.error); - } - - private static const TEST_TIME:int = 8000; - - private var eventDispatcher:EventDispatcher; - private var eventCount:int = 0; - private var mediaErrors:Array; - private var _loader:LoaderBase; - private var doTwice:Boolean; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.traits +{ + import flash.errors.IllegalOperationError; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.TimerEvent; + import flash.utils.Timer; + + import flexunit.framework.TestCase; + + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.MediaResourceBase; + import org.osmf.utils.SimpleResource; + + public class TestLoaderBase extends TestCase + { + override public function setUp():void + { + super.setUp(); + + _loader = createLoader(); + + eventDispatcher = new EventDispatcher(); + eventCount = 0; + mediaErrors = []; + doTwice = false; + } + + override public function tearDown():void + { + super.tearDown(); + + _loader = null; + eventDispatcher = null; + } + + protected function createInterfaceObject(... args):Object + { + return new LoaderBase(); + } + + //--------------------------------------------------------------------- + + public function testCanHandleResource():void + { + assertTrue(loader.canHandleResource(successfulResource) == true); + assertTrue(loader.canHandleResource(failedResource) == true); + assertTrue(loader.canHandleResource(unhandledResource) == false); + } + + public function testLoad():void + { + doTestLoad(); + } + + public function testLoadTwice():void + { + doTwice = true; + doTestLoad(); + } + + private function doTestLoad():void + { + eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); + loader.load(createLoadTrait(loader, successfulResource)); + } + + private function onTestLoad(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var reload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.READY); + + if (doTwice) + { + reload = true; + } + else + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + break; + default: + fail(); + } + + eventCount++; + + if (reload) + { + // Calling load a second time should throw an exception. + try + { + event.loader.load(event.loadTrait); + + fail(); + } + catch (error:IllegalOperationError) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + public function testLoadWithFailure():void + { + doTestLoadWithFailure(); + } + + public function testLoadWithFailureThenReload():void + { + doTwice = true; + doTestLoadWithFailure(); + } + + private function doTestLoadWithFailure():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); + var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); + loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + loader.load(loadTrait); + } + + private function onTestLoadWithFailure(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var reload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.LOAD_ERROR); + + if (eventCount == 1 && doTwice) + { + reload = true; + } + else + { + markCompleteOnMediaError(1); + } + break; + case 2: + assertTrue(doTwice); + + assertTrue(event.oldState == LoadState.LOAD_ERROR); + assertTrue(event.newState == LoadState.LOADING); + break; + case 3: + assertTrue(doTwice); + + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.LOAD_ERROR); + + markCompleteOnMediaError(2); + break; + default: + fail(); + } + + eventCount++; + + if (reload) + { + // Reloading should repeat the failure. + event.loader.load(event.loadTrait); + } + } + + private function markCompleteOnMediaError(numExpected:int):void + { + if (numExpected == mediaErrors.length) + { + // Just verify one of them. + verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + else + { + // Wait a bit, then check again. + var timer:Timer = new Timer(400); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + + function onTimer(event:TimerEvent):void + { + timer.stop(); + timer.removeEventListener(TimerEvent.TIMER, onTimer); + + markCompleteOnMediaError(numExpected); + } + } + } + + public function testLoadWithInvalidResource():void + { + try + { + loader.load(createLoadTrait(loader, unhandledResource)); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + + public function testUnload():void + { + doTestUnload(); + } + + public function testUnloadTwice():void + { + doTwice = true; + doTestUnload(); + } + + private function doTestUnload():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); + loader.load(createLoadTrait(loader, successfulResource)); + } + + private function onTestUnload(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var doUnload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.READY); + + // Now unload. + doUnload = true; + + break; + case 2: + assertTrue(event.oldState == LoadState.READY); + assertTrue(event.newState == LoadState.UNLOADING); + break; + case 3: + assertTrue(event.oldState == LoadState.UNLOADING); + assertTrue(event.newState == LoadState.UNINITIALIZED); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + break; + + default: + fail(); + } + + eventCount++; + + if (doUnload) + { + event.loader.unload(event.loadTrait); + + if (doTwice) + { + // Unloading a second time should throw an exception + // (but the first unload will complete). + try + { + event.loader.unload(event.loadTrait); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + } + } + + public function testUnloadWithInvalidResource():void + { + try + { + loader.unload(createLoadTrait(loader, unhandledResource)); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + + //--------------------------------------------------------------------- + + protected final function createLoader():LoaderBase + { + return createInterfaceObject() as LoaderBase; + } + + protected function setOverriddenLoader(value:LoaderBase):void + { + _loader = value; + } + + protected final function get loader():LoaderBase + { + return _loader; + } + + protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait + { + return new LoadTrait(loader, resource); + } + + + protected function get successfulResource():MediaResourceBase + { + throw new Error("Subclass must override get successfulResource!"); + } + + protected function get failedResource():MediaResourceBase + { + throw new Error("Subclass must override get failedResource!"); + } + + protected function get unhandledResource():MediaResourceBase + { + throw new Error("Subclass must override get unhandledResource!"); + } + + protected function verifyMediaErrorOnLoadFailure(error:MediaError):void + { + // Subclasses can override to check the error's properties. + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + private function mustNotReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is NOT received. + fail(); + } + + private function onMediaError(event:MediaErrorEvent):void + { + mediaErrors.push(event.error); + } + + private static const TEST_TIME:int = 8000; + + private var eventDispatcher:EventDispatcher; + private var eventCount:int = 0; + private var mediaErrors:Array; + private var _loader:LoaderBase; + private var doTwice:Boolean; + } } \ No newline at end of file diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/MockHTTPLoader.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/MockHTTPLoader.as index 62bfd4a..37d7fc2 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/MockHTTPLoader.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/MockHTTPLoader.as @@ -1,47 +1,47 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.net.URLLoader; - - public class MockHTTPLoader extends HTTPLoader - { - public function MockHTTPLoader() - { - super(); - - urlLoader = new MockURLLoader(); - } - - public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void - { - urlLoader.setExpectationForURL(url, expectSuccess, expectedData); - } - - override protected function createURLLoader():URLLoader - { - return urlLoader; - } - - private var urlLoader:MockURLLoader; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.net.URLLoader; + + public class MockHTTPLoader extends HTTPLoader + { + public function MockHTTPLoader() + { + super(); + + urlLoader = new MockURLLoader(); + } + + public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void + { + urlLoader.setExpectationForURL(url, expectSuccess, expectedData); + } + + override protected function createURLLoader():URLLoader + { + return urlLoader; + } + + private var urlLoader:MockURLLoader; + } } \ No newline at end of file diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/MockURLLoader.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/MockURLLoader.as index c2d49a1..490bb25 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/MockURLLoader.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/MockURLLoader.as @@ -1,70 +1,70 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.events.Event; - import flash.events.IOErrorEvent; - import flash.net.URLLoader; - import flash.net.URLRequest; - import flash.utils.Dictionary; - - public class MockURLLoader extends URLLoader - { - public function MockURLLoader() - { - super(); - - expectations = new Dictionary(); - } - - public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void - { - expectations[url] = {"success":expectSuccess, "data":expectedData}; - } - - override public function load(request:URLRequest):void - { - var expectation:Object = expectations[request.url]; - if (expectation != null) - { - data = expectation["data"]; - - // Prevent the network request from happening. - if (expectation["success"] == true) - { - dispatchEvent(new Event(Event.COMPLETE)); - } - else - { - data = null; - dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR)); - } - } - else - { - throw new Error("Expectation needs to be set on MockURLLoader!"); - } - } - - private var expectations:Dictionary; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + import flash.utils.Dictionary; + + public class MockURLLoader extends URLLoader + { + public function MockURLLoader() + { + super(); + + expectations = new Dictionary(); + } + + public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void + { + expectations[url] = {"success":expectSuccess, "data":expectedData}; + } + + override public function load(request:URLRequest):void + { + var expectation:Object = expectations[request.url]; + if (expectation != null) + { + data = expectation["data"]; + + // Prevent the network request from happening. + if (expectation["success"] == true) + { + dispatchEvent(new Event(Event.COMPLETE)); + } + else + { + data = null; + dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR)); + } + } + else + { + throw new Error("Expectation needs to be set on MockURLLoader!"); + } + } + + private var expectations:Dictionary; + } } \ No newline at end of file diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/NullResource.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/NullResource.as index b8b27cc..775b8e1 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/NullResource.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/NullResource.as @@ -1,29 +1,29 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.media.MediaResourceBase; - - public class NullResource extends MediaResourceBase - { - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.media.MediaResourceBase; + + public class NullResource extends MediaResourceBase + { + } } \ No newline at end of file diff --git a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as index 2e0ea2f..038567c 100644 --- a/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as +++ b/lib/osmf/samples/MASTPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as @@ -1,44 +1,44 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.media.MediaResourceBase; - - public class SimpleResource extends MediaResourceBase - { - public static const SUCCESSFUL:String = "successful"; - public static const FAILED:String = "failed"; - public static const UNHANDLED:String = "unhandled"; - - public function SimpleResource(type:String) - { - _type = type; - } - - public function get type():String - { - return _type; - } - - private var _type:String; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.media.MediaResourceBase; + + public class SimpleResource extends MediaResourceBase + { + public static const SUCCESSFUL:String = "successful"; + public static const FAILED:String = "failed"; + public static const UNHANDLED:String = "unhandled"; + + public function SimpleResource(type:String) + { + _type = type; + } + + public function get type():String + { + return _type; + } + + private var _type:String; + } } \ No newline at end of file diff --git a/lib/osmf/samples/MASTSample/.actionScriptProperties b/lib/osmf/samples/MASTSample/.actionScriptProperties index a4a3ea0..5d09ca3 100644 --- a/lib/osmf/samples/MASTSample/.actionScriptProperties +++ b/lib/osmf/samples/MASTSample/.actionScriptProperties @@ -1,35 +1,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MASTSample/MASTSample-build-config.xml b/lib/osmf/samples/MASTSample/MASTSample-build-config.xml index 6066649..8304e90 100644 --- a/lib/osmf/samples/MASTSample/MASTSample-build-config.xml +++ b/lib/osmf/samples/MASTSample/MASTSample-build-config.xml @@ -1,356 +1,356 @@ - - - - - false - - - - - - en_US - - - - - src - ../MASTPlugin/src - - - - false - - - - true - - - - - - - - - - - - - - true - - - - - - - ${flexlib}/libs/textLayout.swc - ${flexlib}/libs/spark.swc - ${flexlib}/libs/sparkskins.swc - ${flexlib}/libs/spark_dmv.swc - ${flexlib}/libs/mx/mx.swc - ${flexlib}/libs/authoringsupport.swc - ${flexlib}/libs/core.swc - ${flexlib}/libs/flash-integration.swc - - assets/EWSamplePlayerUI.swc - ../VASTLibrary/#output.bin#/VAST.swc - #osmf.swc.path# - - - - - - - - http://ns.adobe.com/mxml/2009 - ${flexlib}/mxml-2009-manifest.xml - - - library://ns.adobe.com/flex/spark - ${flexlib}/spark-manifest.xml - - - library://ns.adobe.com/flex/mx - ${flexlib}/mx-manifest.xml - - - - http://www.adobe.com/2006/mxml - ${flexlib}/mxml-manifest.xml - - - - - true - - - - - - - - - - - Bindable - Managed - ChangeEvent - NonCommittingChangeEvent - Transient - - - - - true - - - true - - - true - - - true - - - - - true - - - - - - false - - - - - - - false - - - - - - - - - - - true - - - 20 - - - 1000 - - - - - - - - - flash.fonts.JREFontManager - flash.fonts.BatikFontManager - flash.fonts.AFEFontManager - flash.fonts.CFFFontManager - - - - - - - - - ${flexlib}/themes/Spark/spark.css - - - false - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - false - - - false - - - false - - - true - - - - false - - - false - - - false - - - false - - - true - - - true - - - false - - - true - - - true - - - true - - - false - - - true - - - true - - - false - - - false - - - true - - - - false - - - - - - false - - - true - - - true - - - false - - - 0xFFFFFF - - 800 - 500 - - halo - - - - - - - - - - - - true - - - - - - true - - - - MASTPluginSample - MASTPluginSample - Silviu Vergoti - Silviu Vergoti - EN - - - + + + + + false + + + + + + en_US + + + + + src + ../MASTPlugin/src + + + + false + + + + true + + + + + + + + + + + + + + true + + + + + + + ${flexlib}/libs/textLayout.swc + ${flexlib}/libs/spark.swc + ${flexlib}/libs/sparkskins.swc + ${flexlib}/libs/spark_dmv.swc + ${flexlib}/libs/mx/mx.swc + ${flexlib}/libs/authoringsupport.swc + ${flexlib}/libs/core.swc + ${flexlib}/libs/flash-integration.swc + + assets/EWSamplePlayerUI.swc + ../VASTLibrary/#output.bin#/VAST.swc + #osmf.swc.path# + + + + + + + + http://ns.adobe.com/mxml/2009 + ${flexlib}/mxml-2009-manifest.xml + + + library://ns.adobe.com/flex/spark + ${flexlib}/spark-manifest.xml + + + library://ns.adobe.com/flex/mx + ${flexlib}/mx-manifest.xml + + + + http://www.adobe.com/2006/mxml + ${flexlib}/mxml-manifest.xml + + + + + true + + + + + + + + + + + Bindable + Managed + ChangeEvent + NonCommittingChangeEvent + Transient + + + + + true + + + true + + + true + + + true + + + + + true + + + + + + false + + + + + + + false + + + + + + + + + + + true + + + 20 + + + 1000 + + + + + + + + + flash.fonts.JREFontManager + flash.fonts.BatikFontManager + flash.fonts.AFEFontManager + flash.fonts.CFFFontManager + + + + + + + + + ${flexlib}/themes/Spark/spark.css + + + false + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + false + + + false + + + false + + + true + + + + false + + + false + + + false + + + false + + + true + + + true + + + false + + + true + + + true + + + true + + + false + + + true + + + true + + + false + + + false + + + true + + + + false + + + + + + false + + + true + + + true + + + false + + + 0xFFFFFF + + 800 + 500 + + halo + + + + + + + + + + + + true + + + + + + true + + + + MASTPluginSample + MASTPluginSample + Silviu Vergoti + Silviu Vergoti + EN + + + diff --git a/lib/osmf/samples/MASTSample/html-template/AC_OETags.js b/lib/osmf/samples/MASTSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/MASTSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/MASTSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/MASTSample/html-template/history/historyFrame.html b/lib/osmf/samples/MASTSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/MASTSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/MASTSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/MASTSample/html-template/index.template.html b/lib/osmf/samples/MASTSample/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/MASTSample/html-template/index.template.html +++ b/lib/osmf/samples/MASTSample/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MASTSample/publish_settings.xml b/lib/osmf/samples/MASTSample/publish_settings.xml index bc14b59..a9063b7 100644 --- a/lib/osmf/samples/MASTSample/publish_settings.xml +++ b/lib/osmf/samples/MASTSample/publish_settings.xml @@ -1,180 +1,180 @@ - - - - 1 - 1 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - MASTSample.swf - MASTSample.swt - MASTSample.exe - MASTSample.app - MASTSample.html - MASTSample.gif - MASTSample.jpg - MASTSample.png - MASTSample.mov - MASTSample.smil - - - 0 - 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; - 1 - 1 - MASTSample_content.html - MASTSample_alternate.html - 0 - - 100 - 100 - 0 - 2 - 0 - 0 - 3 - 1 - 1 - 4 - 0 - 0 - 1 - 0 - /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html - 1 - - - - - 0 - 0 - 0 - 80 - 0 - 0 - 7 - 0 - 7 - 0 - 10 - FlashPlayer10 - 3 - 1 - - ./src;../../../../libs/ChromeLibrary;../../../../framework/OSMF;../../../../plugins/MASTPlugin;../../../../libs/VAST - $(AppConfig)/ActionScript 3.0/libs - . - CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; - 0 - - 1 - 1 - 0 - 0 - 0 - 0 - MASTSample - 1 - 1 - 1 - AS3 - 1 - 1 - 0 - 15 - 1 - 0 - - - 550 - 400 - 0 - 4718592 - 0 - 80 - 1 - - - 1 - 0 - 1 - 0 - 0 - 100000 - 1 - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 1 - - - 550 - 400 - 0 - 1 - 1 - - 1 - 0 - 1 - 0 - 0 - - 128 - - - 255 - - - - 550 - 400 - 1 - 0 - 0 - 1 - 0 - 0 - 1 - - - - 24-bit with Alpha - 255 - - - - 550 - 400 - 1 - 0 - - - 00000000 - 0 - 0 - 0 - 0 - 1 - - + + + + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + MASTSample.swf + MASTSample.swt + MASTSample.exe + MASTSample.app + MASTSample.html + MASTSample.gif + MASTSample.jpg + MASTSample.png + MASTSample.mov + MASTSample.smil + + + 0 + 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + MASTSample_content.html + MASTSample_alternate.html + 0 + + 100 + 100 + 0 + 2 + 0 + 0 + 3 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 10 + FlashPlayer10 + 3 + 1 + + ./src;../../../../libs/ChromeLibrary;../../../../framework/OSMF;../../../../plugins/MASTPlugin;../../../../libs/VAST + $(AppConfig)/ActionScript 3.0/libs + . + CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; + 0 + + 1 + 1 + 0 + 0 + 0 + 0 + MASTSample + 1 + 1 + 1 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + + + 550 + 400 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 550 + 400 + 0 + 1 + 1 + + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 550 + 400 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 550 + 400 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + diff --git a/lib/osmf/samples/MASTSample/readme.txt b/lib/osmf/samples/MASTSample/readme.txt index 09acb58..ec60638 100644 --- a/lib/osmf/samples/MASTSample/readme.txt +++ b/lib/osmf/samples/MASTSample/readme.txt @@ -1,30 +1,30 @@ -Sample Application: MASTSampleNew - -A. Overview - -The MASTSampleNew sample application demonstrates the use of the MASTNew Actionscript plugin to retrieve a -MAST document, parse it into a MAST object model, and play a pre-roll ad before a video. - -B. Installation Instructions (Flex Builder) - -1. Unzip/copy the MASTSampleNew project into your Flex Builder workspace folder. -2. In Flex Builder, go to the File menu and select "Import". -3. Select "General", then "Existing Projects into Workspace", and click "Next". -4. Choose "Select root directory" and "Browse". -5. Browse to your Flex Builder workspace folder. -6. Select the checkbox next to "MASTSampleNew", and click "Finish". This will import the project. -7. Build the project. -8. Launch the application from the Run menu. - -NOTE: this sample project requires the OSMF project and the VAST project, you will need to -import those Flex projects as well in order to build the MASTSampleNew project. - -C. Usage Instructions - -The MASTSampleNew app is a pure AS3 application which loads a MAST document, parses it and displays a preroll video ad. -When you run the application, you'll see a 10-15 second preroll, followed by a 30 second video. The preroll -is generated from the VAST document located at the URL referenced in MASTSampleNew.as. - -Note that not all MAST elements are supported in the current release. The OSMF MAST specification (located -at http://opensource.adobe.com/wiki/display/osmf/MAST+Support) has additional details on the current scope of -MAST support within OSMF. +Sample Application: MASTSampleNew + +A. Overview + +The MASTSampleNew sample application demonstrates the use of the MASTNew Actionscript plugin to retrieve a +MAST document, parse it into a MAST object model, and play a pre-roll ad before a video. + +B. Installation Instructions (Flex Builder) + +1. Unzip/copy the MASTSampleNew project into your Flex Builder workspace folder. +2. In Flex Builder, go to the File menu and select "Import". +3. Select "General", then "Existing Projects into Workspace", and click "Next". +4. Choose "Select root directory" and "Browse". +5. Browse to your Flex Builder workspace folder. +6. Select the checkbox next to "MASTSampleNew", and click "Finish". This will import the project. +7. Build the project. +8. Launch the application from the Run menu. + +NOTE: this sample project requires the OSMF project and the VAST project, you will need to +import those Flex projects as well in order to build the MASTSampleNew project. + +C. Usage Instructions + +The MASTSampleNew app is a pure AS3 application which loads a MAST document, parses it and displays a preroll video ad. +When you run the application, you'll see a 10-15 second preroll, followed by a 30 second video. The preroll +is generated from the VAST document located at the URL referenced in MASTSampleNew.as. + +Note that not all MAST elements are supported in the current release. The OSMF MAST specification (located +at http://opensource.adobe.com/wiki/display/osmf/MAST+Support) has additional details on the current scope of +MAST support within OSMF. diff --git a/lib/osmf/samples/MASTSample/src/MASTSample.as b/lib/osmf/samples/MASTSample/src/MASTSample.as index 7a678dd..4d2b5e5 100644 --- a/lib/osmf/samples/MASTSample/src/MASTSample.as +++ b/lib/osmf/samples/MASTSample/src/MASTSample.as @@ -1,362 +1,362 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -* Contributor(s): Eyewonder, LLC -* -*****************************************************/ - -package -{ - import fl.controls.Slider; - import fl.events.SliderEvent; - - import flash.display.MovieClip; - import flash.display.Sprite; - import flash.display.StageAlign; - import flash.display.StageScaleMode; - import flash.events.Event; - import flash.events.MouseEvent; - import flash.utils.getDefinitionByName; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.SerialElement; - import org.osmf.elements.VideoElement; - import org.osmf.events.*; - import org.osmf.layout.ScaleMode; - import org.osmf.mast.MASTPluginInfo; - import org.osmf.mast.media.MASTProxyElement; - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.MediaPlayer; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.PluginInfoResource; - import org.osmf.media.URLResource; - import org.osmf.metadata.*; - import org.osmf.net.NetLoader; - import org.osmf.traits.AudioTrait; - import org.osmf.traits.MediaTraitType; - - [SWF(width="480",height="360", backgroundColor="0x333333")] - public class MASTSample extends Sprite - { - public function MASTSample() - { - stage.scaleMode = StageScaleMode.NO_SCALE; - stage.align = StageAlign.TOP_LEFT; - - mediaFactory = new DefaultMediaFactory(); - - // Create the Sprite class that holds our MediaPlayer. - // Set the Sprite's size to match that of the stage, and - // prevent the content from being scaled. - sprite = new MediaContainer(); - sprite.layoutMetadata.width = 480; - sprite.layoutMetadata.height = 360; - sprite.layoutMetadata.scaleMode = ScaleMode.NONE; - addChild(sprite); - - createPlayerButtons(); - - mediaPlayer.volume = vol = volSlider.value/10; - mediaPlayer.autoPlay = true; - - // Make sure we resize the Sprite when the stage dimensions - // change. - stage.addEventListener(Event.RESIZE, onStageResize); - stage.addEventListener(Event.ADDED, onStageResize); - - playBtn.visible = false; - pauseBtn.visible = true; - playBtn.buttonMode = true; - pauseBtn.buttonMode = true; - stopBtn.buttonMode = true; - - playBtn.addEventListener(MouseEvent.CLICK, onPlayClicked); - pauseBtn.addEventListener(MouseEvent.CLICK, onPauseClicked); - stopBtn.addEventListener(MouseEvent.CLICK, onStopClicked); - fullscreenBtn.addEventListener(MouseEvent.CLICK, onFSClicked); - volSlider.addEventListener(SliderEvent.CHANGE, onVolChanged); - muteBtn.addEventListener(MouseEvent.CLICK, onMutePressed); - unmuteBtn.addEventListener(MouseEvent.CLICK, onMutePressed); - - loadPlugin(MAST_PLUGIN_INFOCLASS); - } - - private function createPlayerButtons():void - { - playBtn = new PlayButton(); - playBtn.y = stage.stageHeight - (playBtn.height + 5); - playBtn.x = 10; - addChild(playBtn); - - stopBtn = new StopButton(); - stopBtn.y = playBtn.y; - stopBtn.x = playBtn.x + playBtn.width + 5; - addChild(stopBtn); - - pauseBtn = new PauseButton(); - pauseBtn.y = playBtn.y; - pauseBtn.x = 10; - pauseBtn.visible = false; - addChild(pauseBtn); - - volSlider = new Slider(); - volSlider.y = playBtn.y + 20; - volSlider.x = stopBtn.x + stopBtn.width + 10; - volSlider.value = 7.5; - vol = volSlider.value/10; - addChild(volSlider); - - fullscreenBtn = new FullScreenButton(); - fullscreenBtn.y = playBtn.y; - fullscreenBtn.x = volSlider.x + volSlider.width + 10; - fullscreenBtn.visible = false; - addChild(fullscreenBtn); - - muteBtn = new MuteButton(); - muteBtn.y = playBtn.y; - muteBtn.x = fullscreenBtn.x + fullscreenBtn.width + 5; - addChild(muteBtn); - - unmuteBtn = new UnmuteButton(); - unmuteBtn.y = muteBtn.y; - unmuteBtn.x = muteBtn.x; - unmuteBtn.visible = false; - addChild(unmuteBtn); - } - - private function loadPlugin(source:String):void - { - var pluginResource:MediaResourceBase; - if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file") - { - // This is a URL, create a URLResource - pluginResource = new URLResource(source); - } - else - { - // Assume this is a class - var pluginInfoRef:Class = getDefinitionByName(source) as Class; - pluginResource = new PluginInfoResource(new pluginInfoRef); - } - - loadPluginFromResource(pluginResource); - } - - private function loadPluginFromResource(pluginResource:MediaResourceBase):void - { - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); - mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); - mediaFactory.loadPlugin(pluginResource); - } - - private function onPluginLoaded(event:MediaFactoryEvent):void - { - trace(">>> Plugin successfully loaded."); - loadMainVideo(REMOTE_STREAM); - } - - private function onPluginLoadFailed(event:MediaFactoryEvent):void - { - trace(">>> Plugin failed to load."); - } - - private function loadMainVideo(url:String):void - { - var resource:URLResource = new URLResource(url); - - // Assign to the resource the metadata that indicates that it should have a MAST - // document applied (and include the URL of that MAST document). - var metadata:Metadata = new Metadata(); - metadata.addValue(MASTPluginInfo.MAST_METADATA_KEY_URI, MAST_VAST_2_LINEAR_FLV); - - resource.addMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata); - - videoElement = mediaFactory.createMediaElement(resource); - - - if (videoElement == null) - { - var netLoader:NetLoader = new NetLoader(); - // Add a default VideoElement - mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, createVideoElement)); - videoElement = mediaFactory.createMediaElement(resource) as VideoElement; - } - - sprite.addMediaElement(videoElement); - mediaPlayer.media = videoElement; - onStageResize(); - videoElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true); - - - } - - private function onTraitAdd(e:MediaElementEvent):void - { - trace("OSMF_Player.onTraitAdd - " + e.traitType); - if(e.traitType == MediaTraitType.PLAY) - { - - trace("OSMF_Player.onTraitAdd -- Content Play Trait Added " ); - playContent(); - } - } - - private function playContent():void - { - trace("Playing Content Video"); - mediaPlayer.play(); - } - - - private function createVideoElement():MediaElement - { - return new VideoElement(); - } - - private function onMediaError(event:MediaErrorEvent):void - { - var errMsg:String = "Media error : code="+event.error.errorID+" description="+event.error.message; - trace(errMsg); - - - var mediaElement:VideoElement = SerialElement(MASTProxyElement(videoElement).proxiedElement).getChildAt(1) as VideoElement; - sprite.addMediaElement(mediaElement); - mediaPlayer.media = mediaElement; - - videoElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - - private function onStageResize(event:Event = null):void - { - sprite.layoutMetadata.width = stage.stageWidth; - sprite.layoutMetadata.height = stage.stageHeight; - } - - private function onMutePressed(event:MouseEvent):void - { - if(muteBtn.visible){ - muteBtn.visible = false; - unmuteBtn.visible = true; - }else{ - muteBtn.visible = true; - unmuteBtn.visible = false; - } - - if(vol != 0) - { - if(mediaPlayer.muted){ - mediaPlayer.muted = false; - }else{ - mediaPlayer.muted = true; - } - } - /* - //This is the second use case for muting the VAST/VPAID creative - if(mediaPlayer.volume != 0) - mediaPlayer.volume = 0; - else - mediaPlayer.volume = vol; - */ - } - - private function onPauseClicked(e:MouseEvent):void - { - mediaPlayer.pause(); - pauseBtn.visible = false; - playBtn.visible = true; - } - - private function onStopClicked(e:MouseEvent):void - { - mediaPlayer.stop(); - } - - private function onPlayClicked(e:MouseEvent):void - { - trace("OSMF_Player.onPlayClicked " ); - mediaPlayer.play(); - playBtn.visible = false; - pauseBtn.visible = true; - } - - private function onFSClicked(e:MouseEvent):void - { - switch(stage.displayState) - { - case "normal": - stage.displayState = "fullScreen"; - break; - case "fullScreen": - default: - stage.displayState = "normal"; - break; - } - } - - private function onVolChanged(e:SliderEvent):void - { - trace("In onVolChanged()"); - vol = (e.currentTarget.value/10); - mediaPlayer.volume = vol; - trace("Slider Volume Changed " + vol ); - } - - private var mediaFactory:MediaFactory; - private var sprite:MediaContainer; - private var mediaPlayer:MediaPlayer = new MediaPlayer(); - private var vol:Number; - private var playInMediaPlayer:MediaElement; - private var mediaElementAudio:AudioTrait; - private var videoElement:MediaElement; - private var playBtn:MovieClip; - private var pauseBtn:MovieClip; - private var fullscreenBtn:MovieClip; - private var stopBtn:MovieClip; - private var volSlider:Slider; - private var muteBtn:MovieClip; - private var unmuteBtn:MovieClip; - - private static const MAST_PLUGIN_INFOCLASS:String = "org.osmf.mast.MASTPluginInfo"; - private static const loadTestRef:MASTPluginInfo = null; - - // MAST documents - // MAST documents - private static const AKAMAI_MAST_URL_POSTROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemend.xml"; - private static const AKAMAI_MAST_URL_PREROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemstart.xml"; - private static const MAST_VAST_1_BROKEN_FLV:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_1_linear_flv_broken.xml"; - private static const MAST_INVALID_VAST:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_invalid_vast.xml"; - private static const MAST_VAST_1_LINEAR_FLV:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_1_linear_flv.xml"; - private static const MAST_VAST_1_WRAPPER:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_1_wrapper.xml"; - private static const MAST_VAST_2_BROKEN_FLV:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_broken_flv.xml"; - private static const MAST_VAST_2_BROKEN_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_broken_vpaid.xml"; - private static const MAST_VAST_2_ENDLESS_WRAPPER:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_endless_wrapper.xml"; - private static const MAST_VAST_2_LINEAR_FLV:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_linear_flv_nonlinear_vpaid.xml"; - private static const MAST_VAST_2_LINEAR_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_linear_vpaid.xml"; - private static const MAST_VAST_2_VPAID_TRACKING_TEST:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_linear_vpaid_tracking_test.xml"; - private static const MAST_VAST_2_NONLINEAR_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_nonlinear_vpaid.xml?ewbust=12341234"; - private static const MAST_VAST_2_WRAPPER:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_wrapper.xml"; - - private static const REMOTE_STREAM:String - = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +* Contributor(s): Eyewonder, LLC +* +*****************************************************/ + +package +{ + import fl.controls.Slider; + import fl.events.SliderEvent; + + import flash.display.MovieClip; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.events.MouseEvent; + import flash.utils.getDefinitionByName; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.SerialElement; + import org.osmf.elements.VideoElement; + import org.osmf.events.*; + import org.osmf.layout.ScaleMode; + import org.osmf.mast.MASTPluginInfo; + import org.osmf.mast.media.MASTProxyElement; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.MediaPlayer; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.PluginInfoResource; + import org.osmf.media.URLResource; + import org.osmf.metadata.*; + import org.osmf.net.NetLoader; + import org.osmf.traits.AudioTrait; + import org.osmf.traits.MediaTraitType; + + [SWF(width="480",height="360", backgroundColor="0x333333")] + public class MASTSample extends Sprite + { + public function MASTSample() + { + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + + mediaFactory = new DefaultMediaFactory(); + + // Create the Sprite class that holds our MediaPlayer. + // Set the Sprite's size to match that of the stage, and + // prevent the content from being scaled. + sprite = new MediaContainer(); + sprite.layoutMetadata.width = 480; + sprite.layoutMetadata.height = 360; + sprite.layoutMetadata.scaleMode = ScaleMode.NONE; + addChild(sprite); + + createPlayerButtons(); + + mediaPlayer.volume = vol = volSlider.value/10; + mediaPlayer.autoPlay = true; + + // Make sure we resize the Sprite when the stage dimensions + // change. + stage.addEventListener(Event.RESIZE, onStageResize); + stage.addEventListener(Event.ADDED, onStageResize); + + playBtn.visible = false; + pauseBtn.visible = true; + playBtn.buttonMode = true; + pauseBtn.buttonMode = true; + stopBtn.buttonMode = true; + + playBtn.addEventListener(MouseEvent.CLICK, onPlayClicked); + pauseBtn.addEventListener(MouseEvent.CLICK, onPauseClicked); + stopBtn.addEventListener(MouseEvent.CLICK, onStopClicked); + fullscreenBtn.addEventListener(MouseEvent.CLICK, onFSClicked); + volSlider.addEventListener(SliderEvent.CHANGE, onVolChanged); + muteBtn.addEventListener(MouseEvent.CLICK, onMutePressed); + unmuteBtn.addEventListener(MouseEvent.CLICK, onMutePressed); + + loadPlugin(MAST_PLUGIN_INFOCLASS); + } + + private function createPlayerButtons():void + { + playBtn = new PlayButton(); + playBtn.y = stage.stageHeight - (playBtn.height + 5); + playBtn.x = 10; + addChild(playBtn); + + stopBtn = new StopButton(); + stopBtn.y = playBtn.y; + stopBtn.x = playBtn.x + playBtn.width + 5; + addChild(stopBtn); + + pauseBtn = new PauseButton(); + pauseBtn.y = playBtn.y; + pauseBtn.x = 10; + pauseBtn.visible = false; + addChild(pauseBtn); + + volSlider = new Slider(); + volSlider.y = playBtn.y + 20; + volSlider.x = stopBtn.x + stopBtn.width + 10; + volSlider.value = 7.5; + vol = volSlider.value/10; + addChild(volSlider); + + fullscreenBtn = new FullScreenButton(); + fullscreenBtn.y = playBtn.y; + fullscreenBtn.x = volSlider.x + volSlider.width + 10; + fullscreenBtn.visible = false; + addChild(fullscreenBtn); + + muteBtn = new MuteButton(); + muteBtn.y = playBtn.y; + muteBtn.x = fullscreenBtn.x + fullscreenBtn.width + 5; + addChild(muteBtn); + + unmuteBtn = new UnmuteButton(); + unmuteBtn.y = muteBtn.y; + unmuteBtn.x = muteBtn.x; + unmuteBtn.visible = false; + addChild(unmuteBtn); + } + + private function loadPlugin(source:String):void + { + var pluginResource:MediaResourceBase; + if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file") + { + // This is a URL, create a URLResource + pluginResource = new URLResource(source); + } + else + { + // Assume this is a class + var pluginInfoRef:Class = getDefinitionByName(source) as Class; + pluginResource = new PluginInfoResource(new pluginInfoRef); + } + + loadPluginFromResource(pluginResource); + } + + private function loadPluginFromResource(pluginResource:MediaResourceBase):void + { + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded); + mediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed); + mediaFactory.loadPlugin(pluginResource); + } + + private function onPluginLoaded(event:MediaFactoryEvent):void + { + trace(">>> Plugin successfully loaded."); + loadMainVideo(REMOTE_STREAM); + } + + private function onPluginLoadFailed(event:MediaFactoryEvent):void + { + trace(">>> Plugin failed to load."); + } + + private function loadMainVideo(url:String):void + { + var resource:URLResource = new URLResource(url); + + // Assign to the resource the metadata that indicates that it should have a MAST + // document applied (and include the URL of that MAST document). + var metadata:Metadata = new Metadata(); + metadata.addValue(MASTPluginInfo.MAST_METADATA_KEY_URI, MAST_VAST_2_LINEAR_FLV); + + resource.addMetadataValue(MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata); + + videoElement = mediaFactory.createMediaElement(resource); + + + if (videoElement == null) + { + var netLoader:NetLoader = new NetLoader(); + // Add a default VideoElement + mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, createVideoElement)); + videoElement = mediaFactory.createMediaElement(resource) as VideoElement; + } + + sprite.addMediaElement(videoElement); + mediaPlayer.media = videoElement; + onStageResize(); + videoElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true); + + + } + + private function onTraitAdd(e:MediaElementEvent):void + { + trace("OSMF_Player.onTraitAdd - " + e.traitType); + if(e.traitType == MediaTraitType.PLAY) + { + + trace("OSMF_Player.onTraitAdd -- Content Play Trait Added " ); + playContent(); + } + } + + private function playContent():void + { + trace("Playing Content Video"); + mediaPlayer.play(); + } + + + private function createVideoElement():MediaElement + { + return new VideoElement(); + } + + private function onMediaError(event:MediaErrorEvent):void + { + var errMsg:String = "Media error : code="+event.error.errorID+" description="+event.error.message; + trace(errMsg); + + + var mediaElement:VideoElement = SerialElement(MASTProxyElement(videoElement).proxiedElement).getChildAt(1) as VideoElement; + sprite.addMediaElement(mediaElement); + mediaPlayer.media = mediaElement; + + videoElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + + private function onStageResize(event:Event = null):void + { + sprite.layoutMetadata.width = stage.stageWidth; + sprite.layoutMetadata.height = stage.stageHeight; + } + + private function onMutePressed(event:MouseEvent):void + { + if(muteBtn.visible){ + muteBtn.visible = false; + unmuteBtn.visible = true; + }else{ + muteBtn.visible = true; + unmuteBtn.visible = false; + } + + if(vol != 0) + { + if(mediaPlayer.muted){ + mediaPlayer.muted = false; + }else{ + mediaPlayer.muted = true; + } + } + /* + //This is the second use case for muting the VAST/VPAID creative + if(mediaPlayer.volume != 0) + mediaPlayer.volume = 0; + else + mediaPlayer.volume = vol; + */ + } + + private function onPauseClicked(e:MouseEvent):void + { + mediaPlayer.pause(); + pauseBtn.visible = false; + playBtn.visible = true; + } + + private function onStopClicked(e:MouseEvent):void + { + mediaPlayer.stop(); + } + + private function onPlayClicked(e:MouseEvent):void + { + trace("OSMF_Player.onPlayClicked " ); + mediaPlayer.play(); + playBtn.visible = false; + pauseBtn.visible = true; + } + + private function onFSClicked(e:MouseEvent):void + { + switch(stage.displayState) + { + case "normal": + stage.displayState = "fullScreen"; + break; + case "fullScreen": + default: + stage.displayState = "normal"; + break; + } + } + + private function onVolChanged(e:SliderEvent):void + { + trace("In onVolChanged()"); + vol = (e.currentTarget.value/10); + mediaPlayer.volume = vol; + trace("Slider Volume Changed " + vol ); + } + + private var mediaFactory:MediaFactory; + private var sprite:MediaContainer; + private var mediaPlayer:MediaPlayer = new MediaPlayer(); + private var vol:Number; + private var playInMediaPlayer:MediaElement; + private var mediaElementAudio:AudioTrait; + private var videoElement:MediaElement; + private var playBtn:MovieClip; + private var pauseBtn:MovieClip; + private var fullscreenBtn:MovieClip; + private var stopBtn:MovieClip; + private var volSlider:Slider; + private var muteBtn:MovieClip; + private var unmuteBtn:MovieClip; + + private static const MAST_PLUGIN_INFOCLASS:String = "org.osmf.mast.MASTPluginInfo"; + private static const loadTestRef:MASTPluginInfo = null; + + // MAST documents + // MAST documents + private static const AKAMAI_MAST_URL_POSTROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemend.xml"; + private static const AKAMAI_MAST_URL_PREROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemstart.xml"; + private static const MAST_VAST_1_BROKEN_FLV:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_1_linear_flv_broken.xml"; + private static const MAST_INVALID_VAST:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_invalid_vast.xml"; + private static const MAST_VAST_1_LINEAR_FLV:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_1_linear_flv.xml"; + private static const MAST_VAST_1_WRAPPER:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_1_wrapper.xml"; + private static const MAST_VAST_2_BROKEN_FLV:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_broken_flv.xml"; + private static const MAST_VAST_2_BROKEN_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_broken_vpaid.xml"; + private static const MAST_VAST_2_ENDLESS_WRAPPER:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_endless_wrapper.xml"; + private static const MAST_VAST_2_LINEAR_FLV:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_linear_flv_nonlinear_vpaid.xml"; + private static const MAST_VAST_2_LINEAR_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_linear_vpaid.xml"; + private static const MAST_VAST_2_VPAID_TRACKING_TEST:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_linear_vpaid_tracking_test.xml"; + private static const MAST_VAST_2_NONLINEAR_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_nonlinear_vpaid.xml?ewbust=12341234"; + private static const MAST_VAST_2_WRAPPER:String = "http://cdn1.eyewonder.com/200125/instream/osmf/mast_vast_2_wrapper.xml"; + + private static const REMOTE_STREAM:String + = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + } +} diff --git a/lib/osmf/samples/MediaContainerSample/.actionScriptProperties b/lib/osmf/samples/MediaContainerSample/.actionScriptProperties index ba23b8d..6d7d451 100644 --- a/lib/osmf/samples/MediaContainerSample/.actionScriptProperties +++ b/lib/osmf/samples/MediaContainerSample/.actionScriptProperties @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MediaContainerSample/html-template/AC_OETags.js b/lib/osmf/samples/MediaContainerSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/MediaContainerSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/MediaContainerSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/MediaContainerSample/html-template/history/historyFrame.html b/lib/osmf/samples/MediaContainerSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/MediaContainerSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/MediaContainerSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/MediaContainerSample/html-template/index.template.html b/lib/osmf/samples/MediaContainerSample/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/MediaContainerSample/html-template/index.template.html +++ b/lib/osmf/samples/MediaContainerSample/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MediaContainerSample/src/MediaContainerSample.as b/lib/osmf/samples/MediaContainerSample/src/MediaContainerSample.as index bb3006f..5f644d0 100644 --- a/lib/osmf/samples/MediaContainerSample/src/MediaContainerSample.as +++ b/lib/osmf/samples/MediaContainerSample/src/MediaContainerSample.as @@ -1,218 +1,218 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - import flash.display.StageAlign; - import flash.display.StageScaleMode; - import flash.events.MouseEvent; - import flash.net.URLRequest; - import flash.net.navigateToURL; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.DurationElement; - import org.osmf.elements.ImageElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.SerialElement; - import org.osmf.elements.VideoElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - [SWF(backgroundColor='#333333', frameRate='30')] - public class MediaContainerSample extends Sprite - { - public function MediaContainerSample() - { - // Setup the Flash stage: - - stage.scaleMode = StageScaleMode.NO_SCALE; - stage.align = StageAlign.TOP_LEFT; - - runSample(); - } - - private function runSample():void - { - // Construct a small tree of media elements: - - var rootElement:ParallelElement = new ParallelElement(); - - var mainContent:VideoElement = constructVideo(REMOTE_PROGRESSIVE); - rootElement.addChild(mainContent); - var banners:SerialElement = new SerialElement(); - banners.addChild(constructBanner(BANNER_1)); - banners.addChild(constructBanner(BANNER_2)); - banners.addChild(constructBanner(BANNER_3)); - rootElement.addChild(banners); - var skyScraper:MediaElement = constructImage(SKY_SCRAPER_1); - rootElement.addChild(skyScraper); - - // Next, decorate the content tree with attributes: - - var bannersLayout:LayoutMetadata = new LayoutMetadata(); - banners.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, bannersLayout); - bannersLayout.percentWidth = 100; - bannersLayout.percentHeight = 100; - bannersLayout.scaleMode = ScaleMode.NONE; - bannersLayout.verticalAlign = VerticalAlign.BOTTOM; - bannersLayout.horizontalAlign = HorizontalAlign.CENTER; - - var mainLayout:LayoutMetadata = new LayoutMetadata(); - mainContent.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, mainLayout); - mainLayout.percentWidth = 100; - mainLayout.percentHeight = 100; - mainLayout.scaleMode = ScaleMode.LETTERBOX; - mainLayout.verticalAlign = VerticalAlign.TOP; - mainLayout.horizontalAlign = HorizontalAlign.CENTER; - - // Consruct 3 regions: - - var bannerContainer:MediaContainer = new MediaContainer(); - bannerContainer.width = 600; - bannerContainer.height = 70; - bannerContainer.backgroundColor = 0xFF0000; - bannerContainer.backgroundAlpha = .2; - addChild(bannerContainer); - - var mainContainer:MediaContainer = new MediaContainer(); - mainContainer.width = 600; - mainContainer.height = 400; - mainContainer.backgroundColor = 0xFFFFFF; - mainContainer.backgroundAlpha = .2; - mainContainer.y = 80; - addChild(mainContainer); - - var skyScraperContainer:MediaContainer = new MediaContainer(); - skyScraperContainer.width = 120; - skyScraperContainer.height = 600; - skyScraperContainer.backgroundColor = 0xFF00; - skyScraperContainer.backgroundAlpha = .2; - skyScraperContainer.x = 610; - skyScraperContainer.y = 10; - addChild(skyScraperContainer); - - // Bind media elements to their target regions: - - bannerContainer.addMediaElement(banners); - mainContainer.addMediaElement(mainContent); - skyScraperContainer.addMediaElement(skyScraper); - - // To operate playback of the content tree, construct a - // media player. Assignment of the root element to its source will - // automatically start its loading and playback: - - var player:MediaPlayer = new MediaPlayer(); - player.media = rootElement; - - // Next, to make things more interesting by adding some interactivity: - // Let's create another region, at the bottom of the main content. Now, - // if we click the top banner, let's have it moved to this region, and - // vice-versa: - - var bottomBannerContainer:MediaContainer = new MediaContainer(); - bottomBannerContainer.width = 600; - bottomBannerContainer.height = 70; - bottomBannerContainer.backgroundColor = 0xFF; - bottomBannerContainer.backgroundAlpha = .2; - bottomBannerContainer.y = 490; - addChild(bottomBannerContainer); - - bannerContainer.addEventListener - ( MouseEvent.CLICK - , function (event:MouseEvent):void - { - bottomBannerContainer.addMediaElement(banners); - } - ); - - bottomBannerContainer.addEventListener - ( MouseEvent.CLICK - , function (event:MouseEvent):void - { - bannerContainer.addMediaElement(banners); - } - ); - - // Let's link to the IAB site on the sky-scraper being clicked: - skyScraperContainer.addEventListener - ( MouseEvent.CLICK - , function (event:MouseEvent):void - { - navigateToURL(new URLRequest(IAB_URL)); - } - ); - } - - // Utilities - // - - private function constructBanner(url:String):MediaElement - { - return new DurationElement - ( BANNER_INTERVAL - , constructImage(url) - ); - } - - private function constructImage(url:String):MediaElement - { - return new ImageElement - ( new URLResource(url) - ) - - } - - private function constructVideo(url:String):VideoElement - { - return new VideoElement - ( new URLResource(url) - ); - } - - private static const BANNER_INTERVAL:int = 5; - - private static const REMOTE_PROGRESSIVE:String - = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; - - // IAB standard banners from: - private static const IAB_URL:String - = "http://www.iab.net/iab_products_and_industry_services/1421/1443/1452"; - - private static const BANNER_1:String - = "http://www.iab.net/media/image/468x60.gif"; - - private static const BANNER_2:String - = "http://www.iab.net/media/image/234x60.gif"; - - private static const BANNER_3:String - = "http://www.iab.net/media/image/120x60.gif"; - - private static const SKY_SCRAPER_1:String - = "http://www.iab.net/media/image/120x600.gif" - - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.MouseEvent; + import flash.net.URLRequest; + import flash.net.navigateToURL; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.DurationElement; + import org.osmf.elements.ImageElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.SerialElement; + import org.osmf.elements.VideoElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + [SWF(backgroundColor='#333333', frameRate='30')] + public class MediaContainerSample extends Sprite + { + public function MediaContainerSample() + { + // Setup the Flash stage: + + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + + runSample(); + } + + private function runSample():void + { + // Construct a small tree of media elements: + + var rootElement:ParallelElement = new ParallelElement(); + + var mainContent:VideoElement = constructVideo(REMOTE_PROGRESSIVE); + rootElement.addChild(mainContent); + var banners:SerialElement = new SerialElement(); + banners.addChild(constructBanner(BANNER_1)); + banners.addChild(constructBanner(BANNER_2)); + banners.addChild(constructBanner(BANNER_3)); + rootElement.addChild(banners); + var skyScraper:MediaElement = constructImage(SKY_SCRAPER_1); + rootElement.addChild(skyScraper); + + // Next, decorate the content tree with attributes: + + var bannersLayout:LayoutMetadata = new LayoutMetadata(); + banners.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, bannersLayout); + bannersLayout.percentWidth = 100; + bannersLayout.percentHeight = 100; + bannersLayout.scaleMode = ScaleMode.NONE; + bannersLayout.verticalAlign = VerticalAlign.BOTTOM; + bannersLayout.horizontalAlign = HorizontalAlign.CENTER; + + var mainLayout:LayoutMetadata = new LayoutMetadata(); + mainContent.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, mainLayout); + mainLayout.percentWidth = 100; + mainLayout.percentHeight = 100; + mainLayout.scaleMode = ScaleMode.LETTERBOX; + mainLayout.verticalAlign = VerticalAlign.TOP; + mainLayout.horizontalAlign = HorizontalAlign.CENTER; + + // Consruct 3 regions: + + var bannerContainer:MediaContainer = new MediaContainer(); + bannerContainer.width = 600; + bannerContainer.height = 70; + bannerContainer.backgroundColor = 0xFF0000; + bannerContainer.backgroundAlpha = .2; + addChild(bannerContainer); + + var mainContainer:MediaContainer = new MediaContainer(); + mainContainer.width = 600; + mainContainer.height = 400; + mainContainer.backgroundColor = 0xFFFFFF; + mainContainer.backgroundAlpha = .2; + mainContainer.y = 80; + addChild(mainContainer); + + var skyScraperContainer:MediaContainer = new MediaContainer(); + skyScraperContainer.width = 120; + skyScraperContainer.height = 600; + skyScraperContainer.backgroundColor = 0xFF00; + skyScraperContainer.backgroundAlpha = .2; + skyScraperContainer.x = 610; + skyScraperContainer.y = 10; + addChild(skyScraperContainer); + + // Bind media elements to their target regions: + + bannerContainer.addMediaElement(banners); + mainContainer.addMediaElement(mainContent); + skyScraperContainer.addMediaElement(skyScraper); + + // To operate playback of the content tree, construct a + // media player. Assignment of the root element to its source will + // automatically start its loading and playback: + + var player:MediaPlayer = new MediaPlayer(); + player.media = rootElement; + + // Next, to make things more interesting by adding some interactivity: + // Let's create another region, at the bottom of the main content. Now, + // if we click the top banner, let's have it moved to this region, and + // vice-versa: + + var bottomBannerContainer:MediaContainer = new MediaContainer(); + bottomBannerContainer.width = 600; + bottomBannerContainer.height = 70; + bottomBannerContainer.backgroundColor = 0xFF; + bottomBannerContainer.backgroundAlpha = .2; + bottomBannerContainer.y = 490; + addChild(bottomBannerContainer); + + bannerContainer.addEventListener + ( MouseEvent.CLICK + , function (event:MouseEvent):void + { + bottomBannerContainer.addMediaElement(banners); + } + ); + + bottomBannerContainer.addEventListener + ( MouseEvent.CLICK + , function (event:MouseEvent):void + { + bannerContainer.addMediaElement(banners); + } + ); + + // Let's link to the IAB site on the sky-scraper being clicked: + skyScraperContainer.addEventListener + ( MouseEvent.CLICK + , function (event:MouseEvent):void + { + navigateToURL(new URLRequest(IAB_URL)); + } + ); + } + + // Utilities + // + + private function constructBanner(url:String):MediaElement + { + return new DurationElement + ( BANNER_INTERVAL + , constructImage(url) + ); + } + + private function constructImage(url:String):MediaElement + { + return new ImageElement + ( new URLResource(url) + ) + + } + + private function constructVideo(url:String):VideoElement + { + return new VideoElement + ( new URLResource(url) + ); + } + + private static const BANNER_INTERVAL:int = 5; + + private static const REMOTE_PROGRESSIVE:String + = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; + + // IAB standard banners from: + private static const IAB_URL:String + = "http://www.iab.net/iab_products_and_industry_services/1421/1443/1452"; + + private static const BANNER_1:String + = "http://www.iab.net/media/image/468x60.gif"; + + private static const BANNER_2:String + = "http://www.iab.net/media/image/234x60.gif"; + + private static const BANNER_3:String + = "http://www.iab.net/media/image/120x60.gif"; + + private static const SKY_SCRAPER_1:String + = "http://www.iab.net/media/image/120x600.gif" + + } +} diff --git a/lib/osmf/samples/MediaContainerSample/src/publish_settings.xml b/lib/osmf/samples/MediaContainerSample/src/publish_settings.xml index 0bc2d50..5c16188 100644 --- a/lib/osmf/samples/MediaContainerSample/src/publish_settings.xml +++ b/lib/osmf/samples/MediaContainerSample/src/publish_settings.xml @@ -1,180 +1,180 @@ - - - - 1 - 1 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - MediaContainerSample.swf - MediaContainerSample.swt - MediaContainerSample.exe - MediaContainerSample.app - MediaContainerSample.html - MediaContainerSample.gif - MediaContainerSample.jpg - MediaContainerSample.png - MediaContainerSample.mov - MediaContainerSample.smil - - - 0 - 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; - 1 - 1 - MediaContainerSample_content.html - MediaContainerSample_alternate.html - 0 - - 100 - 100 - 0 - 2 - 0 - 0 - 3 - 1 - 1 - 4 - 0 - 0 - 1 - 0 - /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html - 1 - - - - - 0 - 0 - 0 - 80 - 0 - 0 - 7 - 0 - 7 - 0 - 10 - FlashPlayer10 - 3 - 1 - - .;../../../../libs/ChromeLibrary;../../../../framework/OSMF - $(AppConfig)/ActionScript 3.0/libs - . - CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; - 0 - - 1 - 1 - 0 - 0 - 0 - 0 - MediaContainerSample - 1 - 1 - 1 - AS3 - 1 - 1 - 0 - 15 - 1 - 0 - - - 550 - 400 - 0 - 4718592 - 0 - 80 - 1 - - - 1 - 0 - 1 - 0 - 0 - 100000 - 1 - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 1 - - - 550 - 400 - 0 - 1 - 1 - - 1 - 0 - 1 - 0 - 0 - - 128 - - - 255 - - - - 550 - 400 - 1 - 0 - 0 - 1 - 0 - 0 - 1 - - - - 24-bit with Alpha - 255 - - - - 550 - 400 - 1 - 0 - - - 00000000 - 0 - 0 - 0 - 0 - 1 - - + + + + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + MediaContainerSample.swf + MediaContainerSample.swt + MediaContainerSample.exe + MediaContainerSample.app + MediaContainerSample.html + MediaContainerSample.gif + MediaContainerSample.jpg + MediaContainerSample.png + MediaContainerSample.mov + MediaContainerSample.smil + + + 0 + 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + MediaContainerSample_content.html + MediaContainerSample_alternate.html + 0 + + 100 + 100 + 0 + 2 + 0 + 0 + 3 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 10 + FlashPlayer10 + 3 + 1 + + .;../../../../libs/ChromeLibrary;../../../../framework/OSMF + $(AppConfig)/ActionScript 3.0/libs + . + CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; + 0 + + 1 + 1 + 0 + 0 + 0 + 0 + MediaContainerSample + 1 + 1 + 1 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + + + 550 + 400 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 550 + 400 + 0 + 1 + 1 + + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 550 + 400 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 550 + 400 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + diff --git a/lib/osmf/samples/MediaContainerUIComponentLibrary/.actionScriptProperties b/lib/osmf/samples/MediaContainerUIComponentLibrary/.actionScriptProperties index 0b1fc1c..b473a4c 100644 --- a/lib/osmf/samples/MediaContainerUIComponentLibrary/.actionScriptProperties +++ b/lib/osmf/samples/MediaContainerUIComponentLibrary/.actionScriptProperties @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MediaContainerUIComponentLibrary/.flexLibProperties b/lib/osmf/samples/MediaContainerUIComponentLibrary/.flexLibProperties index 319e0e0..6b2850a 100644 --- a/lib/osmf/samples/MediaContainerUIComponentLibrary/.flexLibProperties +++ b/lib/osmf/samples/MediaContainerUIComponentLibrary/.flexLibProperties @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/lib/osmf/samples/MediaContainerUIComponentLibrary/MediaContainerUIComponent-build-config.xml b/lib/osmf/samples/MediaContainerUIComponentLibrary/MediaContainerUIComponent-build-config.xml index 0c4380e..70ec553 100644 --- a/lib/osmf/samples/MediaContainerUIComponentLibrary/MediaContainerUIComponent-build-config.xml +++ b/lib/osmf/samples/MediaContainerUIComponentLibrary/MediaContainerUIComponent-build-config.xml @@ -1,332 +1,332 @@ - - - - - false - - - - en_US - - - - - src - - - - false - - - - true - - - - - - - - - - - - - - false - - - - - - - ${flexlib}/libs/textLayout.swc - ${flexlib}/libs/advancedgrids.swc - ${flexlib}/libs/mx/mx.swc - ${flexlib}/libs/rpc.swc - ${flexlib}/libs/authoringsupport.swc - ${flexlib}/libs/charts.swc - ${flexlib}/libs/core.swc - ${flexlib}/libs/flash-integration.swc - ${flexlib}/libs/spark_dmv.swc - ${flexlib}/locale/{locale} - ${flexlib}/libs/framework.swc - ${flexlib}/libs/air/servicemonitor.swc - ${flexlib}/libs/air/airframework.swc - - #osmf.swc.path# - - - - true - - - - - - - - - - - Bindable - Managed - ChangeEvent - NonCommittingChangeEvent - Transient - - - - - true - - - true - - - true - - - true - - - - - true - - - - - - false - - - - - - - false - - - - - - - - - - - true - - - 20 - - - 1000 - - - - - - - - - flash.fonts.JREFontManager - flash.fonts.AFEFontManager - flash.fonts.BatikFontManager - - - - - - - - ${flexlib}/themes/Halo/halo.swc - - - - false - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - false - - - false - - - false - - - true - - - - false - - - false - - - false - - - false - - - true - - - true - - - false - - - true - - - true - - - true - - - false - - - true - - - true - - - false - - - false - - - true - - - - false - - - - - - false - - - true - - - true - - - false - - - - - - - - - - - - - libs/framework.swc - framework_3.0.177608.swz - - framework_3.0.177608.swf - - - - true - - - - - - - true - - - - MediaContainerUIComponent - MediaContainerUIComponent - Silviu Vergoti - Brian Riggs - EN - - - + + + + + false + + + + en_US + + + + + src + + + + false + + + + true + + + + + + + + + + + + + + false + + + + + + + ${flexlib}/libs/textLayout.swc + ${flexlib}/libs/advancedgrids.swc + ${flexlib}/libs/mx/mx.swc + ${flexlib}/libs/rpc.swc + ${flexlib}/libs/authoringsupport.swc + ${flexlib}/libs/charts.swc + ${flexlib}/libs/core.swc + ${flexlib}/libs/flash-integration.swc + ${flexlib}/libs/spark_dmv.swc + ${flexlib}/locale/{locale} + ${flexlib}/libs/framework.swc + ${flexlib}/libs/air/servicemonitor.swc + ${flexlib}/libs/air/airframework.swc + + #osmf.swc.path# + + + + true + + + + + + + + + + + Bindable + Managed + ChangeEvent + NonCommittingChangeEvent + Transient + + + + + true + + + true + + + true + + + true + + + + + true + + + + + + false + + + + + + + false + + + + + + + + + + + true + + + 20 + + + 1000 + + + + + + + + + flash.fonts.JREFontManager + flash.fonts.AFEFontManager + flash.fonts.BatikFontManager + + + + + + + + ${flexlib}/themes/Halo/halo.swc + + + + false + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + false + + + false + + + false + + + true + + + + false + + + false + + + false + + + false + + + true + + + true + + + false + + + true + + + true + + + true + + + false + + + true + + + true + + + false + + + false + + + true + + + + false + + + + + + false + + + true + + + true + + + false + + + + + + + + + + + + + libs/framework.swc + framework_3.0.177608.swz + + framework_3.0.177608.swf + + + + true + + + + + + + true + + + + MediaContainerUIComponent + MediaContainerUIComponent + Silviu Vergoti + Brian Riggs + EN + + + diff --git a/lib/osmf/samples/MediaContainerUIComponentLibrary/readme.txt b/lib/osmf/samples/MediaContainerUIComponentLibrary/readme.txt index c87998f..021b393 100644 --- a/lib/osmf/samples/MediaContainerUIComponentLibrary/readme.txt +++ b/lib/osmf/samples/MediaContainerUIComponentLibrary/readme.txt @@ -1,22 +1,22 @@ -Sample Library: MediaContainerUIComponent - -A. Overview - -This sample library contains a Flex UIComponent wrapper for MediaContainer. It is used in a number of sample applications. - -B. Installation Instructions (Flex Builder) - -1. Unzip/copy the MediaContainerUIComponent project into your Flex Builder workspace folder. -2. In Flex Builder, go to the File menu and select "Import". -3. Select "General", then "Existing Projects into Workspace", and click "Next". -4. Choose "Select root directory" and "Browse". -5. Browse to your Flex Builder workspace folder. -6. Select the checkbox next to "MediaContainerUIComponent", and click "Finish". This will import the project. -7. Build the project. -8. Add the project to your own Flex application by selecting the Project menu, "Properties", - "Flex Build Path", "Library Path", "Add Project", and select "MediaContainerUIComponent". - -C. Usage Instructions - -Use MediaContainerUIComponent (which extends UIComponent) in your Flex application. You can assign a -the MediaContainer, add MediaElements, set layout metadata, etc. +Sample Library: MediaContainerUIComponent + +A. Overview + +This sample library contains a Flex UIComponent wrapper for MediaContainer. It is used in a number of sample applications. + +B. Installation Instructions (Flex Builder) + +1. Unzip/copy the MediaContainerUIComponent project into your Flex Builder workspace folder. +2. In Flex Builder, go to the File menu and select "Import". +3. Select "General", then "Existing Projects into Workspace", and click "Next". +4. Choose "Select root directory" and "Browse". +5. Browse to your Flex Builder workspace folder. +6. Select the checkbox next to "MediaContainerUIComponent", and click "Finish". This will import the project. +7. Build the project. +8. Add the project to your own Flex application by selecting the Project menu, "Properties", + "Flex Build Path", "Library Path", "Add Project", and select "MediaContainerUIComponent". + +C. Usage Instructions + +Use MediaContainerUIComponent (which extends UIComponent) in your Flex application. You can assign a +the MediaContainer, add MediaElements, set layout metadata, etc. diff --git a/lib/osmf/samples/MediaContainerUIComponentLibrary/src/org/osmf/samples/MediaContainerUIComponent.as b/lib/osmf/samples/MediaContainerUIComponentLibrary/src/org/osmf/samples/MediaContainerUIComponent.as index 6a89239..ddd059d 100644 --- a/lib/osmf/samples/MediaContainerUIComponentLibrary/src/org/osmf/samples/MediaContainerUIComponent.as +++ b/lib/osmf/samples/MediaContainerUIComponentLibrary/src/org/osmf/samples/MediaContainerUIComponent.as @@ -1,121 +1,121 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.samples -{ - import mx.core.UIComponent; - - import org.osmf.containers.MediaContainer; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.layout.LayoutRendererBase; - - /** - * UIComponent that exposes an OSMF MediaContainer. Useful for integrating - * OSMF into a Flex application. - **/ - public class MediaContainerUIComponent extends UIComponent - { - // Public Interface - // - - public function set container(value:MediaContainer):void - { - if (value != _container) - { - if (_container && contains(_container)) - { - _container.removeEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange); - removeChild(_container); - } - - _container = value; - - if (_container) - { - _container.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange); - _container.width = unscaledWidth; - _container.height = unscaledHeight; - addChild(_container); - } - - invalidateSize(); - invalidateDisplayList(); - } - } - - public function get container():MediaContainer - { - return _container; - } - - // Overrides - // - - override protected function measure():void - { - super.measure(); - - if (_container) - { - var renderer:LayoutRendererBase = _container.layoutRenderer; - if (renderer) - { - measuredWidth = renderer.measuredWidth; - measuredHeight = renderer.measuredHeight; - } - } - if (measuredWidth == 0 || isNaN(measuredWidth) || - measuredHeight == 0 || isNaN(measuredHeight) ) - { - measuredWidth = DEFAULT_WIDTH; - measuredHeight = DEFAULT_HEIGHT; - } - - } - - override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void - { - if (_container) - { - _container.width = unscaledWidth; - _container.height = unscaledHeight; - } - - super.updateDisplayList(unscaledWidth, unscaledHeight); - } - - // Internals - // - - private function onMediaSizeChange(event:DisplayObjectEvent):void - { - invalidateSize(); - invalidateDisplayList(); - } - - private static const DEFAULT_WIDTH:Number = 320; - private static const DEFAULT_HEIGHT:Number = 240; - - - private var _container:MediaContainer; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.samples +{ + import mx.core.UIComponent; + + import org.osmf.containers.MediaContainer; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.layout.LayoutRendererBase; + + /** + * UIComponent that exposes an OSMF MediaContainer. Useful for integrating + * OSMF into a Flex application. + **/ + public class MediaContainerUIComponent extends UIComponent + { + // Public Interface + // + + public function set container(value:MediaContainer):void + { + if (value != _container) + { + if (_container && contains(_container)) + { + _container.removeEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange); + removeChild(_container); + } + + _container = value; + + if (_container) + { + _container.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange); + _container.width = unscaledWidth; + _container.height = unscaledHeight; + addChild(_container); + } + + invalidateSize(); + invalidateDisplayList(); + } + } + + public function get container():MediaContainer + { + return _container; + } + + // Overrides + // + + override protected function measure():void + { + super.measure(); + + if (_container) + { + var renderer:LayoutRendererBase = _container.layoutRenderer; + if (renderer) + { + measuredWidth = renderer.measuredWidth; + measuredHeight = renderer.measuredHeight; + } + } + if (measuredWidth == 0 || isNaN(measuredWidth) || + measuredHeight == 0 || isNaN(measuredHeight) ) + { + measuredWidth = DEFAULT_WIDTH; + measuredHeight = DEFAULT_HEIGHT; + } + + } + + override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void + { + if (_container) + { + _container.width = unscaledWidth; + _container.height = unscaledHeight; + } + + super.updateDisplayList(unscaledWidth, unscaledHeight); + } + + // Internals + // + + private function onMediaSizeChange(event:DisplayObjectEvent):void + { + invalidateSize(); + invalidateDisplayList(); + } + + private static const DEFAULT_WIDTH:Number = 320; + private static const DEFAULT_HEIGHT:Number = 240; + + + private var _container:MediaContainer; + } } \ No newline at end of file diff --git a/lib/osmf/samples/MediaPlayerSpriteSample/.actionScriptProperties b/lib/osmf/samples/MediaPlayerSpriteSample/.actionScriptProperties index 50617f6..b18a22a 100644 --- a/lib/osmf/samples/MediaPlayerSpriteSample/.actionScriptProperties +++ b/lib/osmf/samples/MediaPlayerSpriteSample/.actionScriptProperties @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MediaPlayerSpriteSample/src/MediaPlayerSpriteSample.as b/lib/osmf/samples/MediaPlayerSpriteSample/src/MediaPlayerSpriteSample.as index 6abf5f3..f2a73ab 100644 --- a/lib/osmf/samples/MediaPlayerSpriteSample/src/MediaPlayerSpriteSample.as +++ b/lib/osmf/samples/MediaPlayerSpriteSample/src/MediaPlayerSpriteSample.as @@ -1,81 +1,81 @@ -/***************************************************** - * - * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. - * - ***************************************************** - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems - * Incorporated. All Rights Reserved. - * - *****************************************************/ -package -{ - import flash.display.Sprite; - import flash.display.StageAlign; - import flash.display.StageScaleMode; - import flash.events.Event; - - import org.osmf.events.DisplayObjectEvent; - import org.osmf.events.MediaPlayerCapabilityChangeEvent; - import org.osmf.events.MediaPlayerStateChangeEvent; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaPlayerSprite; - import org.osmf.media.MediaPlayerState; - import org.osmf.media.URLResource; - - /** - * A simple demonstration of the MediaPlayerSprite. This sample will - * show how the MediaPlayerSprite can take a URLResource, and create a video - * with a letterbox layout, and scaling capability in 9 lines of code. - **/ - [SWF(backgroundColor=0x000000)] - public class MediaPlayerSpriteSample extends Sprite - { - public function MediaPlayerSpriteSample() - { - //Neccesary to prevent the MPS from scaling via ScaleX and ScaleY. - stage.scaleMode = StageScaleMode.NO_SCALE; - stage.align = StageAlign.TOP_LEFT; - - // Create the container class that displays the media. - mps = new MediaPlayerSprite(); - addChild(mps); - - stage.addEventListener(Event.RESIZE, onResize); - - mps.resource = new URLResource(REMOTE_PROGRESSIVE); - - //Update the MPS to the initial size. - onResize(); - } - - /** - * Resizes the component when the stage resizes. Matches - * the width and height the stage. - */ - private function onResize(event:Event = null):void - { - mps.width = stage.stageWidth; - mps.height = stage.stageHeight; - } - - private static const REMOTE_PROGRESSIVE:String = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; - private var mps:MediaPlayerSprite; - } -} - - +/***************************************************** + * + * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package +{ + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + + import org.osmf.events.DisplayObjectEvent; + import org.osmf.events.MediaPlayerCapabilityChangeEvent; + import org.osmf.events.MediaPlayerStateChangeEvent; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaPlayerSprite; + import org.osmf.media.MediaPlayerState; + import org.osmf.media.URLResource; + + /** + * A simple demonstration of the MediaPlayerSprite. This sample will + * show how the MediaPlayerSprite can take a URLResource, and create a video + * with a letterbox layout, and scaling capability in 9 lines of code. + **/ + [SWF(backgroundColor=0x000000)] + public class MediaPlayerSpriteSample extends Sprite + { + public function MediaPlayerSpriteSample() + { + //Neccesary to prevent the MPS from scaling via ScaleX and ScaleY. + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + + // Create the container class that displays the media. + mps = new MediaPlayerSprite(); + addChild(mps); + + stage.addEventListener(Event.RESIZE, onResize); + + mps.resource = new URLResource(REMOTE_PROGRESSIVE); + + //Update the MPS to the initial size. + onResize(); + } + + /** + * Resizes the component when the stage resizes. Matches + * the width and height the stage. + */ + private function onResize(event:Event = null):void + { + mps.width = stage.stageWidth; + mps.height = stage.stageHeight; + } + + private static const REMOTE_PROGRESSIVE:String = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; + private var mps:MediaPlayerSprite; + } +} + + diff --git a/lib/osmf/samples/MediaPlayerSpriteSample/src/publish_settings.xml b/lib/osmf/samples/MediaPlayerSpriteSample/src/publish_settings.xml index 3dd8ca2..418e07a 100644 --- a/lib/osmf/samples/MediaPlayerSpriteSample/src/publish_settings.xml +++ b/lib/osmf/samples/MediaPlayerSpriteSample/src/publish_settings.xml @@ -1,180 +1,180 @@ - - - - 1 - 1 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - MediaPlayerSpriteSample.swf - MediaPlayerSpriteSample.swt - MediaPlayerSpriteSample.exe - MediaPlayerSpriteSample.app - MediaPlayerSpriteSample.html - MediaPlayerSpriteSample.gif - MediaPlayerSpriteSample.jpg - MediaPlayerSpriteSample.png - MediaPlayerSpriteSample.mov - MediaPlayerSpriteSample.smil - - - 0 - 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; - 1 - 1 - MediaPlayerSpriteSample_content.html - MediaPlayerSpriteSample_alternate.html - 0 - - 100 - 100 - 0 - 2 - 0 - 0 - 3 - 1 - 1 - 4 - 0 - 0 - 1 - 0 - /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html - 1 - - - - - 0 - 0 - 0 - 80 - 0 - 0 - 7 - 0 - 7 - 0 - 10 - FlashPlayer10 - 3 - 1 - - ./src;../../../../libs/ChromeLibrary;../../../../framework/OSMF - $(AppConfig)/ActionScript 3.0/libs - . - CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; - 0 - - 1 - 1 - 0 - 0 - 0 - 0 - MediaPlayerSpriteSample - 1 - 1 - 1 - AS3 - 1 - 1 - 0 - 15 - 1 - 0 - - - 550 - 400 - 0 - 4718592 - 0 - 80 - 1 - - - 1 - 0 - 1 - 0 - 0 - 100000 - 1 - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 1 - - - 550 - 400 - 0 - 1 - 1 - - 1 - 0 - 1 - 0 - 0 - - 128 - - - 255 - - - - 550 - 400 - 1 - 0 - 0 - 1 - 0 - 0 - 1 - - - - 24-bit with Alpha - 255 - - - - 550 - 400 - 1 - 0 - - - 00000000 - 0 - 0 - 0 - 0 - 1 - - + + + + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + MediaPlayerSpriteSample.swf + MediaPlayerSpriteSample.swt + MediaPlayerSpriteSample.exe + MediaPlayerSpriteSample.app + MediaPlayerSpriteSample.html + MediaPlayerSpriteSample.gif + MediaPlayerSpriteSample.jpg + MediaPlayerSpriteSample.png + MediaPlayerSpriteSample.mov + MediaPlayerSpriteSample.smil + + + 0 + 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + MediaPlayerSpriteSample_content.html + MediaPlayerSpriteSample_alternate.html + 0 + + 100 + 100 + 0 + 2 + 0 + 0 + 3 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 10 + FlashPlayer10 + 3 + 1 + + ./src;../../../../libs/ChromeLibrary;../../../../framework/OSMF + $(AppConfig)/ActionScript 3.0/libs + . + CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; + 0 + + 1 + 1 + 0 + 0 + 0 + 0 + MediaPlayerSpriteSample + 1 + 1 + 1 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + + + 550 + 400 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 550 + 400 + 0 + 1 + 1 + + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 550 + 400 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 550 + 400 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + diff --git a/lib/osmf/samples/MulticastPlayer/.actionScriptProperties b/lib/osmf/samples/MulticastPlayer/.actionScriptProperties index 3238352..bad554f 100644 --- a/lib/osmf/samples/MulticastPlayer/.actionScriptProperties +++ b/lib/osmf/samples/MulticastPlayer/.actionScriptProperties @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/MulticastPlayer/.flexProperties b/lib/osmf/samples/MulticastPlayer/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/MulticastPlayer/.flexProperties +++ b/lib/osmf/samples/MulticastPlayer/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/MulticastPlayer/html-template/AC_OETags.js b/lib/osmf/samples/MulticastPlayer/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/MulticastPlayer/html-template/AC_OETags.js +++ b/lib/osmf/samples/MulticastPlayer/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/MulticastPlayer/html-template/history/historyFrame.html b/lib/osmf/samples/MulticastPlayer/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/MulticastPlayer/html-template/history/historyFrame.html +++ b/lib/osmf/samples/MulticastPlayer/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/MulticastPlayer/html-template/index.template.html b/lib/osmf/samples/MulticastPlayer/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/MulticastPlayer/html-template/index.template.html +++ b/lib/osmf/samples/MulticastPlayer/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/NestedMediaContainersSample/.actionScriptProperties b/lib/osmf/samples/NestedMediaContainersSample/.actionScriptProperties index a6f75f3..07ed7e5 100644 --- a/lib/osmf/samples/NestedMediaContainersSample/.actionScriptProperties +++ b/lib/osmf/samples/NestedMediaContainersSample/.actionScriptProperties @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/NestedMediaContainersSample/html-template/AC_OETags.js b/lib/osmf/samples/NestedMediaContainersSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/NestedMediaContainersSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/NestedMediaContainersSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/NestedMediaContainersSample/html-template/history/historyFrame.html b/lib/osmf/samples/NestedMediaContainersSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/NestedMediaContainersSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/NestedMediaContainersSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/NestedMediaContainersSample/html-template/index.template.html b/lib/osmf/samples/NestedMediaContainersSample/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/NestedMediaContainersSample/html-template/index.template.html +++ b/lib/osmf/samples/NestedMediaContainersSample/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/NestedMediaContainersSample/readme.txt b/lib/osmf/samples/NestedMediaContainersSample/readme.txt index ddffd9d..4279319 100644 --- a/lib/osmf/samples/NestedMediaContainersSample/readme.txt +++ b/lib/osmf/samples/NestedMediaContainersSample/readme.txt @@ -1,34 +1,34 @@ -Sample Application: Nested Regions - -A. Overview - -This sample application demonstrates part of the framework's gateway feature, that allows media -elements to be routed. Gateway objects are of type IMediaGateway. A specialized interface is -IContainerGateway, that specifies gateways that may contain one or more media element children. -The RegionSprite class implements this interface, but derives from Sprite. This constitutes a -media element container that can be staged in Flash. This allows for sending parts of a -composition to predefined regions within a Flash experience. - -RegionSprite instances can have child regions. The child regions of a region are laid out using -the same layout mechanism that is available for parallel viewable elements. This sample shows -how to create a nested region, and how to lay out the child regions relative to their parent. - -B. Installation Instructions (Flex Builder) - -1. Unzip/copy the NestedRegionsSample project into your Flex Builder workspace folder. -2. In Flex Builder, go to the File menu and select "Import". -3. Select "General", then "Existing Projects into Workspace", and click "Next". -4. Choose "Select root directory" and "Browse". -5. Browse to your Flex Builder workspace folder. -6. Select the checkbox next to "NestedRegionSample", and click "Finish". This will import the project. -7. Build the project. -8. Launch the application from the Run menu. - -Note that the sample loads assets from the web, so please make sure to be connected to the -internet when trying them out. - -C. Usage Instructions - -The sample is not interactive. Please note that the semi-transparent blue and green areas denote -the child regions. This region background is specifically set from the sample code (using the +Sample Application: Nested Regions + +A. Overview + +This sample application demonstrates part of the framework's gateway feature, that allows media +elements to be routed. Gateway objects are of type IMediaGateway. A specialized interface is +IContainerGateway, that specifies gateways that may contain one or more media element children. +The RegionSprite class implements this interface, but derives from Sprite. This constitutes a +media element container that can be staged in Flash. This allows for sending parts of a +composition to predefined regions within a Flash experience. + +RegionSprite instances can have child regions. The child regions of a region are laid out using +the same layout mechanism that is available for parallel viewable elements. This sample shows +how to create a nested region, and how to lay out the child regions relative to their parent. + +B. Installation Instructions (Flex Builder) + +1. Unzip/copy the NestedRegionsSample project into your Flex Builder workspace folder. +2. In Flex Builder, go to the File menu and select "Import". +3. Select "General", then "Existing Projects into Workspace", and click "Next". +4. Choose "Select root directory" and "Browse". +5. Browse to your Flex Builder workspace folder. +6. Select the checkbox next to "NestedRegionSample", and click "Finish". This will import the project. +7. Build the project. +8. Launch the application from the Run menu. + +Note that the sample loads assets from the web, so please make sure to be connected to the +internet when trying them out. + +C. Usage Instructions + +The sample is not interactive. Please note that the semi-transparent blue and green areas denote +the child regions. This region background is specifically set from the sample code (using the region's backgroundColor and backgroundAlpha properties). \ No newline at end of file diff --git a/lib/osmf/samples/NestedMediaContainersSample/src/NestedMediaContainersSample.as b/lib/osmf/samples/NestedMediaContainersSample/src/NestedMediaContainersSample.as index 6c04717..d751a32 100644 --- a/lib/osmf/samples/NestedMediaContainersSample/src/NestedMediaContainersSample.as +++ b/lib/osmf/samples/NestedMediaContainersSample/src/NestedMediaContainersSample.as @@ -1,188 +1,188 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package -{ - import flash.display.Sprite; - import flash.display.StageAlign; - import flash.display.StageScaleMode; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.DurationElement; - import org.osmf.elements.ImageElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.SerialElement; - import org.osmf.elements.VideoElement; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaPlayer; - import org.osmf.media.URLResource; - - [SWF(backgroundColor='#333333', frameRate='30')] - public class NestedMediaContainersSample extends Sprite - { - public function NestedMediaContainersSample() - { - // Setup the Flash stage: - - stage.scaleMode = StageScaleMode.NO_SCALE; - stage.align = StageAlign.TOP_LEFT; - - runSample(); - } - - private function runSample():void - { - // Construct a small tree of media elements: - - var rootElement:ParallelElement = new ParallelElement(); - - var mainContent:VideoElement = constructVideo(REMOTE_PROGRESSIVE); - rootElement.addChild(mainContent); - - var banners:SerialElement = new SerialElement(); - banners.addChild(constructBanner(BANNER_1)); - banners.addChild(constructBanner(BANNER_2)); - banners.addChild(constructBanner(BANNER_3)); - rootElement.addChild(banners); - - var skyScraper:MediaElement = constructImage(SKY_SCRAPER_1); - rootElement.addChild(skyScraper); - - // Next, decorate the content tree with attributes: - - var bannersLayout:LayoutMetadata = new LayoutMetadata(); - banners.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, bannersLayout); - bannersLayout.percentWidth = 100; - bannersLayout.percentHeight = 100; - bannersLayout.scaleMode = ScaleMode.LETTERBOX; - bannersLayout.verticalAlign = VerticalAlign.TOP; - bannersLayout.horizontalAlign = HorizontalAlign.CENTER; - - var skyScraperLayout:LayoutMetadata = new LayoutMetadata() - skyScraper.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, skyScraperLayout); - skyScraperLayout.percentWidth = 100; - skyScraperLayout.percentHeight = 100; - skyScraperLayout.scaleMode = ScaleMode.LETTERBOX; - skyScraperLayout.verticalAlign = VerticalAlign.MIDDLE; - skyScraperLayout.horizontalAlign = HorizontalAlign.RIGHT; - - var mainLayout:LayoutMetadata = new LayoutMetadata(); - mainContent.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, mainLayout); - mainLayout.percentWidth = 100; - mainLayout.percentHeight = 100; - mainLayout.scaleMode = ScaleMode.STRETCH; - mainLayout.verticalAlign = VerticalAlign.TOP; - mainLayout.horizontalAlign = HorizontalAlign.CENTER; - - // Consruct a tree of containers: - - var mainGroup:MediaContainer = new MediaContainer(); - mainGroup.width = 640; - mainGroup.height = 352; - mainGroup.backgroundColor = 0xFFFFFF; - mainGroup.backgroundAlpha = .2; - addChild(mainGroup); - - var bannerGroup:MediaContainer = new MediaContainer(); - bannerGroup.backgroundColor = 0xFF; - bannerGroup.backgroundAlpha = .2; - bannerGroup.height = 60; - - bannerGroup.layoutMetadata.left = bannerGroup.layoutMetadata.right = bannerGroup.layoutMetadata.top = 5; - - var skyScraperGroup:MediaContainer = new MediaContainer(); - skyScraperGroup.backgroundColor = 0xFF00; - skyScraperGroup.backgroundAlpha = .2; - skyScraperGroup.width = 120; - - skyScraperGroup.layoutMetadata.right = skyScraperGroup.layoutMetadata.top = skyScraperGroup.layoutMetadata.bottom = 5; - - // Bind media elements to their target containers: - mainGroup.addMediaElement(mainContent); - bannerGroup.addMediaElement(banners); - skyScraperGroup.addMediaElement(skyScraper); - - // Add the sub containers to the main container's layout renderer. We - // can do this because MediaContainer implements ILayoutTarget: - mainGroup.layoutRenderer.addTarget(bannerGroup); - mainGroup.layoutRenderer.addTarget(skyScraperGroup); - - // To operate playback of the content tree, construct a - // media player. Assignment of the root element to its source will - // automatically start its loading and playback: - - var player:MediaPlayer = new MediaPlayer(); - player.media = rootElement; - } - - // Utilities - // - - private function constructBanner(url:String):MediaElement - { - return new DurationElement - ( BANNER_INTERVAL - , constructImage(url) - ); - } - - private function constructImage(url:String):MediaElement - { - return new ImageElement - ( new URLResource(url) - ) - - } - - private function constructVideo(url:String):VideoElement - { - return new VideoElement - ( new URLResource(url) - ); - } - - private static const BANNER_INTERVAL:int = 5; - - private static const REMOTE_PROGRESSIVE:String - = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; - - // IAB standard banners from: - private static const IAB_URL:String - = "http://www.iab.net/iab_products_and_industry_services/1421/1443/1452"; - - private static const BANNER_1:String - = "http://www.iab.net/media/image/468x60.gif"; - - private static const BANNER_2:String - = "http://www.iab.net/media/image/234x60.gif"; - - private static const BANNER_3:String - = "http://www.iab.net/media/image/120x60.gif"; - - private static const SKY_SCRAPER_1:String - = "http://www.iab.net/media/image/120x600.gif" - - } -} +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package +{ + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.DurationElement; + import org.osmf.elements.ImageElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.SerialElement; + import org.osmf.elements.VideoElement; + import org.osmf.layout.HorizontalAlign; + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.ScaleMode; + import org.osmf.layout.VerticalAlign; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaPlayer; + import org.osmf.media.URLResource; + + [SWF(backgroundColor='#333333', frameRate='30')] + public class NestedMediaContainersSample extends Sprite + { + public function NestedMediaContainersSample() + { + // Setup the Flash stage: + + stage.scaleMode = StageScaleMode.NO_SCALE; + stage.align = StageAlign.TOP_LEFT; + + runSample(); + } + + private function runSample():void + { + // Construct a small tree of media elements: + + var rootElement:ParallelElement = new ParallelElement(); + + var mainContent:VideoElement = constructVideo(REMOTE_PROGRESSIVE); + rootElement.addChild(mainContent); + + var banners:SerialElement = new SerialElement(); + banners.addChild(constructBanner(BANNER_1)); + banners.addChild(constructBanner(BANNER_2)); + banners.addChild(constructBanner(BANNER_3)); + rootElement.addChild(banners); + + var skyScraper:MediaElement = constructImage(SKY_SCRAPER_1); + rootElement.addChild(skyScraper); + + // Next, decorate the content tree with attributes: + + var bannersLayout:LayoutMetadata = new LayoutMetadata(); + banners.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, bannersLayout); + bannersLayout.percentWidth = 100; + bannersLayout.percentHeight = 100; + bannersLayout.scaleMode = ScaleMode.LETTERBOX; + bannersLayout.verticalAlign = VerticalAlign.TOP; + bannersLayout.horizontalAlign = HorizontalAlign.CENTER; + + var skyScraperLayout:LayoutMetadata = new LayoutMetadata() + skyScraper.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, skyScraperLayout); + skyScraperLayout.percentWidth = 100; + skyScraperLayout.percentHeight = 100; + skyScraperLayout.scaleMode = ScaleMode.LETTERBOX; + skyScraperLayout.verticalAlign = VerticalAlign.MIDDLE; + skyScraperLayout.horizontalAlign = HorizontalAlign.RIGHT; + + var mainLayout:LayoutMetadata = new LayoutMetadata(); + mainContent.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, mainLayout); + mainLayout.percentWidth = 100; + mainLayout.percentHeight = 100; + mainLayout.scaleMode = ScaleMode.STRETCH; + mainLayout.verticalAlign = VerticalAlign.TOP; + mainLayout.horizontalAlign = HorizontalAlign.CENTER; + + // Consruct a tree of containers: + + var mainGroup:MediaContainer = new MediaContainer(); + mainGroup.width = 640; + mainGroup.height = 352; + mainGroup.backgroundColor = 0xFFFFFF; + mainGroup.backgroundAlpha = .2; + addChild(mainGroup); + + var bannerGroup:MediaContainer = new MediaContainer(); + bannerGroup.backgroundColor = 0xFF; + bannerGroup.backgroundAlpha = .2; + bannerGroup.height = 60; + + bannerGroup.layoutMetadata.left = bannerGroup.layoutMetadata.right = bannerGroup.layoutMetadata.top = 5; + + var skyScraperGroup:MediaContainer = new MediaContainer(); + skyScraperGroup.backgroundColor = 0xFF00; + skyScraperGroup.backgroundAlpha = .2; + skyScraperGroup.width = 120; + + skyScraperGroup.layoutMetadata.right = skyScraperGroup.layoutMetadata.top = skyScraperGroup.layoutMetadata.bottom = 5; + + // Bind media elements to their target containers: + mainGroup.addMediaElement(mainContent); + bannerGroup.addMediaElement(banners); + skyScraperGroup.addMediaElement(skyScraper); + + // Add the sub containers to the main container's layout renderer. We + // can do this because MediaContainer implements ILayoutTarget: + mainGroup.layoutRenderer.addTarget(bannerGroup); + mainGroup.layoutRenderer.addTarget(skyScraperGroup); + + // To operate playback of the content tree, construct a + // media player. Assignment of the root element to its source will + // automatically start its loading and playback: + + var player:MediaPlayer = new MediaPlayer(); + player.media = rootElement; + } + + // Utilities + // + + private function constructBanner(url:String):MediaElement + { + return new DurationElement + ( BANNER_INTERVAL + , constructImage(url) + ); + } + + private function constructImage(url:String):MediaElement + { + return new ImageElement + ( new URLResource(url) + ) + + } + + private function constructVideo(url:String):VideoElement + { + return new VideoElement + ( new URLResource(url) + ); + } + + private static const BANNER_INTERVAL:int = 5; + + private static const REMOTE_PROGRESSIVE:String + = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; + + // IAB standard banners from: + private static const IAB_URL:String + = "http://www.iab.net/iab_products_and_industry_services/1421/1443/1452"; + + private static const BANNER_1:String + = "http://www.iab.net/media/image/468x60.gif"; + + private static const BANNER_2:String + = "http://www.iab.net/media/image/234x60.gif"; + + private static const BANNER_3:String + = "http://www.iab.net/media/image/120x60.gif"; + + private static const SKY_SCRAPER_1:String + = "http://www.iab.net/media/image/120x600.gif" + + } +} diff --git a/lib/osmf/samples/NestedMediaContainersSample/src/publish_settings.xml b/lib/osmf/samples/NestedMediaContainersSample/src/publish_settings.xml index 71936b4..7882682 100644 --- a/lib/osmf/samples/NestedMediaContainersSample/src/publish_settings.xml +++ b/lib/osmf/samples/NestedMediaContainersSample/src/publish_settings.xml @@ -1,180 +1,180 @@ - - - - 1 - 1 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - NestedMediaContainersSample.swf - NestedMediaContainersSample.swt - NestedMediaContainersSample.exe - NestedMediaContainersSample.app - NestedMediaContainersSample.html - NestedMediaContainersSample.gif - NestedMediaContainersSample.jpg - NestedMediaContainersSample.png - NestedMediaContainersSample.mov - NestedMediaContainersSample.smil - - - 0 - 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; - 1 - 1 - NestedMediaContainersSample_content.html - NestedMediaContainersSample_alternate.html - 0 - - 100 - 100 - 0 - 2 - 0 - 0 - 3 - 1 - 1 - 4 - 0 - 0 - 1 - 0 - /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html - 1 - - - - - 0 - 0 - 0 - 80 - 0 - 0 - 7 - 0 - 7 - 0 - 10 - FlashPlayer10 - 3 - 1 - - .;../../../../libs/ChromeLibrary;../../../../framework/OSMF - $(AppConfig)/ActionScript 3.0/libs - . - CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; - 0 - - 1 - 1 - 0 - 0 - 0 - 0 - NestedMediaContainersSample - 1 - 1 - 1 - AS3 - 1 - 1 - 0 - 15 - 1 - 0 - - - 550 - 400 - 0 - 4718592 - 0 - 80 - 1 - - - 1 - 0 - 1 - 0 - 0 - 100000 - 1 - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 1 - - - 550 - 400 - 0 - 1 - 1 - - 1 - 0 - 1 - 0 - 0 - - 128 - - - 255 - - - - 550 - 400 - 1 - 0 - 0 - 1 - 0 - 0 - 1 - - - - 24-bit with Alpha - 255 - - - - 550 - 400 - 1 - 0 - - - 00000000 - 0 - 0 - 0 - 0 - 1 - - + + + + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + NestedMediaContainersSample.swf + NestedMediaContainersSample.swt + NestedMediaContainersSample.exe + NestedMediaContainersSample.app + NestedMediaContainersSample.html + NestedMediaContainersSample.gif + NestedMediaContainersSample.jpg + NestedMediaContainersSample.png + NestedMediaContainersSample.mov + NestedMediaContainersSample.smil + + + 0 + 10,0,2,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + NestedMediaContainersSample_content.html + NestedMediaContainersSample_alternate.html + 0 + + 100 + 100 + 0 + 2 + 0 + 0 + 3 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + /Users/oconnell/Library/Application Support/Adobe/Flash CS4/en/Configuration/HTML/DefaultWithFullScreen.html + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 10 + FlashPlayer10 + 3 + 1 + + .;../../../../libs/ChromeLibrary;../../../../framework/OSMF + $(AppConfig)/ActionScript 3.0/libs + . + CONFIG::FLASH_AUTHORING="true";CONFIG::LOGGING="false";CONFIG::FLASH_10_1="false"; + 0 + + 1 + 1 + 0 + 0 + 0 + 0 + NestedMediaContainersSample + 1 + 1 + 1 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + + + 550 + 400 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 550 + 400 + 0 + 1 + 1 + + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 550 + 400 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 550 + 400 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + diff --git a/lib/osmf/samples/OSMFPlayer/.actionScriptProperties b/lib/osmf/samples/OSMFPlayer/.actionScriptProperties index 8103278..c4c6ad1 100644 --- a/lib/osmf/samples/OSMFPlayer/.actionScriptProperties +++ b/lib/osmf/samples/OSMFPlayer/.actionScriptProperties @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/OSMFPlayer/assets source/.svn/entries b/lib/osmf/samples/OSMFPlayer/assets source/.svn/entries deleted file mode 100644 index 8cb7902..0000000 --- a/lib/osmf/samples/OSMFPlayer/assets source/.svn/entries +++ /dev/null @@ -1,62 +0,0 @@ -10 - -dir -2495 -http://svn.code.sf.net/adobe/osmf/svn/osmf/tags/1.6.1/samples/OSMFPlayer/assets%20source -http://svn.code.sf.net/adobe/osmf/svn - - - -2010-03-29T06:43:34.909324Z -1445 -evrijkom@adobe.com - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -a9308255-753e-0410-a2e9-80b3fbc4fff6 - -assets.ai -file - - - - -2012-02-07T09:49:43.000000Z -e522a21787da58d4bd5f95bbb4568d01 -2010-03-29T06:43:34.909324Z -1445 -evrijkom@adobe.com - - - - - - - - - - - - - - - - - - - - - -428692 - diff --git a/lib/osmf/samples/OSMFPlayer/assets source/.svn/text-base/assets.ai.svn-base b/lib/osmf/samples/OSMFPlayer/assets source/.svn/text-base/assets.ai.svn-base deleted file mode 100644 index 323a8e0..0000000 --- a/lib/osmf/samples/OSMFPlayer/assets source/.svn/text-base/assets.ai.svn-base +++ /dev/null @@ -1,4593 +0,0 @@ -%PDF-1.5 %âãÏÓ -1 0 obj <>/OCGs[7 0 R 10 0 R 8 0 R 9 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 373 0 R 374 0 R 375 0 R 376 0 R 377 0 R 378 0 R 379 0 R 736 0 R 737 0 R 738 0 R 739 0 R 740 0 R 741 0 R 742 0 R 1099 0 R 1100 0 R 1101 0 R 1102 0 R 1103 0 R 1104 0 R 1105 0 R 1462 0 R 1463 0 R 1464 0 R 1465 0 R 1466 0 R 1467 0 R 1468 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream - - - - - application/pdf - - - assets - - - - - Adobe Illustrator CS4 - 2010-03-21T15:29:21+01:00 - 2010-03-29T08:42:07+02:00 - 2010-03-29T08:42:07+02:00 - - - - 256 - 204 - JPEG - /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAzAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FWmYKKnYDFVNbqEy enWjUqAfDFV7yKi8mNBiqyO6ieVogaSJTkp2O/TFVQsAKnFVpmTgWrsMVQzajFHKschpyNAe1fDF W5r9Yk9Vh+5qAW7gHoaeGKqhu4gAeWx6YqrKwZQw6HFUm1rzr5R0O5W11jWLSwuXQSLDcTIjlCSA 3EmtKg4ql/8Aytb8tf8AqZtO/wCkiP8Arirv+Vrflr/1M2nf9JEf9cVd/wArW/LX/qZtO/6SI/64 q7/la35a/wDUzad/0kR/1xV3/K1vy1/6mbTv+kiP+uKu/wCVrflr/wBTNp3/AEkR/wBcVd/ytb8t f+pm07/pIj/rirv+Vrflr/1M2nf9JEf9cVd/ytb8tf8AqZtO/wCkiP8Arirv+Vrflr/1M2nf9JEf 9cVd/wArW/LX/qZtO/6SI/64q7/la35a/wDUzad/0kR/1xV3/K1vy1/6mbTv+kiP+uKu/wCVrflr /wBTNp3/AEkR/wBcVd/ytb8tf+pm07/pIj/rirv+Vrflr/1M2nf9JEf9cVd/ytb8tf8AqZtO/wCk iP8Arirv+Vrflr/1M2nf9JEf9cVd/wArW/LX/qZtO/6SI/64q7/la35a/wDUzad/0kR/1xVPdI1r SNZshfaTeQ31mzFRPbusicl2Iqtdxiqrfcvq7cTQ+IFfwxVj9mL1ryr3DygE0VoglBX+YYqnGqPK tsGSQxsP2wgcg0/lOKpJpDXr3avJdvdEbEvAsNB8164qyO7DlPhNDiqHgglaJkLGp6E4qgv0HeyX Ae4nDxq4dVAA3AI7D3xVZc6NrE0pjN2v1FqBoeArRRt8VK4qmX6OPBFDfZGKouKPggXwFMVS7VfK nlbWJ1uNW0ex1GdF4JLd20M7hak8Q0isQKnpiqB/5Vx+Xn/Ur6R/0gW3/VPFXf8AKuPy8/6lfSP+ kC2/6p4q7/lXH5ef9SvpH/SBbf8AVPFXf8q4/Lz/AKlfSP8ApAtv+qeKu/5Vx+Xn/Ur6R/0gW3/V PFXf8q4/Lz/qV9I/6QLb/qnirv8AlXH5ef8AUr6R/wBIFt/1TxV3/KuPy8/6lfSP+kC2/wCqeKu/ 5Vx+Xn/Ur6R/0gW3/VPFXf8AKuPy8/6lfSP+kC2/6p4q7/lXH5ef9SvpH/SBbf8AVPFXf8q4/Lz/ AKlfSP8ApAtv+qeKu/5Vx+Xn/Ur6R/0gW3/VPFXf8q4/Lz/qV9I/6QLb/qnirv8AlXH5ef8AUr6R /wBIFt/1TxV3/KuPy8/6lfSP+kC2/wCqeKu/5Vx+Xn/Ur6R/0gW3/VPFXf8AKuPy8/6lfSP+kC2/ 6p4q7/lXH5ef9SvpH/SBbf8AVPFXf8q4/Lz/AKlfSP8ApAtv+qeKpzp2mabplolnptpDZWkdTHbW 8axRryNTRECqKk1xVXkZVQlug64qowzW7ysgWjr1FMVVZWQKOQqCQAD4nFVG0mtpWYInF0NGUgAj FVd2VRU4q5GRhVcVS691mG2lRGPxSMEROpJOKpirgoG9q4qgJtWhiuIYS4Ms5PGIbsAP2j4DFUe0 gVC3gK4qlNn5ghudQe0VTyStdthQ0xVNJpljUE9yAPpxVjNh+YflLUZbeLTte069ku3litEt7mGU yyQIskqRhHbm0aOrOB0BBOKozTvN2kahb211YXkN/Z3fP6vdWsiSxP6bcW4uhZTRqg0PXFVO988e U7O4ure78xaZZ3NjEk9/bXF3BHLbxSlAjzIzgxqxnjALUqWXxGKoqTX7BJb+Bb+2uLvShEdRs4ZF aeD1xyi9WMNyj9RfiXkBUdMVWaj5w8vabJYw6hqNtZXOpN6en29xNHFJcPVV4Qo7KZGq6ii16jxx VD2nn7ypefUfqmrWdx+lPV/RvpXET/Wfq9fW9Dix9T06fHxrx74qnLXqmMMNuXTFUtk8y2cepwaY 84F9cwzXMEPFviitniSVuX2Rxa4jFCamu3Q0VRUesRGdoGNXVFeo6UYsB/xHFXapqMemW6XN7cLD BJPb2qNwdqzXc6W0C0UMfjllVa9BWpoN8VbvtQbT/q5uWDC5mWBOI/aZWYdf9XFVSbUoojQ4qg9J 80aZq2nWmpWEhmsr6GO5tZeLLzilQOjcXCsKqwNCK4qnCMGUMOh3xVvFXYq7FXYq7FXYqp3MZkhZ B1IxVLrGxuhfSXMz/DQrHGBsATX78VRt7Gzxrx3KMGp40xVAaPYX0c891eSh5JaBUUUVFWtFG58c VTK4jLpQYq1bQmOOhNTiqjc2UHI3BWsij4cVQFjdXE+ocVRlhUEMWFKnFUbcWkERa54nn3IFTT2x VD6dcyXN1KQjJbhQFDihJHXFW76BbOGSa3jrK3WnXFUHpz3s1oZLhSCrBgveg3xVgy+U/L8KeWrd 7S5uYfKkKwacLi1sp2b044445GlkiaWN0MKuGgaOrDeoAGKpvoWkThoAbm+vZkkkkuLvUPT9Ry6o qhUhEcMaqsYHGONR+0QWZmKq3XdK8vtpuuaRdQX0i6/cW95fOLayu0WW3gtrdRHFeRTwFeNih/eR sakkEHjxVXF7G4E9tYrqUNu9vHZ6ZpTRwQadZQxiMFYYrcR15eitDKXKbiPgrMCqm9z5Zjlv9P1Z mk+t2NpcWUaCnpmO7kt5JCwpy5BrROO/c9dqKpBon5a2uj2llZafcz2tpbTNc3UNrDZWS3kpZWRr n6nb2/8Ad+mopFwDqOMnNagqsxuEaC0R2VmCihCip3HucVeMW35XJb6mb8X1yzx2dzYpAbNTBc/W HhLXGpxGcpez3CRMl47BfWHAqInjV8Vep6fBJc3kt2sbonoxx8XADVR3Y9Cf5sVYP538qad5g8xt qE1xqFvGbuxvJHgtyt7xspIWNkl9HcwyR2L+h6ohRQyXJ9cPUcMVZLaA3mn6Xpsccpms9Qa8nunt YrUTc2mZpJEhYx+vIZuUzqqq8nJwqV4hVr8wPIMvmaSzIuzbfVfUX4ovW4erw/0m2+OP0L6D0/8A R7j4vT5P8DctlVDyH+X03laxt7AXZvkgs7S0SeWKk4+rIwZfVLu5gLuXiiYn0izhW4FVRV6NApWJ VPYDFV+KuxV2KuxV2KuxVZLIEWp7kD7zTFUFFq0TnYf7saL6V3xVFyzBOI/mrT6FLfwxVBWesRXC W7qNrkMVHhwbicVR0swjFTiro5g9adsVSzUtaS2lWMEGRmVVjruQzUJpiqZxupjDU3IrTFUtutYi S5hgV1eWSTi8QIJVQpNSMVTLmqpyHhXFUltfMH1jVGtAnwryq1fAgYqm88yxoKftED78VYhoHn/R tb0iLV4nNpaTfVPT+syW6tyv4IJ4EYRyScJG+togR6MW+yCrIzKphp/m3Sr2G0utNuodQsrz1PRu 7eRJYm9M8W4vGWVqNUGh6jFW9P8AMun6pr13o0Pqx3VkzpMzmAKWjt7K5PpoZPWdeGpxjkI+KsCG K1TmqvTzH5fltrufTNWtdSeyignnitpopWSO7USW7uIyxVZozzjJ+0u42xVD6x5807S73TrGeJ2n 1KJpoWDQpGFS6tLQhmlkj+LnfxlVFS1CFBbirKqp87aENRj0xr62Goyu8UVkZoxO0kcSzyIsdeZZ IpEkYU2VgehGKp/byiaMNTY4qq8E8BirgoHQYq16aeAxVsIg6DFW6DFXUGKuxV2KuxV2KuxV2Kux VSuIy8dB1BBH0GuKpVbaRJG+/wBn1WmJ92FKYqmN3DIyKYxV0rQH3Ur/ABxVK9M0WS3FrG32LVXV D3PNuRriqb3EBkAGKugh9Ote+KrLu0jdGcKDKAeJ98VQFhFfPfPJKvp24JEaUoSPE4qjbm1iX98s fJwVJoKkgEVH3YqhtLjvXlkluUEaNskSilBXv4nFXarZsLdmtU/fE9h7Yqh7CyvksgbirSghuPTp 2xV53pv5brpdvbWFtFfyabbzWlzJZyTQFJ5dOtrS3tGlZbdZR6R0+KWkbqGfly5IeAVTryd5Ih0a ytrG1shaxwSSyyyLFawGaSWg5ulnBaQ8gqKtRGNgK+OKqWo+WLu01671bS01G31O7WVTe20tqfT9 eLT4ZPTjuLW5TdNHiHxhvtP4rxVUdH8oWdjcXf1Hy8LI3Vpa6dBMy2zSW1rZxxxJEtytul5MrLBH y+sTyfZFKAUxVO/MP5f2GtzaXd3Uk6T6YqiFYmRVPG9s774wyMf73ToxsR8JbvQhVK4Pyn0wajZa leySalf2tzJfS3N7BYyvNcvFFDHKW+rL6DQpbRBPq3pV4AvyNTir0Kyi9KEKeoGKojFXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FVOeXgu1KnYVxVLo9YV2lUEViNOh3+7FUZ9YZkSlFZhU18AKnFUut9eS aF5FIqrlAtGJNCR2+WKpnJchEDHauKuS45FaDriqvirsVdirsVdiqhdzGJVp+0wH3nFWJJ560GW1 nvEnkFrb6gNJkleGdFN4blbP005IPUX6w4j9RKpWvxbGiqFb8y/LSW0dy0l0sbu8LK1leiSKZApE M8Zh5wSy+qnoxyqrS8lEYbktVUvtPzZ0u784Dy7aIbtZLee5h1G2+szW/GK3s7mMNKIBb/vI70tV ZmVQI6nlKqhVlNx5p0yy0eTVNWeSK0iNslYIpp5Gku5hBEiRQLLK7PK6qAqnriq/VvM3ljSbqa1v 7qaOW2jt5rtlhuJY4ILozrFPcSxxvHDD/ocvOWRgicauVBFVUv1jz55U06HVFe7eG/0yC7na2vo7 y0VvqcTykh2gdmjdYZGjeJJPUWOVohJ6T8VVPy356ttb06LULS2uLVG1K+01oruK4iYiynkhWQLc RwN8axhmHH4GLRk8kbFU8fzNp36fk0FXdtTitUvpYxDKY0glkeKNmm4+iGd4n4pz5HiTSgOKpRB+ Zvlm4tfrNvLczxtawX9usVhfPJcW1wI2SW1jWEyXCr68fq+irelyAk4nFUn8wfnZ5e0xdPlsj+lY b6dYKWiXU0wrd2duZFjgt5wY/Sv1mRmZfVDRCLmJVYKvRIJC61OKsZ8+edX8u29tFYwR3ur3sqxW djJKsIk+IBvjbZS3IRx1+1IyJ1YYqmflfzLY+YNJt9Rs3DxXC817Gh7EHcHxBxVOMVdirsVdirsV dirsVUrmATRFCSK9CCQR9IxVDWmmRQs7EVZzVj74qq3dp6yKEYxshqrKSPoNOoxVRsNIt7WMrxBJ JYn3JqcVRU0CSAA9sVXRxKqgU6YqvqMVdirqjFXYq6oxVQvIWkjHGnJTUV6VGKvN5Py3Qi1T6sXS 0ulvlL31+zTXMbxyRy3bNcE3TRm3j4evz4hQq0UUxVEQeR54dO/R4s4ZIDcw30jzT3M08lzbSxzQ yy3EszzSsjQRgc3PwqqfZFMVU9D/AC6g0e4iksNOt7Zo4DaI4lncrC0NrblaSSuP7rTrdanf4K9W aqqe635XNzpSWZhW5hBRpbZ5p4opQgZTFOkMkQnhdZCHhl5Rv+0pxVj8/ku/uLu/uriySeTU5In1 BZr/AFKSOZITMyW7xPdmM2v+lS1tuPotyoUIpiqrr3lO91+5mudW0mxuZriAWsz+rdR1hEF3bcaR zoB+61O5Wo3+OvVVIVTjR9D1BTFBNbW9taxXNzfBYGkYme8me4nYmR5D8csztToK0FBtiqO1LyRo t/d3d5P9a+tXqLE9xHe3kUkUalGKWrRzIbVZDChlEHD1OI58sVWaL5E0DRZIpNPt3Rre1isLUSzz zrBbQokaxQLM8ghVhCnqemB6hVWfkwBxVA2n5T+SLT6v9X03h9U9D6v+/uDx+q/UvR6yGvH9EWvX rw3+0/JVlyJ6UZ9t8VeNXnmjyrd3+oah5ha8t9UbUrD6javZX6G3sdL1CG6WkiWlypad4PWZV+2v CMshHNVUb5T8y6UPzDurfy7JPPoOqh75le0ubZLe7Y/v0BniiqszH1RSvxF+m2KvXgagHxxV2Kux V2KuxV2KuxVTnk4JUdSQPvNMVS6DUpHvZbcVPBQenjiqOmlYCNa8WkJFaV6KW/hiqX2WqST3N1CA x9CTgNhTp44qmU0xjSuKrYJmkQNiqVazfzwSMgZouKiT1duIUE1rXFUVo2ote23NgwYFlPNeLVUk br2xVSurtqyAO8MkDipADBw4HFVHck7ADeuKorTb03dkkwBBdQQCKHcdxirEdS81anYauYnVvR5M oAANaH+mKste7ZraOQftkA/ScVea335z6Hb6c1/Hp95c/wChy6xFaw/VPXk0eJFf9JhHuE4QPzAR JCsxNf3fwtRVfoX5u6brVzp9la6VfpqOpW0OpwWMq2okGlzkKuoO63DRCIO3ExhzN/xVTfFVvl78 0x5h1e1TTbC4ttJubPUriG5v7Z7eS5Fm9j6Fzahm+K2mS+YhmUE07UNVWVS+a47SztjPaT6je30k dvp2n2vpCaeYxTTuqtPJBCvGG3kkJkkUUWgqxVSqkNx+cXlk6zpOmaToeoa4uvyXkWhahp7aebW9 bTQfrhhee8gYLEysvJ1VXpVCykEqq0n5u+Um8tp5j07SdU1fSb2dLXQpNPtRPNqc1JTMtpbc1uF+ ri2lMhuI4hRSU5bVVTHSfMd3d2MF08ccUjavqunkRAhTFYX9xaRE8ix5FIFLf5VaUG2Kta3+Zek6 XqF1aSxTv9Wmh08TKYFWbVLpYpLfTYVlljkeeSO4jkDcPSVSS0i8W4qsesPz60S5+setpGqWXo6o /l+P11s29bWUpTT4/RuZqSPX4ZH4w+MgxVFat+bUkWonSbHS71L63n0mPUrm6t62Vu+pX1nBJZNc RSGNrtLe+EgEbMnfk1CMVejW7mRDyxVB3PlzR7mQyTWyu56k4q3a+X9JtZBJBbqjjoRiqYgUxV2K uxV2KuxV2KuxVZLGkkZRxVT1BxVQtrGGBy6gVIpX2HbFVS6tobiIxygFffFVOzsYbYuy7tIas3cn 3xVESRq4owxV0aKgoMVQ99Y2l2nC4RXU7EMAcVda2SQUCUCAUAHhiqy902yuyBOisQQQGAO46HFV a3t/SrvUYqhrvSLC5mEkkaNIpqpIBIOKqpsj6HBTQjdT4EYqwy9/K/T7yCa2uLLTZ7S4umv57eWx tnje7cFWuHVoyGlYGhc/EfHFVzflvE31XlBYN9S+r/Uq2dufR+p8/q3pfu/g9D1X9Pj9jkeNKnFV ax8g/U7uS5t0s4Jp3mkuJYbWCOR3uShuGZ0QMWlMKFzX4uK16DFUy1nynHqGjyaW8dtPaThFuLa7 giuYZBE3NOUcquh4sKio64qk/wDgK+/T3+IeOnfp/wD6u/1C0+uf3fo/70el6v8AdfB9r7O3TFVE /lvIbW6szb6UbS+jt4b23/R1n6c0dkAtqkqejxdYFUCIN9inw0xVO9M8tajFJGLueF4I5ZbhYoYY 4R607tJLIRGq1aR3ZmPdiSd8VTG+8raDfXc15d6da3F1cWrafcXEsEbySWbks1s7spZoWY1MZ+E+ GKoO2/L/AMm2tgdOttC06DT2eSVrOO0gSEyTQm3kcxqgXk8DtGxpuhKnbFVVfJPldZoJl0ixE1rB Da20gtog0VvbSrNBDGeNVjiljV0UbKwBG4xVOoowgpiq/FXYq7FXYq7FXYq7FXYq7FUs1a8nijkW BecwUGNPHcA/cMVQlvfXTs0fEs6qvPiaAPQcgOuKuv73VPq5SxiE16JEQo24VGBq5BI2qKYqtj1C WaS5S2VnRJSsUnLagqD2O1cVTGW4lHEd/wBrFVaJ5W4ntiqW67PPCGNeMPAs0gYgrxqcVb8vX81z EeXIxgkRuxDFlrs23j1xVdqNzHE0y3b+hbrxcXKsQRUgUxVW0a6nuLYNKjRtT7DMGI+bLsfoxVin mjVNasNSVoixiL0UKxFa1IH4YqzLS55Z7VXkFGI3BxVF4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FVC6tYZ0pJ8wflirra3jjqQeRPUnFVK8sbeZlkY8JENUcbEH2OKqtrbxxKaH kXJZm8SdycVXyRIxqeuKr1UKKDFVk0cUi0kAI98VdDDFGv7sAD2xVbcRQSCkoBHviq+KONFAQUHb FVk1tBKQZFBI6VxVVRFQUXpireKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVK dauZkR0iYJKwAiZjQVJFdz3p0xVT06S5eZ423MaqHYgirUFSOnXFVLVZr+T/AEWymSC9aVArSECs dDy4VBqa028MVVtPmmuJ7rgvCJZSqBgQRQ0O3bpiqKuZJAwA2p1xVEQF2QE4qlutT3W0Ns6pOxWh Y0+HetPfFVfSZ3lMuxCKxAqKdNiae5xVCX819LfW8FnKkZSXleKx+MxKFNEWhLAivTFUXody1xbG XiUjYkxoeoUnYfdiq64lk9SnQAmoxVGwklBXFV+KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxVTnhhkQiQAr3riqlbG0QlYnUnuKgnFW7u2tZUrOBQb1O2KtWb2YBWCRW7mhBOKqzp Gd2xVchSlFO2KrJreKYUcVxV0MCRLxXp/XFVk9lBMQzj4huGGxBHviqpDCkKBEFFGwGKttEjdRiq 4CmKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KqF6WEBZa1BUmm+wIrirHob 64udQjSJZQEcly0bKKdOpGKp5ez/AFcQzMGMaMTIFUsacGHQe+KpRDq36T1eB7NJlt4kZZfVieP4 idqcwK4qnV76np/BWvtiqjpvr0JkBG/fFUfirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdirsVdirsVdirsVcQDscVWiKMGoUA4q2yqwoRUYqtSGJPsqB8sVXkA4q4ADpirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqhfX9l p9nNe308dtaW6l57iVgiIo6lmNAMVYn/AMrl/LL/AKvsJ9wk3/NGKu/5XL+Wf/V9i/5Fzf8ANGKu /wCVy/ln/wBX2L/kXN/zRirv+Vy/ln/1fYv+Rc3/ADRirv8Alcv5Z/8AV9i/5Fzf80Yq7/lcv5Z/ 9X2L/kXN/wA0Yq7/AJXL+Wf/AFfYv+Rc3/NGKu/5XL+Wf/V9i/5Fzf8ANGKu/wCVy/ln/wBX2L/k XN/zRirv+Vy/ln/1fYv+Rc3/ADRirv8Alcv5Z/8AV9i/5Fzf80Yq7/lcv5Z/9X2L/kXN/wA0Yq7/ AJXL+Wf/AFfYv+Rc3/NGKu/5XL+Wf/V9i/5Fzf8ANGKu/wCVy/ln/wBX2L/kXN/zRirv+Vy/ln/1 fYv+Rc3/ADRirv8Alcv5Z/8AV9i/5Fzf80Yq7/lcv5Z/9X2L/kXN/wA0Yq7/AJXL+Wf/AFfYv+Rc 3/NGKu/5XL+Wf/V9i/5Fzf8ANGKu/wCVy/ln/wBX2L/kXN/zRirv+Vy/ln/1fYv+Rc3/ADRirv8A lcv5Z/8AV9i/5Fzf80Yq7/lcv5Z/9X2L/kXN/wA0Yq7/AJXL+Wf/AFfYv+Rc3/NGKu/5XL+Wf/V9 i/5Fzf8ANGKu/wCVy/ln/wBX2L/kXN/zRirv+Vy/ln/1fYv+Rc3/ADRirv8Alcv5Z/8AV9i/5Fzf 80Yq7/lcv5Z/9X2L/kXN/wA0YqyLQfMWh+YLH6/o15HfWgdomliNeLrTkjA0KsKjYjFWNfnQqt+W 2qqwDKXswykVBBvYdiMVfOjOSxJPU4q1U+OKuqfHFXVPjirqnxxV1T44q6p8cVdU+OKuqfHFXVPj irqnxxV1T44q6p8cVdU+OKuqfHFXVPjirqnxxV1T44q6p8cVdU+OKuqfHFXVPjirqnxxV1T44q6p 8cVdU+OKuqfHFXVPjirqnxxV3I+OKvX/APnHY7eZR2M1qxH+UYmBPzNBirK/zrYr+WmrEdns/wDq NhxV8xm9ep3xVr66/jirvrr+OKu+uv44q766/jirvrr+OKu+uv44q766/jirvrr+OKu+uv44q766 /jirvrr+OKu+uv44q766/jirvrr+OKu+uv44q766/jirvrr+OKu+uv44q766/jirvrr+OKu+uv44 q766/jirvrr+OKu+uv44q766/jirvrr+OKu+uv44q766/jirvrr+OKva/wDnGyQyReZGJr+9tP8A k2+Ksw/PA0/LDWD/AJVn/wBRsOKvk1rn4jv3xVr6z74q76z74q76z74q76z74q76z74q76z74q76 z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q 76z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q76z74q99/5xgflaeYz4y2v /Jt8Veq+dfK8Xmnyvf6DLcNaC9RQlyihjG8brLG3E0DAOgqK7juMVePH/nFqYmp8ywVPX/cdL/2W 4q1/0KzL/wBTLD/3Dpf+y3FXf9Csy/8AUyw/9w6X/stxV3/QrMv/AFMsP/cOl/7LcVd/0KzL/wBT LD/3Dpf+y3FXf9Csy/8AUyw/9w6X/stxV3/QrMv/AFMsP/cOl/7LcVd/0KzL/wBTLD/3Dpf+y3FX f9Csy/8AUyw/9w6X/stxV3/QrMv/AFMsP/cOl/7LcVd/0KzL/wBTLD/3Dpf+y3FXf9Csy/8AUyw/ 9w6X/stxV3/QrMv/AFMsP/cOl/7LcVd/0KzL/wBTLD/3Dpf+y3FXf9Csy/8AUyw/9w6X/stxV3/Q rMv/AFMsP/cOl/7LcVd/0KzL/wBTLD/3Dpf+y3FXf9Csy/8AUyw/9w6X/stxV3/QrMv/AFMsP/cO l/7LcVd/0KzL/wBTLD/3Dpf+y3FXf9Csy/8AUyw/9w6X/stxV3/QrMv/AFMsP/cOl/7LcVd/0KzL /wBTLD/3Dpf+y3FXf9Csy/8AUyw/9w6X/stxV3/QrMv/AFMsP/cOl/7LcVd/0KzL/wBTLD/3Dpf+ y3FXf9Csy/8AUyw/9w6X/stxV3/QrMv/AFMsP/cOl/7LcVd/0KzL/wBTLD/3Dpf+y3FXf9Csy/8A Uywf9w6X/stxV6R+V35Zw+RNPvoPr36Qub+ZZZZxF6CKiLxjjWMvMfhqTUtvXFWa4q7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX/9k= - - - - - - proof:pdf - uuid:65E6390686CF11DBA6E2D887CEACB407 - xmp.did:F77F1174072068118B5A85C7332E927D - uuid:6d60af24-6a3a-4340-b0b7-3b073017f5d9 - - - - converted - from application/pdf to <unknown> - - - saved - xmp.iid:D47F11740720681191099C3B601C4548 - 2008-04-17T14:19:21+05:30 - Adobe Illustrator CS4 - - - / - - - - - converted - from application/pdf to <unknown> - - - converted - from application/pdf to <unknown> - - - saved - xmp.iid:FD7F11740720681197C1BF14D1759E83 - 2008-05-16T17:01:20-07:00 - Adobe Illustrator CS4 - - - / - - - - - saved - xmp.iid:F77F117407206811BC18AC99CBA78E83 - 2008-05-19T18:10:15-07:00 - Adobe Illustrator CS4 - - - / - - - - - converted - from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator - - - saved - xmp.iid:FB7F117407206811B628E3BF27C8C41B - 2008-05-22T14:26:44-07:00 - Adobe Illustrator CS4 - - - / - - - - - converted - from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator - - - saved - xmp.iid:08C3BD25102DDD1181B594070CEB88D9 - 2008-05-28T16:51:46-07:00 - Adobe Illustrator CS4 - - - / - - - - - converted - from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator - - - saved - xmp.iid:F77F11740720681192B0DFFC927805D7 - 2008-05-30T21:26:38-07:00 - Adobe Illustrator CS4 - - - / - - - - - converted - from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator - - - saved - xmp.iid:F87F11740720681192B0DFFC927805D7 - 2008-05-30T21:27-07:00 - Adobe Illustrator CS4 - - - / - - - - - converted - from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator - - - saved - xmp.iid:F97F1174072068119098B097FDA39BEF - 2008-06-02T13:26:10-07:00 - Adobe Illustrator CS4 - - - / - - - - - saved - xmp.iid:FFE440664A3DDD11BD33D3EB8D3A1068 - 2008-06-18T22:23:18+07:00 - Adobe Illustrator CS4 - - - / - - - - - saved - xmp.iid:686AE2A5723EDD11A6F1BABF7C5A7A51 - 2008-06-19T20:14:43-07:00 - Adobe Illustrator CS4 - - - / - - - - - saved - xmp.iid:696AE2A5723EDD11A6F1BABF7C5A7A51 - 2008-06-19T20:29:57-07:00 - Adobe Illustrator CS4 - - - / - - - - - saved - xmp.iid:0B9FED37200A11689FE8CB9EA85C5459 - 2008-06-26T06:08:02-07:00 - Adobe Illustrator CS4 - - - / - - - - - saved - xmp.iid:8FA7BEF06548DD1194DA8463B7D22218 - 2008-07-02T11:53:26-07:00 - Adobe Illustrator CS4 - - - / - - - - - saved - xmp.iid:F97F11740720681195FE859499B3C652 - 2009-12-15T12:14:23+01:00 - Adobe Illustrator CS4 - / - - - saved - xmp.iid:018011740720681195FE905C00262D22 - 2009-12-15T14:50:08+01:00 - Adobe Illustrator CS4 - / - - - saved - xmp.iid:028011740720681195FE905C00262D22 - 2009-12-15T17:10:20+01:00 - Adobe Illustrator CS4 - / - - - saved - xmp.iid:038011740720681195FE905C00262D22 - 2009-12-16T09:39:39+01:00 - Adobe Illustrator CS4 - / - - - saved - xmp.iid:058011740720681195FE905C00262D22 - 2009-12-17T18:50:07+01:00 - Adobe Illustrator CS4 - / - - - saved - xmp.iid:0180117407206811BA56BB3BB2EFF410 - 2009-12-23T14:22:42+01:00 - Adobe Illustrator CS4 - / - - - saved - xmp.iid:0180117407206811AB08C0AC8863DAA8 - 2009-12-28T16:45:24+01:00 - Adobe Illustrator CS4 - / - - - saved - xmp.iid:01801174072068118599A7B9548EC1D9 - 2010-03-01T10:47:31+01:00 - Adobe Illustrator CS4 - / - - - saved - xmp.iid:F77F1174072068118B5A85C7332E927D - 2010-03-21T15:29:17+01:00 - Adobe Illustrator CS4 - / - - - - - uuid:81fc375b-cebd-6e44-81ca-b8b7246549b5 - xmp.did:01801174072068118599A7B9548EC1D9 - uuid:65E6390686CF11DBA6E2D887CEACB407 - proof:pdf - - - - - EmbedByReference - - /private/var/folders/B+/B+gAiq46EDSxYiB0x-5Qik+++TI/-Tmp-/QrvuEy.tif - - - - - - - Web - Document - - - 1 - True - False - - 320.000000 - 240.000000 - Pixels - - - - - MyriadPro-BoldIt - Myriad Pro - Bold Italic - Open Type - Version 2.037;PS 2.000;hotconv 1.0.51;makeotf.lib2.0.18671 - False - MyriadPro-BoldIt.otf - - - - - - Cyan - Magenta - Yellow - Black - - - - - - Default Swatch Group - 0 - - - - White - RGB - PROCESS - 255 - 255 - 255 - - - Black - RGB - PROCESS - 0 - 0 - 0 - - - RGB Red - RGB - PROCESS - 255 - 0 - 0 - - - RGB Yellow - RGB - PROCESS - 255 - 255 - 0 - - - RGB Green - RGB - PROCESS - 0 - 255 - 0 - - - RGB Cyan - RGB - PROCESS - 0 - 255 - 255 - - - RGB Blue - RGB - PROCESS - 0 - 0 - 255 - - - RGB Magenta - RGB - PROCESS - 255 - 0 - 255 - - - R=193 G=39 B=45 - RGB - PROCESS - 193 - 39 - 45 - - - R=237 G=28 B=36 - RGB - PROCESS - 237 - 28 - 36 - - - R=241 G=90 B=36 - RGB - PROCESS - 241 - 90 - 36 - - - R=247 G=147 B=30 - RGB - PROCESS - 247 - 147 - 30 - - - R=251 G=176 B=59 - RGB - PROCESS - 251 - 176 - 59 - - - R=252 G=238 B=33 - RGB - PROCESS - 252 - 238 - 33 - - - R=217 G=224 B=33 - RGB - PROCESS - 217 - 224 - 33 - - - R=140 G=198 B=63 - RGB - PROCESS - 140 - 198 - 63 - - - R=57 G=181 B=74 - RGB - PROCESS - 57 - 181 - 74 - - - R=0 G=146 B=69 - RGB - PROCESS - 0 - 146 - 69 - - - R=0 G=104 B=55 - RGB - PROCESS - 0 - 104 - 55 - - - R=34 G=181 B=115 - RGB - PROCESS - 34 - 181 - 115 - - - R=0 G=169 B=157 - RGB - PROCESS - 0 - 169 - 157 - - - R=41 G=171 B=226 - RGB - PROCESS - 41 - 171 - 226 - - - R=0 G=113 B=188 - RGB - PROCESS - 0 - 113 - 188 - - - R=46 G=49 B=146 - RGB - PROCESS - 46 - 49 - 146 - - - R=27 G=20 B=100 - RGB - PROCESS - 27 - 20 - 100 - - - R=102 G=45 B=145 - RGB - PROCESS - 102 - 45 - 145 - - - R=147 G=39 B=143 - RGB - PROCESS - 147 - 39 - 143 - - - R=158 G=0 B=93 - RGB - PROCESS - 158 - 0 - 93 - - - R=212 G=20 B=90 - RGB - PROCESS - 212 - 20 - 90 - - - R=237 G=30 B=121 - RGB - PROCESS - 237 - 30 - 121 - - - R=199 G=178 B=153 - RGB - PROCESS - 199 - 178 - 153 - - - R=153 G=134 B=117 - RGB - PROCESS - 153 - 134 - 117 - - - R=115 G=99 B=87 - RGB - PROCESS - 115 - 99 - 87 - - - R=83 G=71 B=65 - RGB - PROCESS - 83 - 71 - 65 - - - R=198 G=156 B=109 - RGB - PROCESS - 198 - 156 - 109 - - - R=166 G=124 B=82 - RGB - PROCESS - 166 - 124 - 82 - - - R=140 G=98 B=57 - RGB - PROCESS - 140 - 98 - 57 - - - R=117 G=76 B=36 - RGB - PROCESS - 117 - 76 - 36 - - - R=96 G=56 B=19 - RGB - PROCESS - 96 - 56 - 19 - - - R=66 G=33 B=11 - RGB - PROCESS - 66 - 33 - 11 - - - PANTONE 485 C - SPOT - 100.000000 - CMYK - 0.000000 - 94.999702 - 100.000000 - 0.000000 - - - - - - Grays - 1 - - - - R=0 G=0 B=0 - RGB - PROCESS - 0 - 0 - 0 - - - R=26 G=26 B=26 - RGB - PROCESS - 26 - 26 - 26 - - - R=51 G=51 B=51 - RGB - PROCESS - 51 - 51 - 51 - - - R=77 G=77 B=77 - RGB - PROCESS - 77 - 77 - 77 - - - R=102 G=102 B=102 - RGB - PROCESS - 102 - 102 - 102 - - - R=128 G=128 B=128 - RGB - PROCESS - 128 - 128 - 128 - - - R=153 G=153 B=153 - RGB - PROCESS - 153 - 153 - 153 - - - R=179 G=179 B=179 - RGB - PROCESS - 179 - 179 - 179 - - - R=204 G=204 B=204 - RGB - PROCESS - 204 - 204 - 204 - - - R=230 G=230 B=230 - RGB - PROCESS - 230 - 230 - 230 - - - R=242 G=242 B=242 - RGB - PROCESS - 242 - 242 - 242 - - - - - - Web Color Group - 1 - - - - R=63 G=169 B=245 - RGB - PROCESS - 63 - 169 - 245 - - - R=122 G=201 B=67 - RGB - PROCESS - 122 - 201 - 67 - - - R=255 G=147 B=30 - RGB - PROCESS - 255 - 147 - 30 - - - R=255 G=29 B=37 - RGB - PROCESS - 255 - 29 - 37 - - - R=255 G=123 B=172 - RGB - PROCESS - 255 - 123 - 172 - - - R=189 G=204 B=212 - RGB - PROCESS - 189 - 204 - 212 - - - - - - - - - Adobe PDF library 9.00 - - - - - - - - - - - - - - - - - - - - - - - - - endstream endobj 3 0 obj <> endobj 1470 0 obj <>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/Properties<>/XObject<>>>/Thumb 1617 0 R/TrimBox[0.0 0.0 320.0 240.0]/Type/Page>> endobj 1471 0 obj <>stream -H‰œW;o$7 îçW¨LŠÝÕûÑzíR8‡…Hy…‘KÜ^pq‘¿RÒHy¨™5 Ø&õ‰”>>Ä9}>³Ó󙳇Ç3›žžá×)©DRý˜8“š3%9;à?ÿþ1ýξƒþôé…³?ߦÓ/7Îÿ™.‹í2m¿Œ ˆl@¼7 ¶ Æáç X8&‡ß¯74'“¹!ý&D»MHô#ĦŸ!$ùB¬Ý„x³ \obðF"È­!ñFcHôãÔ¦Ÿ!$ùB¢£7ý !ÉÏý(³égI~†èGØM?CHò3„ Ÿà¶Ü ÑËÓzœ'1­Ç”ÖcLò4Ì”äiÉž†˜äi˜+ÉÓ’= 1ÉÓ0[’§!${b’§a¾$OCHö´Š9í4Wª ˜œsaA÷hÃ*kýKw uè«’Óyv”@@0Ū4åÄë-¹ß é§¤‡:q§íæ0ë…´z˜}Ðæ0ĆU×ùîl}ßEa\ØK¢n˶†fÎïY’*R“vD=û5[Û©Fï‹d‹Ôìt*ëôŠÎ¬èìŠÎ­èüŠ.¬èDò.Óé ƒßëñ‡½½~GœFœÔ8A±z¸Ï×IâD%˜+²Y2} ¡bèSEö ëh;É`0a!Û*ÓLÂxŠ'3ó Ä|­~AR ŠZÐÔ‚¡,µàº…B¸§± 9µÐß¼,È9¨Žq -5*Ü3Œ]‰ -GÎM–T Y¡f’"•ƒ‘«ºÝёגâZR\KŠkIq-)®%ŵ¢¸V¢¡Tx_)…•(GrB¡l;-äÝô)*‡Å«¢xU¯ŠâUõ¼–…ž×²Ðó:/èž×²@U¯¦n®©›kêæº¿yiºýÍË•QšÊ(Me”¡2ÊPÕkú›—Ur_VÙ”­Ë²-e- –¬oÖEÓ|q72ä4>ìL7²¬ë†ÂØÚÌw篡bb¨l4T6* •†ÊFKe£­U®qäi¶Y¶•Qdžm–ëóÃC#ã@‰ŒêÚD£®‰ŠÂ1ì0Y;‹3p‚¦ñFŒª˜ÍH”ÁÊ*Û×SYècW¨z²T=Yªž,UO–ª'GÕ“£:‰£:‰£:‰£²Ö™9?®Óé*¾`į_'5p|„?2~ŰëmúéòóõïééC¦°ùË&ŒsÚVe>VGQî(ÊE¹£ÊÅSåâÅ:`ÜZÐUCÐþ^RFZ*ƒ=G¯çóÓ ÙÁÍsÏ~§TŸòTŸòTŸòTŸòñ">P¹ÊäY3;4¬8•Ç[;‘u¦Ñ©Ï:]uPY—1ú=Æ™%f7ËêAêAêA*ˆ@D  -"ôq±å£‰ -Œàä×/¡|…OÞ%uÜY—e‘e•ežåÜ  X“œ«²Nx[ß+œ6QWì…^o*n“;bê²oÀ;Èߦ¿~™NçÎÎ/qgìåüÛ¤Ù3»ÇÏæ^ÀÜÓó™M§Ïgvz>öðÒ üXò©^l¨\ÁÍ<Þ ÊÍ`e0¸;ýz+a+2$+vËB& ¢ZÀÚÞc ãÒ~Y÷‡53´ÄŒ8Sj˜»r™‡ÃK„Æ”€¶Í ¢•pn`k Zô´Å,&ÃÈ$Vx1YÛýŠMD›¢TŒ€O!á"Äñ•˜Éb ³&jγËÄ Ì&T“zøÖî:Efú}î8SÝA]I?cs¬Û²s: gŸ€r,ÙEÿhÍ]¦ÿäÃOæ endstream endobj 1472 0 obj <> endobj 1617 0 obj <>stream -8;Z\sd0[T2$q,$+m,L:tPC9`3K2IkbnNQ;HT,>rsY:=3DOTbOam8]j7 endstream endobj 1619 0 obj [/Indexed/DeviceRGB 255 1620 0 R] endobj 1620 0 obj <>stream -8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 -b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` -E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn -6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( -l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 1485 0 obj <>/ExtGState<>/Shading<>/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr /Fm0 Do -Q -q -315 8 m -315 6.344 313.657 5 312 5 c -8 5 l -6.343 5 5 6.344 5 8 c -5 39 l -5 40.656 6.343 42 8 42 c -312 42 l -313.657 42 315 40.656 315 39 c -h -W n -q -0 g -/GS1 gs -0 -37 -37 0 159.9995117 42 cm -BX /Sh0 sh EX Q -Q -q -/GS2 gs -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr /Fm1 Do -Q -/CS1 cs 0 0 0 scn -/GS1 gs -q 1 0 0 1 312 42 cm -0 0 m --304 0 l --305.657 0 -307 -1.344 -307 -3 c --307 -34 l --307 -35.656 -305.657 -37 -304 -37 c -0 -37 l -1.657 -37 3 -35.656 3 -34 c -3 -3 l -3 -1.344 1.657 0 0 0 c -0 -1 m -1.103 -1 2 -1.897 2 -3 c -2 -34 l -2 -35.103 1.103 -36 0 -36 c --304 -36 l --305.103 -36 -306 -35.103 -306 -34 c --306 -3 l --306 -1.897 -305.103 -1 -304 -1 c -0 -1 l -f -Q -q -0 g -/GS3 gs -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr /Fm2 Do -Q - endstream endobj 1486 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 0.4 0.4 0.4 scn -/CS0 CS 0 0 0 SCN -3 w 4 M 0 j 1 J []0 d -/GS0 gs -q 1 0 0 1 103 233 cm -0 0 m -210 0 l -B -Q - endstream endobj 1487 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -52 226 -9 1 re -f - endstream endobj 1488 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -85 237 -1 1 re -f - endstream endobj 1489 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -64 199 1 -5 re -f -63 198 1 -4 re -f -62 197 1 -3 re -f -61 196 1 -2 re -f -60 195 1 -1 re -f - endstream endobj 1490 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -69 186 -1 5 re -f -70 187 -1 4 re -f -71 188 -1 3 re -f -72 189 -1 2 re -f -73 190 -1 1 re -f - endstream endobj 1491 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -102 199 1 -5 re -f -101 198 1 -4 re -f -100 197 1 -3 re -f -99 196 1 -2 re -f -98 195 1 -1 re -f - endstream endobj 1492 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -107 186 -1 5 re -f -108 187 -1 4 re -f -109 188 -1 3 re -f -110 189 -1 2 re -f -111 190 -1 1 re -f - endstream endobj 1493 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -62 212 -1 5 re -f -63 213 -1 4 re -f -64 214 -1 3 re -f -65 215 -1 2 re -f -66 216 -1 1 re -f - endstream endobj 1494 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -71 211 1 -5 re -f -70 210 1 -4 re -f -69 209 1 -3 re -f -68 208 1 -2 re -f -67 207 1 -1 re -f - endstream endobj 1495 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -100 212 -1 5 re -f -101 213 -1 4 re -f -102 214 -1 3 re -f -103 215 -1 2 re -f -104 216 -1 1 re -f - endstream endobj 1496 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -109 211 1 -5 re -f -108 210 1 -4 re -f -107 209 1 -3 re -f -106 208 1 -2 re -f -105 207 1 -1 re -f - endstream endobj 1497 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -69 152 -1 1 re -f -70 151 -1 1 re -f -71 150 -1 1 re -f -68 153 -1 1 re -f -67 153 -1 3 re -f -68 154 -1 2 re -f -69 155 -1 1 re -f -70 156 -4 1 re -f -64 155 -1 5 re -f -65 151 -1 8 re -f -66 152 -1 6 re -f -63 156 -1 3 re -f -62 157 -1 1 re -f -72 149 -1 1 re -f - endstream endobj 1498 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -14 230 -9 1 re -f - endstream endobj 1499 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -107 152 -1 1 re -f -108 151 -1 1 re -f -109 150 -1 1 re -f -106 153 -1 1 re -f -105 153 -1 3 re -f -106 154 -1 2 re -f -107 155 -1 1 re -f -108 156 -4 1 re -f -102 155 -1 5 re -f -103 151 -1 8 re -f -104 152 -1 6 re -f -101 156 -1 3 re -f -100 157 -1 1 re -f -110 149 -1 1 re -f - endstream endobj 1500 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -70 133 -1 1 re -f -71 132 -1 1 re -f -69 134 -1 1 re -f -68 134 -1 3 re -f -69 135 -1 2 re -f -70 136 -1 1 re -f -71 137 -4 1 re -f -65 136 -1 5 re -f -66 132 -1 8 re -f -67 133 -1 6 re -f -64 137 -1 3 re -f -63 138 -1 1 re -f - endstream endobj 1501 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -108 133 -1 1 re -f -109 132 -1 1 re -f -107 134 -1 1 re -f -106 134 -1 3 re -f -107 135 -1 2 re -f -108 136 -1 1 re -f -109 137 -4 1 re -f -103 136 -1 5 re -f -104 132 -1 8 re -f -105 133 -1 6 re -f -102 137 -1 3 re -f -101 138 -1 1 re -f - endstream endobj 1502 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream -BT -/CS0 cs 1 1 1 scn -/GS0 gs -/T1_0 1 Tf -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 12 0 0 12 62 113 Tm -(Q)Tj -ET - endstream endobj 1503 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream -BT -/CS0 cs 1 1 1 scn -/GS0 gs -/T1_0 1 Tf -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 12 0 0 12 100 113 Tm -(Q)Tj -ET - endstream endobj 1504 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -180 206 -17 11 re -f - endstream endobj 1505 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -134 206 -17 11 re -f - endstream endobj 1506 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -180 187 -17 11 re -f - endstream endobj 1507 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -134 187 -17 11 re -f - endstream endobj 1508 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -148 168 -31 11 re -f - endstream endobj 1509 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -13 231 -7 1 re -f - endstream endobj 1510 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -148 149 -31 11 re -f - endstream endobj 1511 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -222 168 -31 11 re -f - endstream endobj 1512 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -222 149 -31 11 re -f - endstream endobj 1513 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -249 206 -17 11 re -f - endstream endobj 1514 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -203 206 -17 11 re -f - endstream endobj 1515 0 obj <>/Subtype/Form>>stream - endstream endobj 1516 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -12 232 -5 1 re -f - endstream endobj 1517 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -11 233 -3 1 re -f - endstream endobj 1518 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -10 234 -1 1 re -f - endstream endobj 1519 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -14 227 -9 1 re -f - endstream endobj 1520 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -14 226 -9 1 re -f - endstream endobj 1521 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -46 207 -1 9 re -f - endstream endobj 1522 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -47 208 -1 7 re -f - endstream endobj 1523 0 obj <>/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr /Fm0 Do -Q - endstream endobj 1524 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -48 209 -1 5 re -f - endstream endobj 1525 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -49 210 -1 3 re -f - endstream endobj 1526 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -50 211 -1 1 re -f - endstream endobj 1527 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -8 207 -1 9 re -f - endstream endobj 1528 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -9 208 -1 7 re -f - endstream endobj 1529 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -10 209 -1 5 re -f - endstream endobj 1530 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -11 210 -1 3 re -f - endstream endobj 1531 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -12 211 -1 1 re -f - endstream endobj 1532 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -45 188 -1 9 re -f - endstream endobj 1533 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -50 188 -1 9 re -f - endstream endobj 1534 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -259 0 0 156 -3 87 cm -/Im0 Do -Q - endstream endobj 1535 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -49 188 -1 9 re -f - endstream endobj 1536 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -44 188 -1 9 re -f - endstream endobj 1537 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -8 188 -1 9 re -f - endstream endobj 1538 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -13 188 -1 9 re -f - endstream endobj 1539 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -12 188 -1 9 re -f - endstream endobj 1540 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -7 188 -1 9 re -f - endstream endobj 1541 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -6 171 -1 5 re -f - endstream endobj 1542 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -8 171 -1 6 re -f - endstream endobj 1543 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -9 170 -1 8 re -f - endstream endobj 1544 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -8 170 -1 1 re -f - endstream endobj 1545 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -52 230 -9 1 re -f - endstream endobj 1546 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -9 169 -1 1 re -f - endstream endobj 1547 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -7 172 -1 4 re -f - endstream endobj 1548 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -7 171 -1 1 re -f - endstream endobj 1549 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -15 176 -1 2 re -f - endstream endobj 1550 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -17 175 -5 1 re -f - endstream endobj 1551 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -15 173 -1 2 re -f - endstream endobj 1552 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -45 152 -1 5 re -f - endstream endobj 1553 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -47 152 -1 6 re -f - endstream endobj 1554 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -48 151 -1 8 re -f - endstream endobj 1555 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -47 151 -1 1 re -f - endstream endobj 1556 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -51 231 -7 1 re -f - endstream endobj 1557 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -48 150 -1 1 re -f - endstream endobj 1558 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -46 153 -1 4 re -f - endstream endobj 1559 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -46 152 -1 1 re -f - endstream endobj 1560 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -54 156 -3 1 re -f - endstream endobj 1561 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -7 152 -1 5 re -f - endstream endobj 1562 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -9 152 -1 6 re -f - endstream endobj 1563 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -10 151 -1 8 re -f - endstream endobj 1564 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -9 151 -1 1 re -f - endstream endobj 1565 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -10 150 -1 1 re -f - endstream endobj 1566 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -8 153 -1 4 re -f - endstream endobj 1567 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -50 232 -5 1 re -f - endstream endobj 1568 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -8 152 -1 1 re -f - endstream endobj 1569 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -16 156 -3 1 re -f - endstream endobj 1570 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -44 171 -1 5 re -f - endstream endobj 1571 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -46 171 -1 6 re -f - endstream endobj 1572 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -47 170 -1 8 re -f - endstream endobj 1573 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -46 170 -1 1 re -f - endstream endobj 1574 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -47 169 -1 1 re -f - endstream endobj 1575 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -45 172 -1 4 re -f - endstream endobj 1576 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -45 171 -1 1 re -f - endstream endobj 1577 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -53 176 -1 2 re -f - endstream endobj 1578 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -49 233 -3 1 re -f - endstream endobj 1579 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -55 175 -5 1 re -f - endstream endobj 1580 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -53 173 -1 2 re -f - endstream endobj 1581 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream -BT -/CS0 cs 1 1 1 scn -/GS0 gs -/T1_0 1 Tf -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 12 0 0 12 2 132 Tm -(Q)Tj -ET - endstream endobj 1582 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -15 138 -1 2 re -f - endstream endobj 1583 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -17 137 -5 1 re -f - endstream endobj 1584 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -15 135 -1 2 re -f - endstream endobj 1585 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream -BT -/CS0 cs 1 1 1 scn -/GS0 gs -/T1_0 1 Tf -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 12 0 0 12 40 132 Tm -(Q)Tj -ET - endstream endobj 1586 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -53 138 -1 2 re -f - endstream endobj 1587 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -55 137 -5 1 re -f - endstream endobj 1588 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -53 135 -1 2 re -f - endstream endobj 1589 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -48 234 -1 1 re -f - endstream endobj 1590 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream -BT -/CS0 cs 1 1 1 scn -/GS0 gs -/T1_0 1 Tf -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 12 0 0 12 2 113 Tm -(Q)Tj -ET - endstream endobj 1591 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -16 118 -3 1 re -f - endstream endobj 1592 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream -BT -/CS0 cs 1 1 1 scn -/GS0 gs -/T1_0 1 Tf -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 12 0 0 12 40 113 Tm -(Q)Tj -ET - endstream endobj 1593 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -54 118 -3 1 re -f - endstream endobj 1594 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -13 94 -7 7 re -f - endstream endobj 1595 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -51 94 -7 7 re -f - endstream endobj 1596 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -61 230 -1 7 re -f - endstream endobj 1597 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -60 230 -1 6 re -f - endstream endobj 1598 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -62 230 -1 6 re -f - endstream endobj 1599 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -59 230 -1 5 re -f - endstream endobj 1600 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -52 227 -9 1 re -f - endstream endobj 1601 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -58 230 -1 4 re -f - endstream endobj 1602 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -63 230 -1 5 re -f - endstream endobj 1603 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -64 230 -1 4 re -f - endstream endobj 1604 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -85 230 -1 7 re -f - endstream endobj 1605 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -84 230 -1 6 re -f - endstream endobj 1606 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -86 230 -1 6 re -f - endstream endobj 1607 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -83 230 -1 5 re -f - endstream endobj 1608 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -82 230 -1 4 re -f - endstream endobj 1609 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -87 230 -1 5 re -f - endstream endobj 1610 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -88 230 -1 4 re -f - endstream endobj 1611 0 obj <>stream -H‰ìÐ1 - ÀöÿŸ–¢¸ºdp¸ƒf ¡U¼u÷DHµîëÑÖ\z·V~kþ¯¿X ŒÄ endstream endobj 1612 0 obj <>stream -H‰ìÑA -À ÀäÿŸ.Ö¢´´§ð0sP’ÕÈG‘_We¼Ô¿zg¿ufÛZ5ËUqMf.c_Ržqk_“q޽CFÙ;`O‡OA endstream endobj 1613 0 obj <>stream -H‰ìÑA -À0@÷ÿŸ.è¡´7(Ì€‚± -Îʯ"’néºÇɈ^öÑæ"ê¹8}ÔdÄû[~±òæç] ¿ç< endstream endobj 1614 0 obj <>stream -H‰ìÐÁ 0 ±zÿ¥ é -~" p89X$Ÿ“)ö¢Kså+6ÏîoìÿØç -0: endstream endobj 1615 0 obj <>stream -H‰ìÎ ±·iK -nŽKà‡’ÚH ºy·µa’ endstream endobj 1616 0 obj <>stream -H‰ìÐÁ €0 Àzÿ¥!pÕ>î’·ce €]rÏŠÔò¶}¶x`¦¦ÙûKM±ì¿kOæK›8Å%Àîr# endstream endobj 1475 0 obj [/Indexed 1474 0 R 1 1763 0 R] endobj 1762 0 obj <>/Filter/FlateDecode/Height 82/Intent/RelativeColorimetric/Length 69/Name/X/Subtype/Image/Type/XObject/Width 86>>stream -H‰ìÐÁ €0 Àî¿´!pÕ>î’·ce €]rÏŠÔò¶}¶x`¦¦ÙûKM±ì¿kOæK›8Å%À:ô!ß endstream endobj 1474 0 obj [/ICCBased 1764 0 R] endobj 1763 0 obj <>stream -ÿÿÿ endstream endobj 1764 0 obj <>stream -H‰œ–yTSwÇoÉž•°Ãc [€°5la‘QIBHØADED„ª•2ÖmtFOE.®c­Ö}êÒõ0êè8´׎8GNg¦Óïï÷9÷wïïÝß½÷ó '¥ªµÕ0 Ö ÏJŒÅb¤  - 2y­.-;!à’ÆK°ZÜ ü‹ž^i½"LÊÀ0ðÿ‰-×é @8(”µrœ;q®ª7èLöœy¥•&†Qëñq¶4±jž½ç|æ9ÚÄ -V³)gB£0ñiœWו8#©8wÕ©•õ8_Å٥ʨQãüÜ«QÊj@é&»A)/ÇÙgº>'K‚óÈtÕ;\ú” Ó¥$ÕºF½ZUnÀÜå˜(4TŒ%)ë«”ƒ0C&¯”阤Z£“i˜¿óœ8¦Úbx‘ƒE¡ÁÁBÑ;…ú¯›¿P¦ÞÎӓ̹žAü om?çW= -€x¯Íú·¶Ò-Œ¯Àòæ[›Ëû0ñ¾¾øÎ}ø¦y)7ta¾¾õõõ>j¥ÜÇTÐ7úŸ¿@ï¼ÏÇtÜ›ò`qÊ2™±Ê€™ê&¯®ª6ê±ZL®Ä„?â_øóyxg)Ë”z¥ÈçL­UáíÖ*ÔuµSkÿSeØO4?׸¸c¯¯Ø°.òò· åÒR´ ßÞô-•’2ð5ßáÞüÜÏ ú÷Sá>Ó£V­š‹“då`r£¾n~ÏôY &à+`œ;ÂA4ˆÉ 䀰ÈA9Ð=¨- t°lÃ`;»Á~pŒƒÁ ðGp| ®[`Lƒ‡`<¯ "A ˆ YA+äùCb(ЇR¡,¨*T2B-Ð -¨ꇆ¡Ðnè÷ÐQètº}MA ï —0Óal»Á¾°ŽSàx ¬‚kà&¸^Á£ð>ø0|>_ƒ'á‡ð,ÂG!"F$H:Rˆ”!z¤éF‘Qd?r 9‹\A&‘GÈ ”ˆrQ ¢áhš‹ÊÑ´íE‡Ñ]èaô4zBgÐ×Á–àE#H ‹*B=¡‹0HØIøˆp†p0MxJ$ùD1„˜D, V›‰½Ä­ÄÄãÄKÄ»ÄY‰dEò"EÒI2’ÔEÚBÚGúŒt™4MzN¦‘Èþär!YKî ’÷?%_&ß#¿¢°(®”0J:EAi¤ôQÆ(Ç()Ó”WT6U@ æP+¨íÔ!ê~êêmêæD ¥eÒÔ´å´!ÚïhŸÓ¦h/èº']B/¢éëèÒÓ¿¢?a0nŒhF!ÃÀXÇØÍ8ÅøšñÜŒkæc&5S˜µ™˜6»lö˜Iaº2c˜K™MÌAæ!æEæ#…寒°d¬VÖë(ëk–Íe‹Øél »—½‡}Ž}ŸCâ¸qâ9 -N'çÎ)Î].ÂuæJ¸rî -î÷ wšGä xR^¯‡÷[ÞoÆœchžgÞ`>bþ‰ù$á»ñ¥ü*~ÿ ÿ:ÿ¥…EŒ…ÒbÅ~‹ËÏ,m,£-•–Ý–,¯Y¾´Â¬â­*­6X[ݱF­=­3­ë­·YŸ±~dó ·‘ÛtÛ´¹i ÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî”Ý#{¾}´}…ý€ý§ö¸‘j‡‡ÏþŠ™c1X6„Æfm“Ž;'_9 œr:œ8Ýq¦:‹ËœœO:ϸ8¸¤¹´¸ìu¹éJq»–»nv=ëúÌMà–ï¶ÊmÜí¾ÀR 4 ö -n»3Ü£ÜkÜGݯz=Ä•[=¾ô„=ƒ<Ë=GTB(É/ÙSòƒ,]6*›-•–¾W:#—È7Ë*¢ŠÊe¿ò^YDYÙ}U„j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ+¬Ê¯: !kJ4Gµm¥ötµ}uCõ%—®K7YV³©fFŸ¢ßY Õ.©=bàá?SŒîƕƩºÈº‘ºçõyõ‡Ø Ú† žkï5%4ý¦m–7Ÿlqlio™Z³lG+ÔZÚz²Í¹­³mzyâò]íÔöÊö?uøuôw|¿"űN»ÎåwW&®ÜÛe֥ﺱ*|ÕöÕèjõê‰5k¶¬yÝ­èþ¢Ç¯g°ç‡^yïkEk‡Öþ¸®lÝD_pß¶õÄõÚõ×7DmØÕÏîoê¿»1mãál {àûMśΠnßLÝlÜ<9”úO¤[þ˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾ -¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ ÷„óû endstream endobj 1761 0 obj <>/Filter/FlateDecode/Height 82/Intent/RelativeColorimetric/Length 43/Name/X/Subtype/Image/Type/XObject/Width 75>>stream -H‰ìÎ ±ï_ZK -nŽKà‡’ÚH ºy·µ^Áû endstream endobj 1760 0 obj <>/Filter/FlateDecode/Height 82/Intent/RelativeColorimetric/Length 58/Name/X/Subtype/Image/Type/XObject/Width 82>>stream -H‰ìÐÁ 0 ±î¿´ é -~" p89X$Ÿ“)ö¢Kså+6ÏîoìÿØç -0ÇJë endstream endobj 1759 0 obj <>/Filter/FlateDecode/Height 82/Intent/RelativeColorimetric/Length 76/Name/X/Subtype/Image/Type/XObject/Width 99>>stream -H‰ìÑA -À0@ÿÿé-è¡´7(Ì€‚± -Îʯ"’néºÇɈ^öÑæ"ê¹8}ÔdÄû[~±òæç] ¹Ö:Æ endstream endobj 1758 0 obj <>/Filter/FlateDecode/Height 82/Intent/RelativeColorimetric/Length 89/Name/X/Subtype/Image/Type/XObject/Width 100>>stream -H‰ìÑA -À ÀüÿÓ)Ö¢´´§ð0sP’ÕÈG‘_We¼Ô¿zg¿ufÛZ5ËUqMf.c_Ržqk_“q޽CFÙ;`O‡h£?Á endstream endobj 1757 0 obj <>/Filter/FlateDecode/Height 82/Intent/RelativeColorimetric/Length 63/Name/X/Subtype/Image/Type/XObject/Width 86>>stream -H‰ìÐ1 - ÀþÿÓ•¢¸ºdp¸ƒf ¡U¼u÷DHµîëÑÖ\z·V~kþ¯¿X èäæ endstream endobj 1756 0 obj <> endobj 1480 0 obj <> endobj 1755 0 obj <> endobj 1754 0 obj <> endobj 1753 0 obj <> endobj 1752 0 obj <> endobj 1751 0 obj <> endobj 1750 0 obj <> endobj 1749 0 obj <> endobj 1748 0 obj <> endobj 1747 0 obj <> endobj 1746 0 obj <> endobj 1745 0 obj <> endobj 1744 0 obj <> endobj 1743 0 obj <> endobj 1742 0 obj <> endobj 1741 0 obj <> endobj 1740 0 obj <> endobj 1739 0 obj <> endobj 1738 0 obj <> endobj 1461 0 obj <> endobj 1765 0 obj <> endobj 1766 0 obj <>stream -H‰bd`ab`dd”ˆðqò‰Ðö­,ÊLL (Ê×uÊÏIñ,É)ýfü!ÂÒÀÃôC†Gôwìï>–“¿òY¿¿çÿþIðö3B L@Cþ1r;ç HÏ(Q0´´4Ò‘&`Ò\GÁÈÀÀLš(8¦ä'¥*W—¤æ+xæ%çä%–¤¦è)8æä(€(V(J-N-* T’š ”WHªTÕ ŠUçÕ¸˜˜šè˜Zé)@œ®Y¬šY’‘Z¤4 =hGP_IQbJjnbQ¶B>H‰›†Ç9 -™y -@³Bó2A¼à `±Bb^Š>Д|°-Éù¥y%E™©ÅzúnÁ!•© - -)©i @`ÄÀÄÈèwõGG÷Þoö2I•½ÌÝ,?:~üé`ûÞ÷û¨èo»ï“Y¿¿`û­ðû€èwçÏ$ö?lq`öw»ß@>Ûý¢ Öoïg¨zÙwɲEe?.|çÚý]÷û“ïºÂ{~ò´ˆM ž‘4£}㬵‹—-å¸|eËw¾ïlRßµŒ¾‹ÿöÒ6H÷ð³·MúÍõ›MJøÎo»OªßÅ›ä&Mé¨]-<ï}ÊóŽß?D¿®0µ·ÊùÍ&Ÿ›“Z/­áÕ͕ߙ’_µjÓ¼Ò| Ó~šÍþ;í»Ö´=ÓþäObû¡4ù·Æä?ùÓvNž;™$=ýwÜ´ïú é’I?¼&þö™”Þ1qÅDN¹ ®M3ÿóp~gâú®ÃÝÃÃ`ìƒ î endstream endobj 1737 0 obj <> endobj 1736 0 obj <> endobj 1735 0 obj <> endobj 1734 0 obj <> endobj 1733 0 obj <> endobj 1732 0 obj <> endobj 1731 0 obj <> endobj 1730 0 obj <> endobj 1729 0 obj <> endobj 1728 0 obj <> endobj 1727 0 obj <> endobj 1726 0 obj <> endobj 1725 0 obj <> endobj 1724 0 obj <> endobj 1723 0 obj <> endobj 1722 0 obj <> endobj 1721 0 obj <> endobj 1720 0 obj <> endobj 1719 0 obj <> endobj 1718 0 obj <> endobj 1717 0 obj <> endobj 1716 0 obj <> endobj 1715 0 obj <> endobj 1714 0 obj <> endobj 1713 0 obj <> endobj 1712 0 obj <> endobj 1711 0 obj <> endobj 1710 0 obj <> endobj 1709 0 obj <> endobj 1708 0 obj <> endobj 1707 0 obj <> endobj 1706 0 obj <> endobj 1705 0 obj <> endobj 1704 0 obj <> endobj 1703 0 obj <> endobj 1702 0 obj <> endobj 1701 0 obj <> endobj 1700 0 obj <> endobj 1699 0 obj <> endobj 1698 0 obj <> endobj 1697 0 obj <> endobj 1696 0 obj <> endobj 1695 0 obj <> endobj 1694 0 obj <> endobj 1693 0 obj <> endobj 1692 0 obj <> endobj 1691 0 obj <> endobj 1690 0 obj <> endobj 1689 0 obj <> endobj 1688 0 obj <> endobj 1687 0 obj <> endobj 1686 0 obj <> endobj 1685 0 obj <> endobj 1684 0 obj <> endobj 1683 0 obj <> endobj 1682 0 obj <> endobj 1681 0 obj <> endobj 1678 0 obj <> endobj 1680 0 obj <>stream -H‰ì—ÑVí DÛÿÿé»ÔëÑ– =Ì<éifC-G*5¦óCðóŸÑù­ÛÏë‾Õ(§ Žu}c”—!¸ÐXIÐ7E¥Þ…ôMQl¹—DS–fë0€Æ)KD° c–.‰`/šΦ$E0;šUIÀÁ«àì\ 2&“²^ŠÌMÒ/y![xmØFÕ¸puú=ªÙ,.gíR&‰Ö/SøÝjMj’B¹±5.B„ríÖTQÝú2y-¬²ôJ]qm®¥ÙréÝKm;úNŠ™¬Á¦}Õ¶£«ÅLVw·Ï¨eGß©<ÚØû”°¥o^"Hû¼ ‰` Á F¾›0D°ƒ‘Ó!Í=­‡Ä8‚²…7§¾›BAÍ:Jg¬/ó(œ[ŪGe -wh‚’+Œ„(ŠU#`³¦ˆÚ£HáJ(úÑjk^’Ôe-«Ûb28“UËf•!˜YP¼nu¾‰Àõvõ U”A"8ÁÁ|tóLgÁlL†à‡ ÷tˆ“m–#î›"L¶Y>rE=ÓãøñÐUÅòÒc ”hµ¹6+*VËB}Ä­YSyhy¿]((XÝyûTƬø„•ÄÒMrÏX<Ø«©Åh½ÖN@ùT÷´­÷ÑÚë#®½­÷ÑÚk `w¼¥‰`Án©‹@DÝ=õ˜‚@òÛzR¿««# p4–'¯€@w}–Äb€M)Ö9D :éÖ—9àý ´ç•}A«–8Ösi9¥úÇ{›´ZU×AË7bMfàâÈ˯PÌbufé•ö@ðòqìõwb±êM;«öiX>,á ö †÷<*öÓá~2â¿ÂM%¼ìˆ@ý07»Áç•‚ Ÿ|“ª,£"ðRû§`‚UÔTÕÃÄw(äÑ€îwXBs^°Xï•…¬/Y?¦°¬·Å7Ë„€Â‘õeJôNü/I¤Þ*#FÛ*ÀÓj–k¾úˆÿ_[èù׸ažDŒñìjO+ŸýجÊCm¹è^’Îÿ…~»©—B±£g.äHÀz0šù.WFÍÎ|Õ ‰ ‚)Áæü$x†ŠhEÒkÞ]ðt³I#6¹%@: -,…ßfE’uÕ„`Û¬PÒã¦çÙ­V(A8ÎË!J/rXAʪ„¹P­Ø-¾M{ªòî¦0W±T$ ÿÑ€”/(„bþš•@ê%pÂÊÞìÀ¥ –Ù‰ïr%€T¢ßžG;cv櫞'šúªD|?‰Öa³3ßÕ À:wÛ/‚0ÏÑÀ>ÅÀcdn Õ[†Mï07’ª=Ã’{Ì %½eÈë47”ʹg -127”ʦÖ­{ÅQêÞ-¹Ìhña•ïïy–SÙC—”]tÞ…VøΈAÿÆ7 DÁ‘ŽDp$‚A8Ê»1DpäáC•¸ঈá0ï¶>UfÛ;ï·þ 0âzS endstream endobj 1767 0 obj <>/Filter/FlateDecode/Height 156/Intent/RelativeColorimetric/Length 8822/Name/X/Subtype/Image/Type/XObject/Width 259>>stream -H‰ìWÙO[g}÷Íwµ¯÷íÚÆ¼°96˜5i -N‹ !Ð3 …)´…)I‘ª´ŠÒªTj*•DJúÐ>ŽZe’—’ŒÔ&óä­Ë<õ-jç¡j§#Í÷ùz” &Öô÷Çןïùó;ßïìÛ÷;~Çî`€Øäïÿ FAŒ…ÄÁŸ(Š‚ŠŸT'›¼÷cS1Qœ $Œ šÀð< ÆˆUGÂú’–B*[~®ÈŠÁˆQœ(‰…!FgDզРŽÀƒPÇýâSu%-‡*•­‰TO°&èQMdõ´!Ew¼;w,×w‹…7¢Œ%Ü9òÒÜK#a ƒ á´`q8!HÞÝrdæÂÛfSAo´ïå>½ùé/÷Öª¢â ÔEë‰F«¥ @°ÖHçÑɩɣ+ ÚÈ@ð¦†^½¸|ñÕ¡”W€Rò'Mf§Oó9Í¿Ïm•8š•=ÑÖ‡´Æ|ªâ¨kï?>v¼¿=b31¬ ¨ªªðtõÜŠ”VÉg‡NüáÄгɀBC -8G¢÷ÅÙ×ßx}öÅÞ„ƒÓç Àéñzœ€Šde»¿&\ãwÈ+Ø´hs²x#žÄ ŠáL\Uy#HÖt hx¨ÿ@“V¢ ~ðøÔÜüÜÔñƒñ2¢Åît9í‘%qœâpC -…ã$øÄf·8B{ˆÕå$O´í`ßᾃmQTc­ÍôŸ˜85q¢?Sket!м¢Úl6Ðä ÈÅ’$ ä -¼4Ì4Ü´±`¢‘êÚ“t#mN¥SͺÍã’¼±Ì¡ÃÏ>”‰y+`1’å%Y–%ž%1#D1U=k´”·ÁðØó)L˜S\Ó48ÇA€”pFqëbñX]Ð¥0ÐàÞü1 2Ü ëÖÆjL{ éaL¢$I¢‰Ño2Ý [¬V«E.vÀŠá ÷«7ÛÍö /ÇÒ>€â$ ôM“x)aØïzïWt¾IíŸ TÁæÑ­ˆÞ“CJ_*ä¶~ˆÁ -c¿ùÉ}•‡dÃàÛV¨ü{%è¥ü›%”ÞgÓ¤öäMèÜH‹~è'L’mb4–Ž$hÉì%¬A0»?d}nÁ™íU¨¬·Ð2:ü…#u&€äJ—†‘¼ÉìÈp_‹n—Û Ïar5ôŽMÏ/ž×±8?=ÖÛè1«ÁŽÑ…K—W®êX¹|ia´# 3Œ ºü`HG0àw©Có»>¤`Êg̾H4ì–KÀ÷tÖ§2-a›©ÄP Á˜xŽÆ‹Ö”kºFN¤5º €m…R -v-.¯\»þÄõk+Ë‹c]a‡+1°°²z{íîß î®Ý^]YˆÛxÞì -ÕÇ :ñúËlâ”ÐnQ˜JÅ8õdâpA(*˜”Cí¹‘#µV3V´¡XA‡¡”p÷ðx>ÛäH¬`·BPÊ\—~÷ãÏnÜü+ÄÍŸ}üît6æñ§ò—Vï=øæ»@|÷̓{«—òI§(ZýuMÉTZG*ÙTç· -¼ºëCT®¬ IK>v¤;jçp½ËZ=wúO3ÃmšTlàYÙærè²$i©¾l:dá(è«Àæ´†1–Xn~eõÖÚ»wÖn­®Ì4ú™ÉË·|ÿðÇBüøðû·/O¶z$Ɉ'[3í:2­ÉxÀ. -¶øn©4x±¥‡'OæöûÄÒÈbìÍÇæ/^øc¶^¥Ksf—Ïk—ôhÅI¦›B6åŽN”Ø:Ĭ\¼vã‹/ï݇¸÷å7®-mò;ά¬}ýð§_þñËO¿^[9“ñʲ#˜He::utdR‰ Cí‰Ýbç×S „{F§Î µd²D£åø¹åwfs S¡ÀâÖüàêÑ•€R¢Ã¯¹-‚I€q‡HaØÖ!‰5Yƒç®ß\ûêþß!îµvóú¹£ÍZ¨óì•;ßþðó¯ÿ†øõç¾½sål;|ûPCº½³KGg{º!)hØí!)ØAïMYàXÁjJ'#â[†œ ‡w]À½ï‚Ì‚’{")ÎJgúRšDío -˜EÛÓ7 vt#è×$‚b¤ànÊæÇ‡»Ã -¯€-Bµª¸ûa¾ç7ÂŽ|îA'²–?5ÒUÉ–¡°EPž:_°3wXþ.)ù[ú†G²I¯@Uô¸Oâ„§ÎîpG(ÓÇ;"©î®dÊè’ùóÕÛÔy†±ÏýæcŸøø8¾%ØäB.vH“ûbB`Є‹BˆAUÖJk¦ M•¦2©êÔ¡‰ A~vë¯R©¡‚´áL*vôÏ6¡Jˆ1)“Ú, -Ó…Riï÷ÇÇ>‰ƒã‘<2JxsÎçï{¿÷}ÞçÉ’¸"Èûb{„œâR®¤ºª\3Z&_ˆ*†É+²S´<â:"뼨ùÍôÍ;w‰SÈ •B ’Ñïªæ5 ©Š†dDEó‚!Á€OSD†:%i†Ac~£Iı4‹x4žô"./ê|—±ZÅMg•3>›ÅqsNœH°=Ͱ(_?œ7dG5Çò‚(1 ¢Ñ!; È‘c³BûÏn Ê­Èñ:€¤ 5pÅp‚ '^%9å¼saä~V à™¹ÇK®.d+R -,e[æió­.n’À{´ êà $ä¼ bÉàÌô3«ÙŠÑ¶M¹§Ê½ÏUrú2iÙ8.Í6‚â¨"øÇQ)J³IOÏRÝ KB3oÉâ2ÙÚ„‹äRô‘X¼8\” h^`¯¦èÃÃfC„‚Aâù$ySN€N+ªü!ÅgÅHÁÊZ°, •^ÀVÑNòš­U[kªÊÜDF“S:HãĶ%˜Þ¥xYQd~ébV;Ò¼CQ5¯M…?0ÅJŠæ  |š"±lbv C‘æk(JrOIÐaËóeˆ(YÖt/+†SB´"JD(5”3Íò"ºm‡ÃøÄÑ-Ð4“ žEn£È½`•Ë[·ÊAvs¬ÊIÊ&Z=&áã0þ¯²“†ŒŠi—–ÈÞìò°§a”=î|4Ô3c½²ÅW­²e7n„T[”ÈBn[˜ðy\"ƒ6f7Ê -ö¬k°ÙíÖ„1=I½n - -ÊÕ ERçȾÜB«Ò!&:4cr4#E• O€((z9 ~É,kNCS„ÅÞáZ8Qvˆ<ÇC…±ö@Œè*)qJ¢$;e¬…°D‹"ê$‰‚;†ƒi(š±Ìˆ4#50½" Wê[°ÏeòwÆar3 *¥¿¦8ÕãùK€šsz7Wn)óz¼ß¦hU:£0 -ÈH³42c¡dFJ6)0†¸4/³á¹¥óÚHÖé-”{,™Ý£vZôl®m¨«ú›ápwë ÖíèjÛV®¬‹Ö”ƒ %RIDµ"èµR` -XÅ$ÍXF.›‘ÏQM`9AÛbEÒJÜ œ)Þ¯ :³=ØBw¤©§¯«©Ÿ·Ì-ÐŒä&ØÙmÚÑL/C¢Ö@6õF¦OxÑœÛd“ÌXÆ4™‘²PÍ~ D“âöhÖð¸‰7®ÊNI¾XßðO†ûb>‰²›o…’ü ‰ƒGöuŪjëÉ唊®‘·'Þ8ÐÕÜÚý£öhÐ •ÁƒVùU§äpB1žÞÝ7>yõfrúϹ˜NÞ¼:9¾¿qó–ö± ·|3÷ô?¹x:÷̓[ÆâA/8J<ÞRkx=%Cž¡ÌW'ÆÎ?7–¨vs„y^3ÎÍñ×Nž>Ò×XU«@dOÝž7Ï¿wv´·¹¹M¯ -d-’¸šKr¬­ -x-68qåÚí;÷frqïÎíkW&†šÂ§&“æž}Ÿ‹g s’“§ÚB2/šüƒn1PY|ä©?L½3/sЙ›‡¸"‡Þøé讆HyqÇZìµñß\øå±žXm4†¸€&iÑÜéq-\)h<;u=ywæ‹\ÌÜM^Ÿ:;ôJ¤²ëô¥éÇó‹ÏÈÅóÅùÇÓ—N·¿@ -H^«Û;~ùFòÆåñ½uOšS WÁpo]&MñzLi«,+Ã$¨TÈ<–éO„õ¨tÏáα÷?ýòï_~úþXgØÅ˜Ä»ÎÃ?n«Ôœ`Ã1a1üâõ}!UqáQŠæ$pÒâ p]°.\`§D_ãй?8ûðóÏ 5úÄLFLM„±‹ñ§EìM::ØUí‘x_9 <œÀ±kQ‡ë1lë®Úyæâ­ßþûÛ·.žÙYåf‰Ì2Àº VVAmº•ÓuA¼> £¢À’Y׎”R,0ë£ àJƒ­#ï~|vþ¿ó³÷?~w¤5ä0•®}ªÄ†È¦«ÃH@á©%ßꃶ°i]Ô!*‚­ý?›J>|òÝâwO&§Þ¨1Fì™s.å™§–z>åÖ–uð6)ú·9õ«Ùù…Å…ùÙ¯>ùõÑ– De¦@wŠ™$o8EÓð·­Ñ#¦VyÙNêÎîyýwŸýuöÉüÓù'ÿúÛÍ‹g -cbt‹ÃA„ ²yß¶H/BмCQ5¯54UGz\Ñ|`È -Á€OS°@Õ·¹ì:‹1JÕ®7'oüåk ×þãëûŸ]ßSçá²Bîé,B¹ÇYÕkæª0¬–d QàY4tHÜæNk¤ÛÁ¾ô¯E)¨Lœzï÷×ÿ8 \:ý§}ðÖžz³<2¶i±ñs€Ø!K"¬"ôòS@Ëå­ÞúÕ/!.½øÛó??ÚS­ræyY¸ÂÌ1ó}"Òäy¼aÛ „^v# ZuÛÞ#'0·—Žö6„œÌÿ˜/—ç6ª,#µ¤~ª»¥îV¿$Ùz:²lY–âG,ÅÈCìØ‰“òÀaƉãxL‘f1  < ¨©›doÙ²¡ØÀ†d<æ`G±d—‚YP0LÕœ{o·,YΨ§*eël\>ÕWuÏãžóý¨æ!¡‚F©Ð!ç´hdGÇ'ñ¯MNœ>–Pš—³Qo9YhlEEæâs;ý*É|Â)ÉBi g+CV‡—ïð—â „lM;žÀ· UjËb#;& ,ª;³Q6“Ž Hù€8`£é0Š–“Ã3 Ó•œÁ¿èÅå?|4"-Íò p‰Á´ µ®{BÈ嬥ȢÀ 8„.¬ÁÉŠìEí#¢“êµJÖŠ)4eˆNºüêÅÙr&aÅdŒ£“"ZÔ þo”6ßýpçÞj½œ@ÓÅçÁ8™ÔäMÖ² ^»ýù_íöóÓ¿û⣵ñ„Èñ¢3͈̃)°[¨ÿ¹×ÐrjüüÍÛWO—z wÅÆ_ÿÛï\¯ö÷Ú¤ Ð ·Ó™¤.C -P Žž^ÛÙýxwg½^Œiø<¸‚“¡•íGŸ~ùÕ7ß¶Û7_}ùé£í #é\uýÁãïŸþòÛ¿Ûí·_ž~ÿøÁúdRâIÕMë`3uUâ=¦ ’™zysëÕú`B•Ð,ðSpÍóoýý£¿¾:•·TϘj"›íÑ%<ý¸{*+÷îï>|ÿV½¨ó¯JAyåÝÏýí?ÛíÛ¯¶ûÎ…ÑL¾vûá“~úõ÷ÿ´Ûï¿þôÓ‡·O>Ç.¸2Óoˆ,Þn¼}e¬W ãÐ肘ˆá͇ -¬äj«Û;ïÿåê©‚.àyÑÑ -vcYpei"«rD]úÉ,x{ciØ Ò¸³ÀR²laå³4mýÖ•—ÆúL·JGâ»n¸áôÔšáÀ¡ðòõ•jŸÊ9»An@8ÒS®Öë§ÆJ9+ÂpÍ;¸8š×Žb#thÌCÅ”Æ;ѹ\0>—\”v¸@äéU òKä‹ÅB_®×ŠâÍÙÑÅÓÜpAÇ:´´pC9øfâÑ==…é…aѤ€€ÿQà5’µÑÙÅÓ̡ӡ·À/5××ÑÑ”v4‚¿Y+x‚î#Q9Ì8ÝÁ q‡«¼d ¡©¦p¥ØŠÒŽRlò€T P„ã¼ºŽ®@è•¢7kc5EíKâ~´Ä¿£ }>/.øbŨöÌ!¦EaŽPƬ¸#îöYËö…Ô!·ß÷¬ƒ- ìäB=¢aªpË"ü†[ÅÝ>ãy0mèßfž@î†ïºç!÷mú™¶_ôaýEù›¾òâòP;§mžmè+áyJt(nÑFØPƒ -âj¸ÊÒMÔ^phhrø}ïÕÛ“«]¸T¹çS_/€¶d¡áùãTà&d)"C&h_Þ­¥¿ÑâxÛi†âÒ¤Þ\]fpCFTtÓžf9xe d‚æ£fOº×RE!,ËÚ–¨/kD·­ó$ ¥œ­dý½àÍÕ]`e3u¬XHÛjT‰ÅT‰c˜p,5p|üÅRÖÖÍDÒVÃt°ˆ;°tÈi ?EËÉá™……éJÎŒ -òäê2Chç‡ÇNNŒR‰d:ÓkDÂ’ž™^8wvîÄ@_¡4TìÕ†fò¢*‘ç€rxÔÔN+Ì\ÝÜZ[©•z Þ\Gs«AD3?Z›ŸŸ>Q:V,õ§ UÏŒž¾pýµ—ÏL?1U+Æ#ï®n2?!^R-‚Á”£~XQµÓ}Dzv„%TÕ$ÍrK·`>|K³h<†‚TC>zqu“Á\Ò\˜Ÿ«í@;†#ª¦H{}ëC¯ É– …'w:xwu•ùPlDù¸á‚ Õ¼¥äè5 Û„ϵÿ×ÕU†‚C%jº òðêÛ÷áA´ûº9Øg©okÕPR¨}%?(2|¶õm<«[žï¥Ÿ§Á4Àœjy»Á< ôð÷œ$Ø}Iñïäl(ØÒAí‰ê&ÃÃ6À"£‚Œ d‘ aï=æ÷ÒtÖ#îYfšÎ~| #*ºiô„àš(fØ“Q³'Ýk -FµeW×m¦³Œ»MöÎò.6íÆ ÍԱⱴá´ºZÐRÇÇ_LëÏq ê(.Eþ¡Hk´œ°$ÈrϦ4>è0Eãl°ûÀ‰V¶óÃc'Ç+}¶"‰aŒËŒL/,ŸÍ™j4"ñ0€dEU"xÆhœΛ#QRx÷l%e)’– {–é>Z¶e=:Ê”ÇU{#Ã?€;ÙÒF­ö*ÝbÚÔTYÕÔrãÎî~çù½|Ê2µÏr’7 3ajr˜ÅUàÖ*yKBÓ/ÈÈö9wg³|M Ð.!ÑåB9ù®AZ´ò•Z£ÞhÖ«E[—Å0/hNy³³ÿzÿ`¯½ž›Ö•H˜ ñ²f$Lœ2@ÀÞès× -8DH¹æqŸW7hfz\ߦ`­þ¡^¹y5І!Ãǜʳ½?ö6ï^KèŒf¸ˆfN!@¸ CÜ2n|HS>ç¶VÒQ>£zܘÄú²Ììʃ擧Ojw2†€F?’íÛÍ탷½Ýi.%£1I±’j$¦¬)ú™¸+q€;§ó¤Û÷Ñ/Ó¨0®¸ÐçtÌãÐ.¬Þ¯7ë÷n¥-˜¹µÇ/÷^ÿ¾‘3í¿ Áðh¤¡ZÖ£aú\ú^ಸè¹F´ˆ¥®ÏŠw‚ §rKw«kËÙ„ÄÀû’!yúæêçígµå´Â®ƒ§ G”˜®! IõDß W¤ñôæBÀŸåú he 1kv>ŸĮ̈xX¡+sÑ)§p»\^ʘ¢«rÑ!Ã…¥HD䙞Ê…ë#ÀHªi]M¨‚+\`†‹jÂv®§2KºEŽa9Žeúm®Ÿ -žá Þȳ:àÿY)R¿r‘ÛES‘²ð[p}p²Ã0Ñ»2x;ônCÏ!èú£oÃõà‚1xA|–00ü]àR£p}…À9†Nð³}Áµ/wñg?ܧ$+?%‰uààw?_l_<²CÈR^ÿâAÇrZw¼ -”ú£¼M"Wm½Ú}Õªºž_zµ}Ø=î¶WÓ2ãj_VÒ­¤´tzÞ‘€n©õæ¨{ô¦U²!ÞÁj¹Æá‡“Ó“‡œvÚEµf³óÙYKåýhw¾ÈÝ)ÎúöÑû¿ßm¯;Jm‚3^tO>}:é¾X08H|a2[(²I]¯N@)Pç6:ï>þóñ]gcN…¼¹¸u|zöïÙéñ֢ɓ8bÜž/Þ*ÎÛqqìR𿯂É,˜l„‰.¸2Q‡€‰G˜8EÀg‚Ã'$>üãG\ñ;àrl㯇ÿžî—Ç endstream endobj 1679 0 obj <> endobj 1768 0 obj <> endobj 1769 0 obj [0.0 0.0 0.0] endobj 1770 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -259 0 0 156 -3 87 cm -/Im0 Do -Q - endstream endobj 1771 0 obj <> endobj 1772 0 obj <>/Filter/FlateDecode/Height 156/Intent/RelativeColorimetric/Length 8822/Name/X/Subtype/Image/Type/XObject/Width 259>>stream -H‰ìWÙO[g}÷Íwµ¯÷íÚÆ¼°96˜5i -N‹ !Ð3 …)´…)I‘ª´ŠÒªTj*•DJúÐ>ŽZe’—’ŒÔ&óä­Ë<õ-jç¡j§#Í÷ùz” &Öô÷Çןïùó;ßïìÛ÷;~Çî`€Øäïÿ FAŒ…ÄÁŸ(Š‚ŠŸT'›¼÷cS1Qœ $Œ šÀð< ÆˆUGÂú’–B*[~®ÈŠÁˆQœ(‰…!FgDզРŽÀƒPÇýâSu%-‡*•­‰TO°&èQMdõ´!Ew¼;w,×w‹…7¢Œ%Ü9òÒÜK#a ƒ á´`q8!HÞÝrdæÂÛfSAo´ïå>½ùé/÷Öª¢â ÔEë‰F«¥ @°ÖHçÑɩɣ+ ÚÈ@ð¦†^½¸|ñÕ¡”W€Rò'Mf§Oó9Í¿Ïm•8š•=ÑÖ‡´Æ|ªâ¨kï?>v¼¿=b31¬ ¨ªªðtõÜŠ”VÉg‡NüáÄгɀBC -8G¢÷ÅÙ×ßx}öÅÞ„ƒÓç Àéñzœ€Šde»¿&\ãwÈ+Ø´hs²x#žÄ ŠáL\Uy#HÖt hx¨ÿ@“V¢ ~ðøÔÜüÜÔñƒñ2¢Åît9í‘%qœâpC -…ã$øÄf·8B{ˆÕå$O´í`ßᾃmQTc­ÍôŸ˜85q¢?Sket!м¢Úl6Ðä ÈÅ’$ ä -¼4Ì4Ü´±`¢‘êÚ“t#mN¥SͺÍã’¼±Ì¡ÃÏ>”‰y+`1’å%Y–%ž%1#D1U=k´”·ÁðØó)L˜S\Ó48ÇA€”pFqëbñX]Ð¥0ÐàÞü1 2Ü ëÖÆjL{ éaL¢$I¢‰Ño2Ý [¬V«E.vÀŠá ÷«7ÛÍö /ÇÒ>€â$ ôM“x)aØïzïWt¾IíŸ TÁæÑ­ˆÞ“CJ_*ä¶~ˆÁ -c¿ùÉ}•‡dÃàÛV¨ü{%è¥ü›%”ÞgÓ¤öäMèÜH‹~è'L’mb4–Ž$hÉì%¬A0»?d}nÁ™íU¨¬·Ð2:ü…#u&€äJ—†‘¼ÉìÈp_‹n—Û Ïar5ôŽMÏ/ž×±8?=ÖÛè1«ÁŽÑ…K—W®êX¹|ia´# 3Œ ºü`HG0àw©Có»>¤`Êg̾H4ì–KÀ÷tÖ§2-a›©ÄP Á˜xŽÆ‹Ö”kºFN¤5º €m…R -v-.¯\»þÄõk+Ë‹c]a‡+1°°²z{íîß î®Ý^]YˆÛxÞì -ÕÇ :ñúËlâ”ÐnQ˜JÅ8õdâpA(*˜”Cí¹‘#µV3V´¡XA‡¡”p÷ðx>ÛäH¬`·BPÊ\—~÷ãÏnÜü+ÄÍŸ}üît6æñ§ò—Vï=øæ»@|÷̓{«—òI§(ZýuMÉTZG*ÙTç· -¼ºëCT®¬ IK>v¤;jçp½ËZ=wúO3ÃmšTlàYÙærè²$i©¾l:dá(è«Àæ´†1–Xn~eõÖÚ»wÖn­®Ì4ú™ÉË·|ÿðÇBüøðû·/O¶z$Ɉ'[3í:2­ÉxÀ. -¶øn©4x±¥‡'OæöûÄÒÈbìÍÇæ/^øc¶^¥Ksf—Ïk—ôhÅI¦›B6åŽN”Ø:Ĭ\¼vã‹/ï݇¸÷å7®-mò;ά¬}ýð§_þñËO¿^[9“ñʲ#˜He::utdR‰ Cí‰Ýbç×S „{F§Î µd²D£åø¹åwfs S¡ÀâÖüàêÑ•€R¢Ã¯¹-‚I€q‡HaØÖ!‰5Yƒç®ß\ûêþß!îµvóú¹£ÍZ¨óì•;ßþðó¯ÿ†øõç¾½sål;|ûPCº½³KGg{º!)hØí!)ØAïMYàXÁjJ'#â[†œ ‡w]À½ï‚Ì‚’{")ÎJgúRšDío -˜EÛÓ7 vt#è×$‚b¤ànÊæÇ‡»Ã -¯€-Bµª¸ûa¾ç7ÂŽ|îA'²–?5ÒUÉ–¡°EPž:_°3wXþ.)ù[ú†G²I¯@Uô¸Oâ„§ÎîpG(ÓÇ;"©î®dÊè’ùóÕÛÔy†±ÏýæcŸøø8¾%ØäB.vH“ûbB`Є‹BˆAUÖJk¦ M•¦2©êÔ¡‰ A~vë¯R©¡‚´áL*vôÏ6¡Jˆ1)“Ú, -Ó…Riï÷ÇÇ>‰ƒã‘<2JxsÎçï{¿÷}ÞçÉ’¸"Èûb{„œâR®¤ºª\3Z&_ˆ*†É+²S´<â:"뼨ùÍôÍ;w‰SÈ •B ’Ñïªæ5 ©Š†dDEó‚!Á€OSD†:%i†Ac~£Iı4‹x4žô"./ê|—±ZÅMg•3>›ÅqsNœH°=Ͱ(_?œ7dG5Çò‚(1 ¢Ñ!; È‘c³BûÏn Ê­Èñ:€¤ 5pÅp‚ '^%9å¼saä~V à™¹ÇK®.d+R -,e[æió­.n’À{´ êà $ä¼ bÉàÌô3«ÙŠÑ¶M¹§Ê½ÏUrú2iÙ8.Í6‚â¨"øÇQ)J³IOÏRÝ KB3oÉâ2ÙÚ„‹äRô‘X¼8\” h^`¯¦èÃÃfC„‚Aâù$ySN€N+ªü!ÅgÅHÁÊZ°, •^ÀVÑNòš­U[kªÊÜDF“S:HãĶ%˜Þ¥xYQd~ébV;Ò¼CQ5¯M…?0ÅJŠæ  |š"±lbv C‘æk(JrOIÐaËóeˆ(YÖt/+†SB´"JD(5”3Íò"ºm‡ÃøÄÑ-Ð4“ žEn£È½`•Ë[·ÊAvs¬ÊIÊ&Z=&áã0þ¯²“†ŒŠi—–ÈÞìò°§a”=î|4Ô3c½²ÅW­²e7n„T[”ÈBn[˜ðy\"ƒ6f7Ê -ö¬k°ÙíÖ„1=I½n - -ÊÕ ERçȾÜB«Ò!&:4cr4#E• O€((z9 ~É,kNCS„ÅÞáZ8Qvˆ<ÇC…±ö@Œè*)qJ¢$;e¬…°D‹"ê$‰‚;†ƒi(š±Ìˆ4#50½" Wê[°ÏeòwÆar3 *¥¿¦8ÕãùK€šsz7Wn)óz¼ß¦hU:£0 -ÈH³42c¡dFJ6)0†¸4/³á¹¥óÚHÖé-”{,™Ý£vZôl®m¨«ú›ápwë ÖíèjÛV®¬‹Ö”ƒ %RIDµ"èµR` -XÅ$ÍXF.›‘ÏQM`9AÛbEÒJÜ œ)Þ¯ :³=ØBw¤©§¯«©Ÿ·Ì-ÐŒä&ØÙmÚÑL/C¢Ö@6õF¦OxÑœÛd“ÌXÆ4™‘²PÍ~ D“âöhÖð¸‰7®ÊNI¾XßðO†ûb>‰²›o…’ü ‰ƒGöuŪjëÉ唊®‘·'Þ8ÐÕÜÚý£öhÐ •ÁƒVùU§äpB1žÞÝ7>yõfrúϹ˜NÞ¼:9¾¿qó–ö± ·|3÷ô?¹x:÷̓[ÆâA/8J<ÞRkx=%Cž¡ÌW'ÆÎ?7–¨vs„y^3ÎÍñ×Nž>Ò×XU«@dOÝž7Ï¿wv´·¹¹M¯ -d-’¸šKr¬­ -x-68qåÚí;÷frqïÎíkW&†šÂ§&“æž}Ÿ‹g s’“§ÚB2/šüƒn1PY|ä©?L½3/sЙ›‡¸"‡Þøé讆HyqÇZìµñß\øå±žXm4†¸€&iÑÜéq-\)h<;u=ywæ‹\ÌÜM^Ÿ:;ôJ¤²ëô¥éÇó‹ÏÈÅóÅùÇÓ—N·¿@ -H^«Û;~ùFòÆåñ½uOšS WÁpo]&MñzLi«,+Ã$¨TÈ<–éO„õ¨tÏáα÷?ýòï_~úþXgØÅ˜Ä»ÎÃ?n«Ôœ`Ã1a1üâõ}!UqáQŠæ$pÒâ p]°.\`§D_ãй?8ûðóÏ 5úÄLFLM„±‹ñ§EìM::ØUí‘x_9 <œÀ±kQ‡ë1lë®Úyæâ­ßþûÛ·.žÙYåf‰Ì2Àº VVAmº•ÓuA¼> £¢À’Y׎”R,0ë£ àJƒ­#ï~|vþ¿ó³÷?~w¤5ä0•®}ªÄ†È¦«ÃH@á©%ßꃶ°i]Ô!*‚­ý?›J>|òÝâwO&§Þ¨1Fì™s.å™§–z>åÖ–uð6)ú·9õ«Ùù…Å…ùÙ¯>ùõÑ– De¦@wŠ™$o8EÓð·­Ñ#¦VyÙNêÎîyýwŸýuöÉüÓù'ÿúÛÍ‹g -cbt‹ÃA„ ²yß¶H/BмCQ5¯54UGz\Ñ|`È -Á€OS°@Õ·¹ì:‹1JÕ®7'oüåk ×þãëûŸ]ßSçá²Bîé,B¹ÇYÕkæª0¬–d QàY4tHÜæNk¤ÛÁ¾ô¯E)¨Lœzï÷×ÿ8 \:ý§}ðÖžz³<2¶i±ñs€Ø!K"¬"ôòS@Ëå­ÞúÕ/!.½øÛó??ÚS­ræyY¸ÂÌ1ó}"Òäy¼aÛ „^v# ZuÛÞ#'0·—Žö6„œÌÿ˜/—ç6ª,#µ¤~ª»¥îV¿$Ùz:²lY–âG,ÅÈCìØ‰“òÀaƉãxL‘f1  < ¨©›doÙ²¡ØÀ†d<æ`G±d—‚YP0LÕœ{o·,YΨ§*eël\>ÕWuÏãžóý¨æ!¡‚F©Ð!ç´hdGÇ'ñ¯MNœ>–Pš—³Qo9YhlEEæâs;ý*É|Â)ÉBi g+CV‡—ïð—â „lM;žÀ· UjËb#;& ,ª;³Q6“Ž Hù€8`£é0Š–“Ã3 Ó•œÁ¿èÅå?|4"-Íò p‰Á´ µ®{BÈ嬥ȢÀ 8„.¬ÁÉŠìEí#¢“êµJÖŠ)4eˆNºüêÅÙr&aÅdŒ£“"ZÔ þo”6ßýpçÞj½œ@ÓÅçÁ8™ÔäMÖ² ^»ýù_íöóÓ¿û⣵ñ„Èñ¢3͈̃)°[¨ÿ¹×ÐrjüüÍÛWO—z wÅÆ_ÿÛï\¯ö÷Ú¤ Ð ·Ó™¤.C -P Žž^ÛÙýxwg½^Œiø<¸‚“¡•íGŸ~ùÕ7ß¶Û7_}ùé£í #é\uýÁãïŸþòÛ¿Ûí·_ž~ÿøÁúdRâIÕMë`3uUâ=¦ ’™zysëÕú`B•Ð,ðSpÍóoýý£¿¾:•·TϘj"›íÑ%<ý¸{*+÷îï>|ÿV½¨ó¯JAyåÝÏýí?ÛíÛ¯¶ûÎ…ÑL¾vûá“~úõ÷ÿ´Ûï¿þôÓ‡·O>Ç.¸2Óoˆ,Þn¼}e¬W ãÐ肘ˆá͇ -¬äj«Û;ïÿåê©‚.àyÑÑ -vcYpei"«rD]úÉ,x{ciØ Ò¸³ÀR²laå³4mýÖ•—ÆúL·JGâ»n¸áôÔšáÀ¡ðòõ•jŸÊ9»An@8ÒS®Öë§ÆJ9+ÂpÍ;¸8š×Žb#thÌCÅ”Æ;ѹ\0>—\”v¸@äéU òKä‹ÅB_®×ŠâÍÙÑÅÓÜpAÇ:´´pC9øfâÑ==…é…aѤ€€ÿQà5’µÑÙÅÓ̡ӡ·À/5××ÑÑ”v4‚¿Y+x‚î#Q9Ì8ÝÁ q‡«¼d ¡©¦p¥ØŠÒŽRlò€T P„ã¼ºŽ®@è•¢7kc5EíKâ~´Ä¿£ }>/.øbŨöÌ!¦EaŽPƬ¸#îöYËö…Ô!·ß÷¬ƒ- ìäB=¢aªpË"ü†[ÅÝ>ãy0mèßfž@î†ïºç!÷mú™¶_ôaýEù›¾òâòP;§mžmè+áyJt(nÑFØPƒ -âj¸ÊÒMÔ^phhrø}ïÕÛ“«]¸T¹çS_/€¶d¡áùãTà&d)"C&h_Þ­¥¿ÑâxÛi†âÒ¤Þ\]fpCFTtÓžf9xe d‚æ£fOº×RE!,ËÚ–¨/kD·­ó$ ¥œ­dý½àÍÕ]`e3u¬XHÛjT‰ÅT‰c˜p,5p|üÅRÖÖÍDÒVÃt°ˆ;°tÈi ?EËÉá™……éJÎŒ -òäê2Chç‡ÇNNŒR‰d:ÓkDÂ’ž™^8wvîÄ@_¡4TìÕ†fò¢*‘ç€rxÔÔN+Ì\ÝÜZ[©•z Þ\Gs«AD3?Z›ŸŸ>Q:V,õ§ UÏŒž¾pýµ—ÏL?1U+Æ#ï®n2?!^R-‚Á”£~XQµÓ}Dzv„%TÕ$ÍrK·`>|K³h<†‚TC>zqu“Á\Ò\˜Ÿ«í@;†#ª¦H{}ëC¯ É– …'w:xwu•ùPlDù¸á‚ Õ¼¥äè5 Û„ϵÿ×ÕU†‚C%jº òðêÛ÷áA´ûº9Øg©okÕPR¨}%?(2|¶õm<«[žï¥Ÿ§Á4Àœjy»Á< ôð÷œ$Ø}Iñïäl(ØÒAí‰ê&ÃÃ6À"£‚Œ d‘ aï=æ÷ÒtÖ#îYfšÎ~| #*ºiô„àš(fØ“Q³'Ýk -FµeW×m¦³Œ»MöÎò.6íÆ ÍԱⱴá´ºZÐRÇÇ_LëÏq ê(.Eþ¡Hk´œ°$ÈrϦ4>è0Eãl°ûÀ‰V¶óÃc'Ç+}¶"‰aŒËŒL/,ŸÍ™j4"ñ0€dEU"xÆhœΛ#QRx÷l%e)’– {–é>Z¶e=:Ê”ÇU{#Ã?€;ÙÒF­ö*ÝbÚÔTYÕÔrãÎî~çù½|Ê2µÏr’7 3ajr˜ÅUàÖ*yKBÓ/ÈÈö9wg³|M Ð.!ÑåB9ù®AZ´ò•Z£ÞhÖ«E[—Å0/hNy³³ÿzÿ`¯½ž›Ö•H˜ ñ²f$Lœ2@ÀÞès× -8DH¹æqŸW7hfz\ߦ`­þ¡^¹y5І!Ãǜʳ½?ö6ï^KèŒf¸ˆfN!@¸ CÜ2n|HS>ç¶VÒQ>£zܘÄú²Ììʃ擧Ojw2†€F?’íÛÍ탷½Ýi.%£1I±’j$¦¬)ú™¸+q€;§ó¤Û÷Ñ/Ó¨0®¸ÐçtÌãÐ.¬Þ¯7ë÷n¥-˜¹µÇ/÷^ÿ¾‘3í¿ Áðh¤¡ZÖ£aú\ú^ಸè¹F´ˆ¥®ÏŠw‚ §rKw«kËÙ„ÄÀû’!yúæêçígµå´Â®ƒ§ G”˜®! IõDß W¤ñôæBÀŸåú he 1kv>ŸĮ̈xX¡+sÑ)§p»\^ʘ¢«rÑ!Ã…¥HD䙞Ê…ë#ÀHªi]M¨‚+\`†‹jÂv®§2KºEŽa9Žeúm®Ÿ -žá Þȳ:àÿY)R¿r‘ÛES‘²ð[p}p²Ã0Ñ»2x;ônCÏ!èú£oÃõà‚1xA|–00ü]àR£p}…À9†Nð³}Áµ/wñg?ܧ$+?%‰uààw?_l_<²CÈR^ÿâAÇrZw¼ -”ú£¼M"Wm½Ú}Õªºž_zµ}Ø=î¶WÓ2ãj_VÒ­¤´tzÞ‘€n©õæ¨{ô¦U²!ÞÁj¹Æá‡“Ó“‡œvÚEµf³óÙYKåýhw¾ÈÝ)ÎúöÑû¿ßm¯;Jm‚3^tO>}:é¾X08H|a2[(²I]¯N@)Pç6:ï>þóñ]gcN…¼¹¸u|zöïÙéñ֢ɓ8bÜž/Þ*ÎÛqqìR𿯂É,˜l„‰.¸2Q‡€‰G˜8EÀg‚Ã'$>üãG\ñ;àrl㯇ÿžî—Ç endstream endobj 1484 0 obj <> endobj 1677 0 obj <> endobj 1676 0 obj <> endobj 1675 0 obj <> endobj 1674 0 obj <> endobj 1673 0 obj <> endobj 1672 0 obj <> endobj 1671 0 obj <> endobj 1670 0 obj <> endobj 1669 0 obj <> endobj 1668 0 obj <> endobj 1667 0 obj <>/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr /Fm0 Do -Q - endstream endobj 1773 0 obj <> endobj 1774 0 obj <>/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr /Fm0 Do -Q - endstream endobj 1775 0 obj <> endobj 1776 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 0 0 0 scn -/GS0 gs -q 1 0 0 1 9.5 7.5 cm -0 0 m -0 1.1 -0.9 2 -2 2 c --17 2 l --18.1 2 -19 1.1 -19 0 c --19 -15 l --19 -16.1 -18.1 -17 -17 -17 c --2 -17 l --0.9 -17 0 -16.1 0 -15 c -h -f -Q - endstream endobj 1777 0 obj <> endobj 1666 0 obj <> endobj 1665 0 obj <> endobj 1664 0 obj <> endobj 1663 0 obj <> endobj 1662 0 obj <> endobj 1661 0 obj <> endobj 1660 0 obj <> endobj 1659 0 obj <> endobj 1658 0 obj <> endobj 1657 0 obj <> endobj 1656 0 obj <> endobj 1655 0 obj <> endobj 1654 0 obj <> endobj 1653 0 obj <> endobj 1652 0 obj <> endobj 1651 0 obj <> endobj 1650 0 obj <> endobj 1649 0 obj <> endobj 1648 0 obj <> endobj 1647 0 obj <> endobj 1646 0 obj <> endobj 1645 0 obj <> endobj 1644 0 obj <> endobj 1643 0 obj <> endobj 1642 0 obj <> endobj 1641 0 obj <> endobj 1640 0 obj <> endobj 1639 0 obj <> endobj 1638 0 obj <> endobj 1637 0 obj <> endobj 1636 0 obj <> endobj 1635 0 obj <> endobj 1634 0 obj <> endobj 1633 0 obj <> endobj 1632 0 obj <> endobj 1631 0 obj <> endobj 1630 0 obj <> endobj 1629 0 obj <> endobj 1621 0 obj <> endobj 1626 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -322 0 0 49 -1 -1 cm -/Im0 Do -Q - endstream endobj 1627 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -q 1 0 0 1 315 8 cm -0 0 m -0 -1.656 -1.343 -3 -3 -3 c --307 -3 l --308.657 -3 -310 -1.656 -310 0 c --310 31 l --310 32.656 -308.657 34 -307 34 c --3 34 l --1.343 34 0 32.656 0 31 c -h -f -Q - endstream endobj 1628 0 obj <>/ExtGState<>>>/Subtype/Form>>stream -/CS0 cs 1 1 1 scn -/GS0 gs -q 1 0 0 1 5 28 cm -0 0 m -0 11 l -0 12.656 1.344 14 3 14 c -307 14 l -308.657 14 310 12.656 310 11 c -310 0 l -h -f -Q - endstream endobj 1783 0 obj <> endobj 1782 0 obj <> endobj 1778 0 obj <> endobj 1781 0 obj <>stream -H‰ìÁàùS_áUð™=¢ endstream endobj 1779 0 obj [/Indexed 1474 0 R 0 1785 0 R] endobj 1784 0 obj <>/Filter/FlateDecode/Height 49/Intent/RelativeColorimetric/Length 649/Name/X/Subtype/Image/Type/XObject/Width 322>>stream -H‰ìÕ¿‹Ó`Çñôáï‚ÉR -úiAAZP¤iAAZP¤iAAZP¤iAAZP¤iAAZP¤iý[°Út\o:„¦žë4«¿ ê†ew‡coyãa×¶ }UPTµB¥Ñ Ý äF¥ ©â² ’È—ëíNÏéBN¯Ó®—ó eQBñ¬iÕv³5íFÝ2³ñÀ"„yy73Ë«ˆY•²™KïÊ>stream -ÿÿÿ endstream endobj 1780 0 obj <> endobj 1786 0 obj <> endobj 1787 0 obj [0.0 0.0 0.0] endobj 1788 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -322 0 0 49 -1 -1 cm -/Im0 Do -Q - endstream endobj 1789 0 obj <> endobj 1790 0 obj <>/Filter/FlateDecode/Height 49/Intent/RelativeColorimetric/Length 649/Name/X/Subtype/Image/Type/XObject/Width 322>>stream -H‰ìÕ¿‹Ó`Çñôáï‚ÉR -úiAAZP¤iAAZP¤iAAZP¤iAAZP¤iAAZP¤iý[°Út\o:„¦žë4«¿ ê†ew‡coyãa×¶ }UPTµB¥Ñ Ý äF¥ ©â² ’È—ëíNÏéBN¯Ó®—ó eQBñ¬iÕv³5íFÝ2³ñÀ"„yy73Ë«ˆY•²™KïÊ> endobj 1791 0 obj [/ICCBased 1764 0 R] endobj 1792 0 obj <> endobj 1793 0 obj <> endobj 1794 0 obj <> endobj 1622 0 obj <> endobj 1623 0 obj <> endobj 1624 0 obj <> endobj 1795 0 obj <> endobj 1796 0 obj [1.0] endobj 1797 0 obj <>/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -0 Tc 0 Tw 0 Ts 100 Tz 0 Tr /Fm0 Do -Q - endstream endobj 1798 0 obj <>stream -H‰ª6Ô3…ÔŠä …âÒ$…Z€7Ê endstream endobj 1799 0 obj <> endobj 1800 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream -q -/GS0 gs -314 0 0 41 3 3 cm -/Im0 Do -Q - endstream endobj 1802 0 obj <> endobj 1803 0 obj <>/Filter/FlateDecode/Height 41/Intent/RelativeColorimetric/Length 346/Name/X/Subtype/Image/Type/XObject/Width 314>>stream -H‰ìÐMNÂP†aöÁºÊÔ2jSnqdd'*lXG$VI)ýq¦Ú„¶7%0щcËps“ïYÁ›·Õ¸´¶Ñ8CáA#µ­žÑ¡sÆxêá*ŽøWGá«?_Ó¹þôc›•¬¡Yù6›öéÜÀß¿á ÇÍË€Î9A®:E7ù»Cç†a¡ºD7e$èœXUªKt#Îy±T]¢›:ÎÕªKt³ÏNçœ;Ó>»Å9œãÂ9.œãÂ9.œãÂ9.œãÂ9.œãÂ9.œãÂ9.œãÂ9.œãÂ9.œãú;ãÜ™öÙètNª.ÑMþžQ¥ºD72ñ蜪KtSFC:g¹êÝäo»y^T§èå°ñ-:g>¥ë¯]YIh *wŸëtbÒ¹îÝÃl¾—4° óÙã}—ε¯z–í -šµ-Óè´.îG€"6[o endstream endobj 1801 0 obj /DeviceGray endobj 1462 0 obj <> endobj 1463 0 obj <> endobj 1464 0 obj <> endobj 1465 0 obj <> endobj 1466 0 obj <> endobj 1467 0 obj <> endobj 1468 0 obj <> endobj 1816 0 obj [/View/Design] endobj 1817 0 obj <>>> endobj 1814 0 obj [/View/Design] endobj 1815 0 obj <>>> endobj 1812 0 obj [/View/Design] endobj 1813 0 obj <>>> endobj 1810 0 obj [/View/Design] endobj 1811 0 obj <>>> endobj 1808 0 obj [/View/Design] endobj 1809 0 obj <>>> endobj 1806 0 obj [/View/Design] endobj 1807 0 obj <>>> endobj 1804 0 obj [/View/Design] endobj 1805 0 obj <>>> endobj 1476 0 obj <> endobj 1477 0 obj <> endobj 1478 0 obj <> endobj 1479 0 obj <> endobj 1481 0 obj <> endobj 1482 0 obj <> endobj 1483 0 obj <> endobj 1473 0 obj <> endobj 1818 0 obj <> endobj 1819 0 obj <>stream -%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 14.0 %%AI8_CreatorVersion: 14.0.0 %%For: (Edwin) () %%Title: (assets.ai) %%CreationDate: 3/29/10 8:42 AM %%Canvassize: 16383 %%BoundingBox: 349 263 673 517 %%HiResBoundingBox: 349 263 673 517 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 10.0 %AI12_BuildNumber: 367 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%CMYKCustomColor: 0 0.949997 1 0 (PANTONE 485 C) %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: 352 264 672 504 %AI3_TemplateBox: 512.5 383.5 512.5 383.5 %AI3_TileBox: 134 96 868 672 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 7 %AI9_OpenToView: -489 1109 1 1996 1318 90 1 0 66 129 0 0 0 1 1 0 1 1 0 %AI5_OpenViewLayers: 3777773 %%PageOrigin:0 0 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 1820 0 obj <>stream -%%BoundingBox: 349 263 673 517 %%HiResBoundingBox: 349 263 673 517 %AI7_Thumbnail: 128 100 8 %%BeginData: 9476 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFDFCFFFDA6FFA8FD80FFA8FD64FFA8FFA8FD05FFA8FFA8FD %05FFA8FFFFFFA8FFA8A8A8FFA8A8A8FFA8FFA8FD04FFA827522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %52275227522752275227522752275227A8FD07FFA8FD05FFA8FFA8FD0BFF %A8A8A8FFFFFFA8FFFFFFA8FD05FFA8A87DA87DA87DA87DA87DA87DA87DA8 %7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8 %7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8 %7DA87DA87DA87DA8FD07FFA8A8A8FFFFFFA8A87DA8A8FD05FFA8FFFFFFA8 %A8A8FFA8A87DA8A8FFA8FFA8FD60FFA8FD05FFA8FFA8FD07FFA8FD07FFA8 %FD64FFA8FFA8A8A8FFFFFFA8FFA8A8A8FFFFFFA8FFA8FFA8FDFCFFFD07FF %A8FD07FFA8FD07FFA8FD05FFA8FFA8FFA8FFA8FFFFFFA8FFA8FFA8FD0DFF %A8FFA8FFA8FFFFFFA8FFA8FFA8FFA8FD40FFA8FD07FFA8FD05FFA8A8FD06 %FFA8FD04FFA8A8FD07FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFA8FFFFA8FF %A8FFFFFFA8FFFFFFA8FFFFFFA8A8FFFFA8FD20FFA8FFA8FFFFFFA8FFA8A8 %A8FD05FFA8FFFFFFA8FF7DA8A8FFFFFFA8A87DFFA8FFFFFFA8A8A8FFA8FF %A8A8277D277D52A87DA8A8527D527DFD04A8FF277D277D52A8A8FFA8FF7D %7D52FD04A8FFFFA87D7DA8FF7DA8A8FF7D7D52A8A8FFA8FD1EFFA8FFA8FD %05FFA8FFA8FD13FFA8FD07FFA8FD05FFA87DFF527D7D7DA8A8A87DFF52FF %7DA8A8FFA87DA8527D7D7DFFFFFFA87D52277DFFA8A8A8FF7D5227A8FFA8 %7DFFA87D27277DFFA8FD20FFA8A8A8FD05FF7DA8FD06FFA8FD07FFA8FFA8 %FD05FFA8A8A8FFFFFFA8A87DA8A8FFA8FF7DA87DFF7DA8A8FFFFA8FFA8FF %A8A8FFA8A87DA87DA8A8FFA8FFFD047DA8A8A8FFFFA87DA87DFFA8A8A8FF %FD047DA8FFA8FD37FFA8A8FD05FFA8A8A8FD05FFA8A8A8FFA8A87DFD04A8 %FFFFFFFD04A87DA8A8FFFFFFA8FFA8FFA8FFFFFFFD07A8FFFFA87DA8A8A8 %7DA8A8FFA8FFFFFFA8FD3AFFA8FFA8FFFFFFA8FFA8FFA8FFFFFFA8FFA8FF %A8FFA8A8A8FFA8FFA8FFFD07A8FFFFFFA8FFA8FFA8FFFFFFA8FFA8A8A8FF %A8FFA8FFFD07A8FFFFFFA8FFA8FFA8FDA3FFA8FD05FFA8FFA8FD0BFFA8FD %07FFA8FD05FFA8A8A8FD05FFA8FFA8FFA8FFA8FFFFFFA8FFFFFFA8FFA8FF %A8FFA8FFA8FD3EFFA8FFA8FD04FFA8FD06FFA8FD06FFA8A8FD06FFA8A8FD %05FF7DA8FD04FFA87DA8FFA8FFFFA8A8A87DFD05FFA8FFA87D7DFFA8A8A8 %FD3CFFA8A8A8FFA8FFA8FF7DFFA8FFFFFFA8FFA8FFFFFFA8FFA8A8A8FFA8 %FFA8A8A8FFA8FFFFFFA8A8A8FFA8FFA8A8277DA852277DA8A87D527DFF52 %527DA8A8A8277DA852277DA8FD3CFFA8FFA8FFFFFFA8A8FFA8FD04FFA8FD %09FFA8FD07FFA8FD05FFA8A8A8FFA8FD057DA8A8A8FF52A87DA87DFFA8FF %A852527D7D7DA8FD3CFFA8FFA8FD05FFA8FFA8FD05FFA8FD07FFA8A8A8FD %05FFA8A8A8FFFFFFA8A87DFFFFFFA8A87DA87DA8A8FFFD09A8FFA8A8A8FF %A8FFA8FD44FFA8FD0FFFA8FD05FFA8FFA8FD05FFA8FD04FFFD06A8FFFFFF %FD04A87DA8A8FD05FFA8FD6CFFA8FFA8FFA8FFFFFFA8FFFFFFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FDB9FFA8FFA8FFFFFFA8FFA8FFA8FD07FFA8FD17FFA8 %FFFFFFA8FFFFFFA8FFA8A87DFFA8FD0BFF7DFFA8FD07FFA8FFFFFF7DA8FD %06FFA852A8FD24FFA8FFA8FD04FFA8A8FFA8FFFFFFA8FD1CFF7D7DFF7D7D %A87D7DA82752A8A8A8FF52FFA8A87DA87DA87D277DA8A8FF7DA8A8A87DA8 %7DA8A85227FD06FF7D527DFD21FFA8FFA8A8A8FFA8FFA8FF7DA8A8FFA8FF %A8FFA8FD19FFA8FF527D7D527D7DA827275252A87DFFA852A8527D52A87D %525227A8A8A8FF7D7D7D527D52A82752277DFD05FFA8527D527DA8FD20FF %A8FFA8FD05FFA8FD23FFA8A8A87D7D7DA8A87DA87DA8A8FFFFA8A8A87DA8 %7DFFFD07A8FF7DFF7DA87DFFFD05A8FD05FF52A87DFF52A8FD21FFA8FD07 %FFA8FD23FFFD06A87DA87DA87DA8A8FFA8A87DA87DA87DA87DA87DA8A8FD %0DFFA8FFFFFF7DA8FFA8FF7D52FD4EFFA8FFFFFFA8FFFFFFA8FD07FFA8FF %FFFFA8FFFFFFA8FD12FF7D527D527D527DA8FD36FFA8FD07FFA8FD07FFA8 %FD05FFA8FFA8FFA8FFA8FFA8FFA8FFFFFFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFFFFFA8FFFFFFA8FD09FFA8FD067DFD2AFFA8FD0DFFA8FD07FFA8FD05FF %A8FD0FFFA8FFFFFFA8FD19FFA8FD2CFFA8A8A8FFFFFFA8FFA8A8A8FFFFFF %A8FFA8FD05FFA8A8A8FFFFFFA8FFA8FFA8FFFFFFA8A87DA8A8FFA8FFA8A8 %A87D7DA87DA8A87D52FFA8A8FFA8FFA87DA8FFA8FFA852A8A8A8FFA8A8A8 %7D7DFD04A87D7DFD2BFFA8FFA8FD07FFA8FD05FFA8FD05FFFD05A8FFFFFF %A8FFA8A8FD04FFA87D7DFFFFFFA87D7D7D272752527D27527DA8A8FFFD04 %7DF87D27A87D277DA8A8A8FF527D5227275227A827527DFD2CFFA8A8A8FF %FFFFFD04A8FD04FFA8FFA8FD05FFA8A8A8FFA8FFA8FFA8A8A8FFFFFFA8A8 %7DA8A8FFA8FF7D7D7D527DA852FD047DA8A8FFA87D7D7D52FF527DA87D7D %FFA8A8A87D7D7D27A87D52FD047DA8FD32FFA8FD17FFA8FD0BFFA8FFFD0B %A8FFFFFFFD04A87DA8A8A87DFD04A8FD58FFA8FD07FFA8FFFFFFA8FFA8A8 %A8FFA8A8A8FFA8FFA8FFFD0DA8FDB7FFA8FFA8FFA8FFFFFFA8FFA8FFA8FF %FFFFA8FFFFFFA8FFFFFFA8FFA8FD05FFA8FFA8FFFFFFA8FFA8FD58FFA8FF %A8FD05FFA8FFA8FFA8FD0BFFA8FFA8FD05FFA8FD05FFA8A8A8FD56FFFD05 %A8FFA8FFFD05A8FFA8FFA8FFA8FFA8FFFFFFA8FFA8A8A8FFFFA8A8FFA8FF %FFFFA8A87D7DA8FD56FFA8FFA8FFFFFFA8FFFFFFA8FFA8FFFFFFA8FD07FF %A8A8A8FD05FFA8FD05FFA8A87DFD56FFA8A8A8FFFFFFA8FFA8FFA8FFFFFF %A8FFA8FFA8FD05FFA8A8A8FD05FFA8A8A8FD05FFA8FFA8FD5EFFA8FDFCFF %FD7AFFA8FFA8FFA8FFFFFFA8FFA8FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFA8 %FFA8FFFFFFA8FFA8FD05FFA8FD58FFA8FFA8FD05FF7DFFA8FD0DFFA8FFA8 %FD04FFA8A8FFA8FD5CFFFD05A8FFA8FFFD05A8FFFFFFA8FFA8FD05FFFD05 %A8FFA8FFA8FFA8FD05FFA8FD58FFA8FFA8FFFFFFA8A8FFFFA8FD05FFA8FD %07FFA8FFA8FFFFFFA8FFFFA8FD06FFA8FD56FFA8FFA8FD05FFA8A8A8FD05 %FFA8FFA8FD05FFA8FFA8FD05FFA8A8A8FD05FFA8FFA8FDFCFFFD5CFFA8FD %07FFA8FD74FFA8FFA8FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFA8FFA8FD6EFF %A8FFA8FD06FFA8FD06FFA8FD6EFFA8A8A8FFFFFFA8FFA8A8A8FFFFFFA8FF %A8FFA8FD6CFFA8FFA8FD05FFA8A8A8FD76FFA8FD07FFA8FDFCFFFDFCFFFD %FCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD1AFFA8FD797DFD06FF %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %2752525227525252275252522752525227525252275252522752525227FD %0452FD04FFA8FD7B52A8FD04FF5252527D5252527D5252527D5252527D52 %52527D5252527D5252527D5252527D5252527D5252527D5252527D525252 %7D5252527D5252527D5252527D5252527D5252527D5252527D5252527D52 %52527D5252527D5252527D5252527D5252527D5252527D5252527D525252 %7D5252527D5252527D5252527D525252FD04FFA8FD7B52FD05FFFD7B52FD %04FFA8522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752FD05FFFD7B52FD04FFA85227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %52275227522752275227522752275227522752FD05FF5252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227FD0452FD04FFA85227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %52A8FD04FF52522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %5227522752275252FD04FFA8522727275227272752272727522727275227 %272752272727522727275227272752272727522727275227272752272727 %522727275227272752272727522727275227272752272727522727275227 %272752272727522727275227272752272727522727275227272752272727 %522727275227272752272727522752FD05FF275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275252FD05FF522752272727 %522727275227272752272727522727275227272752272727522727275227 %272752272727522727275227272752272727522727275227272752272727 %522727275227272752272727522727275227272752272727522727275227 %27275227272752272727522727275227272752272727522752277DFD07FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FD %FCFFFD87FFFF %%EndData endstream endobj 1821 0 obj <>stream -%AI12_CompressedDataxœì½ysÉq(ø ú;`ÿp„»tÝ¥ul޼ó¥QhF¶¼Š‰™á3AÒ<$Ïûô›we¯Ÿž-쓨ήʪÊÊ»þîÿøí·_?{õ§Û¯Òéx2üÝß]¾¹½y÷êͯNzòõ‹ïß¾{ƒ _üî—'!ŸŽÐèüëù{iø·oÞ>õòWô+úå5¾ý‹Ã³¿<ùË“_ü ß=÷â`7oßÞ¾{{zóü—ú!xóêæü.ÅvÆ“ùW9žœÿóòÏðÂóÿ¿ 5Í `¯Þ¿|öüå¯þ ^Éí$ÖtR§tR¿þŸÿîöíÚ\½zúþîöå»ß¾yõôöíÛËW/^½yû«“ËŸo^žüúæGøÍÍÉ?ß¾xñê/'/nžþ‹{åúÕËwÐô×?¿y~ó ÞÿêâÕ‹g_¿ƒÿçÉ·ïn^>»yólœJq¯üæööÙí³ñüëòýõó·@û›w'(zþuˆß_¼þâÙoÞßý騛ê„àô=uÿ÷o¡ß0üÁÓ÷_ßäÛÛwï€ðaœ•Ë_ÿó¿„©|uGíx2ž¶ÜZ›NüÏ/~{þ›ï¾ùÍá$Ïåä'èwÿpá‰Do`Ã?þîöÇç´&`öþÇ/¥#o^½¾»yó/ðµT"Ð<ÍãI3ÿþ»Û»×/`¦iVJˆ§å¦þv?KK>µ -)Ÿ´z2×Qñ/ûìÝþùùí_~uò›W/o™lçoÞ}Ë‹%çqä¿ù7¿{ÿâöÍï_>Ç9¨jL·_¿zvûÚÛû×/nˆ\ô„þ77øîæÍ·ï`…½zñþ-ùY¿óòäæç[\Hà›×·/¿{õÔǯòÜNBᯓÐ`H!…ù¤1ò -ÿ›}3èߌÑ Åž&üƒ[á·0Ãß¼yþãó—¿’NßÿÛçÏú¬ùgþ‹q:»ÿšþǽ…¿{wûRh«íò×nõŒ§¿þ¾xxùìòÕRÿ-nEX/a}¼xõ#ÿÎ~¦ßÀëï_R;û×÷¯Þݾ\/na>Ï~|sóç[ó|vþìùíøÍÛ³ó7ðë³Ë§·Ïž¿xqsv¸yúþÝíÙoÞÁ’¿=ûF› g¿·7n¸É a;»yúü ,Œ^ÜþÛÙMoÃïßò§Šü–ÞÎnùÕ[÷ê­½úœÑ?ç6Ï]›çÖæ%¡Î^qÛWÜö•kûÊھ⮼ç¦ï¹éûÞt8{omŸÝüøã훳gÐÁÛÛ³§@ï³·ïnß¼ÀQ¼½}ŠKïìOï_¼¸}wöúæ RàõOgðÆ0’?½*½¡ý Øž=}õ˜Î?½;ƒýúìwè÷Á>wúòÕ»g·?œξyûâæíOƒ^ï¿{þò}o¤ÿþ|ûòìîý{õ——g·ÿöôÅÍý«ëùÓ›ð‚½õìâç/·Ýø˜å‹Û»Wpìüð®ÿS˜ûó×8ò·¯ožÞžódœËb“g¯pk~ûÓÙíýC HLHõ'ý_‡3ðÙó??ÇbD3šÿ³ýôÛžÑÃû7¯¨§´S¬ßô„n8ûá9 X–|ùì5|çÕ3\ 4×}Ÿýéæí­uþš¾ûéÕû·°D†³s·Dîçs^ëÜIó5ÿöËõkkô57ú†}ãð鸿á¿ç¿÷h~Ï¿z†3gý™{›'âîæé\ïÀï©ÙÍSÚ¼¥yGg?½ùãÍ›÷w/nÞ¿ƒ}G¿œ=½÷†ïÄGËûþ»·ppôó"}Olêðòé+~uòýútÞ×<Û4:Û¼Ålü»ÿ?|Q?ÁÕw?¿¾ýè.yÙ`)(@WüÿŸ-ZòY²×…ïÞ¼çü1Ô æ$Lé fêö_ßß¼€ÿ©gÏ_þ;õÝÏnÿãìP`ß ¶ÁÔãÿ aÈ€ ½{~óâÙó~8ƒ1Ý‘dpöúÍ«gzß!»ôs;ûæîöÇ›“!´r< ·4œŠÓÙÍkxáߤm>»º}¢X YöìÿÿuûòÇÛ“˜GlüvÖ÷ßþ|÷§W/¾?ã#/LÎ_…傇Ùð›×É®¿}ñ~õo^½ýõË^ ¿`a÷;ØŒH¦oþô?Ï‚ð*€þӷ»öõ/Dçé›Ûþ%¼Lÿ«ÿ~øí«Û@üë¯3ôðòÏ·/^½vh sòO7o^õo_ܼ¼ysBpÃüä9È¿½uÜöHoÞýÂ20Ë·†“ÿw‰aÆ÷íS”FÞœ\¼yÿö§“ï^½zah—¿2ì&(¶ÿñßÒ /¿yÉÚ~I¬¿’踯@ëû¿¿üŒýòN|“ž?ÝûÀÎïíKü»OYXĉž¿½ëëÉA~‹œòé‹Ûoíî!lH `ÃÏ`!Óé½}u÷UÜ“oºy}K8ßýtM-¿5„Ù¾g}_}5„“‹—Ž1þ2_8KA/ÿýË—7w·ÏN~¨m¿v¡À]ÓÉÅ3ìÿ~8Ÿà™áiôàŸ z.Ṃç@ÏõùõÅHO 'Ò“èÉôzêpQá™è™éiø ÿ| ÕOm=3<ø?Œm.ṂçÏu»>á ðDx=™žOŇ;ÏÝwàox"< ýn•ï.¿zµùjÿ®}y°O—Þè~«\•ëjª¥Nð‘‹zU¯'8§j^›.§Ã<Îi.óC¾œm„>MЇËv€oE@\¡;@ík m€ôíââêâp9^ÆË|Y/'úV¾Ê—@îóÜòœ§\sÉ9§sÈcºN‡t•.aRÎaØsšRM%åSHc¼Ž‡x/aâÎ0sœbeˆ9¦cˆc¸‡p.a~Ïÿ+ŸüÝ÷o†ñ´–„ZøxZ`MÌ ¨0EðoªµüMC«açAòG€L±LäµSxi øoµ‡?L3h ~ôÒÎ¤Ì -[ò$Œ#b ýû#b¼xkÃ<ÑažÈ0Ot˜':¨ [¬§ mïãQ±¯Ÿ€&¤Ü¦#wÔÐBO/®Œ7+÷}@Ré^†}ñâýíÉïàAVV0pì]0tÄXöˆ`ºÇ8¦1ÃSà©ã4Î#pà^ãåx5Æëñš…C -9X:Èú xòðK؇pÇ6I„Í’c3Áj°“.`G]Ásˆ×i„} R‚=W`ïM°ìÅ Ø“WðÒ5ô#ÀnM°kËÛ·Â&ža3ŸÃ¦¾„Í}È×ù:J,©äR -óÎqÿOXüìo¶þÍÿ!øox¢ Ó…ÿf -éßEžjW¢]êMôÓD?ÍDMø{ ˜°‡ ûÄ+ öa¼‚ÁŒ§Øßú?\__®¯®/¯/àÅóe¾ž®ëub¤ëx®ÇÃõáp¸:\.àœm‡ù0ê¡ò!â!fxýêpuuuyuqu>ÀQ5_MWõª\e }¼ -ÐëËÃåÕåååÚír¾œà¸(ph$8:Âåxq}q€£ä”s8Vf8\*1Îî8ÀRáx?Àás GÐ9D3œ©θ _„ƒpl×4W××4Ð -‡…;·Ááð&"‡™i¨8X. Dr8 4rû%ÿ‚d :‰H ¤R£E&H¤ >£Qé ’é:Ögz&¢Ò ©–û`¶ù\­Ÿa }Ìs±}†àùöé'" ”‰6Pæ!a…e3X8~ %ÌK¥eB ìx\ðÉð2þ™ê\IVªçÊrï€S -»#ÐAºNߪ åG%¡îä>X~@pX¸‡æ0Cé'cø ¹ï4+&±í¢+œìùºÑ.#± E¶,"‹‰çk‘…4æ!WòÀÂ’‡—Ùµ° þ3ÊßÀîè§H°6ø;Ó¿™ž2¯DnY‰cNð÷ £D9Ã'ñ_$Hž@.zIœô*ôA^|$’?€¹ðC&¤E.‹RÊL¼¶¿='‘úJxîåìð\æ¼ 8o!Ɉy·Á=ÈÛ‡è„ôBEÝFtÄ9ª$ gŒ#‰É#î[˜+˜‹K˜‘sl -34 0Y¦,Ã'±³8ã5îJ˜ßK˜i”¾Ìæk ÐzH0°|ô÷-¬šKX?ç0‹3,«ZËk,ÃZ‹@ÚÖáÖã%¬ÍsèÒLë¶ÂÉa¤¦`ÞqxX0¤ùÇ=MO²GyE3£ËC6›ð›Kb—üç‚Rz.Û€„»$b\ÒjÆpI˜j&ÆŠ¬5{Åg$&{MŒYí±[d¸øç| ¾Ûˆ÷ΤÑÆ¢}ÉÚêQ¸X»‰%_“æE¬Œ:vAì4«S{Ü`çiû ‹ÿ?é™öža\?ò)Û§óº?Ú²?yà~TŠ;ZšNœœý¹H\MÀŠ“cfXv±Ô Ṵ̂‘Imó»N1N§©šÊi+¥÷ëø¨YÀF‡åxCIoiÌÓX)qÊØ¦D4gENµå¥²rT¬¯ø|}óìöäÝ«“ú +Ãêÿaš" ÌØP¯˜˜óë„.µÊ´ü{¹\pˆçDñì–__þ€xîQõއ’¦ø Ñ€n*'ÇëŸ!ü”‰ý‡7··/½F´VÑ…„uvæé§gš,×Îd/ªdÁÉdØÁ“7ȹ 'æ@Çe££²ÒQ™å˜äCòŠ8ï‘î1Bµ@ý¬$Kd8FOPu@¥V[%u%:½gñç!‰õ³ÿì!DÁ–U`ÔôUêéÏOQ}iH‰Et«LêW”'سÊþWc]H¯,¹Lr $·²ÌÚ¥V•[ÏB«ˆ­ƒI­*·Ö¥ÜªFÃ(æÂ*†Âs1ªÄÉ ‰ö¿‰lŽçd*=y4IM¡•¬Ÿ Ïý ®@(¸!!€À@|(hÎá‚ÏqÒ[Iþ$Q…=Tµ3©Û…ÅóD}Gá”ïF -ø9)ᤈ_Š2~5 –”Héý—[A§WĔ٨çbîößk\ð6_^3Ù.ÙŽ°0"41 ¨ù`a:€—Q\5}>šþž 6iœ›IƒŒW •,VVT{H®dÉ2м¦sE«çBdL2éå•]b >`\€çëœÌ¸À,óÂsTˆ#dâ -IDwžY›'ûÊØrnÔbzuc‹ÒÌ\fpÁIÍ “Ée2“ ]Øìr£K$£KqÞn­…B˜ §îªYvî(ÙS87´¡tK2vë†:'EUÁ«‚邬 ’.Hº«‚3)çä/¸$•BQ QEIbÇï–üyØ8XCdñzeÌ_šóû“í)›ö2K}öŸAä聾kmãâ}á¸øwYÙ¸òÊÂÕÿ®²­ªpðYì\í\MvÿÍö-Üy—ö泌R9ú¶è×¢að?¬\«z­ -6)ÙöT{&÷Ìòðÿ‘î=0ˆ÷ ¯27ÂÒçe/vF³1VYèlý€e. œÏ ]Õ°¢á| M¤…<Ѿ÷@ž›@¾›*«ô‚Vç5È -™(pòÒãc" äÖAæÊlõBÙ)P2ŠÛLN :$®ätHdÒ5ù˜Ã2€–ŠZë55ÛDo%ÛÖLJ⨳WW4;ѤDà™LgÙàÛ€þÐdÅá:’q®’‡\µc|ûË䉷ýó_axø‘ó–M&f UÓh³ICÉAŒ#lTV³rHÛ—ƒ<ÎÅÎ1‰•YìÌ$žbjî¹Ì«œÃt|£íYdó«kV]Y³–ö¬%—t¬œfÖšáÌa»Z¶2ITlÝ -È ÉJÁ6®+:À.ÄÒuN’âLö®iª‰Å _‰Œ_‘ `ab6˦ŒƒÃ®È ÆX€ê¹=m`³+Ëúf$w6ò‹…\-äÝF®òn#ÕF>‘œÍäj#ïVòfVòn'/΢¶°¤±mpF´ÚŽýlkA[ØÐ>^œÍÒœ1žæìijSS«¯º2˜qMuÄ$a ÝÐ&Æ6~f³Ãâ!J òÎÏ':[ÌÝrŸ·eX;\D -]Ë¡K}ô F[6ÙêÊ&{í@‹:Ør¾²…ÜtÓÊMj²£í•mÕl;±|=8{+^Ÿ‹ w&n%I͸‰$Ï@Zⵘs¯h\ dÕe»îLÂk%ë.Úw3 Ѥ° ¸À -æ5(àŠ.)(€ŸsÌ‘­I[(Tlß³”á­Ú¶Ó™LHa=½¥S×D2*ˆ…ÛÛ¸•DŽ<Q'l©c¤™Da‚Œ.&‚£"ÎE™ÑEŠi!¤ ÷´‹+±R\8ÜÈVÁ!•,Ù»€¡6]âDÈqœ¥Ù -Ÿ'³$ê–ä}¢»$ ¼Ih›è&Q$mÙ¼5ðLXêe¸p/à> ]0—ç)æÉ¥i•)Å å©ÄÕ.¼™æ¼¾eÆp¾™0Qa=ëJæYºZ9$PüÄ™ :/Kš"DÒ¤ó‰%õ‰í8Ä–.±à£˜†U“zÅÔ'6ZÀTù³Z€—Wìb³Ó볘.ªo5MÙ‚qEùš¸t ¶Ä–Á‚*‹ªíò|`yfÏYG:>XpEјjâëL‡ ±Ì`q\çò\Bþseˆ 9I­ê òDû.òMý®~{ñ,!÷â\È‹+ùû—å=ð‰ªr6>æû“‡ùT–§È#’€ÛáøÐì "¤ó#' Žò`Ÿ>ô?æŒfo'ÇQ©J´ ¿X_jÔÄp%ú?›ÕX=bs¹€Uï¿?‰m]_—÷µ-íLK»Ú²V//,èÁâòöÌl{†¶¥©MlRfnKƒ³¸©6uiúÔ(U"©£/Õf ëÒâ2â΢¡²zN^_öô^“Í -gØêåí9Mœ¹—ñj`˜ør£öÔ¬Ó ;çb£h³Ù‘µŽ8ÑšÁ <ÎÄ#±5jèI4ÉjîYG¬l©ƒØ|ؔꩳT½IÕUÅÔÍ@d[Ä´:9ój·ixÀ•î²÷DaŽIÖQˆKªÅˆ¹¥ÚÔvÔ„{ž ÕçrñÈN诛֙•9åÙdÛÙåœ 'í\l®Wd‡à°'Þr²á wâý¦»íÒí¶(ìJQ£bŠ@c„³D¨-ârãCÞ]zdÐq!GÉ8¼· nKɆä8У è~²3 o&ÞNKÞ¿äûçh `}0†ŒŒ˜ÍÊuWœÞxª²Re¡Ä<㜶VÌŽqalÑ1BŠ/ -×Éžî:&©m ¿ónÚ•êU³D`UÓ§D“²8¬+ 1Rýy²Ð¢4HL–jJ‡…ÝéIÔ!U¥»2­!¢ñ ¦P/Uj ؆ ¬Bœ×‹ü^ƒw|-Tìý°8ÒÕí,YØ!jÍFDÕ»Uó¾T훞æðI”ð*[;›*.ª‹jäa+¥Eèb¸²çÒž‹Å#ñáýEjµUX†ôH5VÓˆ5‰Y…\•rZ8ƒ‹_»´3[ÏðæbÙº¶>™P\d›èïѺ•3\hÙÁiôW¦×wÝ^ôûAä™fÏlO§`µ§¸'ïÖÀ -î îû³ -o;,ž«å3\nÿ\lžó{ž¶}Hv¤éÞ‰¥´HÊ{) ¥Dsù°‚¿Vñ—^&Óñ³kéVSwS^DguKÖ¹¨ú“…feSca‹ è±Eþè~¯Ê²BÔ•~Rf‡¿ë´Þ³¦Ê’Æp©†ëMbDÓ=ÈÚbm÷Â4Þ&6 ¨Y€uàbšpîF‚aéÒÄ@ øô8-B Ca’§9'©Ÿ#ÅØDŽNá ŠOQ¦Yk-lL#Ð -£w@è˜ -Õ 8A4Œ£ÐsÛÌ뀃ü«~´ta ¸Ôãàãx!X,#âajç™qi*’CqÄqº˜ùO, -)t|Ô7òfÏË(#X‹Ùå8GÄÝ9B[j§xx¤ŒáS®‹ÇEK=ýòE“ëi ¡b‘:åxÌõ¸FÍADÀ&êKS™di¤ÉàS,™ŠPŒH¥Ät -ŸÀȯàrFŽøS‚Šž<yK9³U´†ôˆ1s_iŠÅ~‚ÅýÉ—=¹Ô P‹Š8(.ÂüûKï¦Ó+D‘ƒÓãY‹ïîMÖà§…ÛÞ»ìwÕ÷Áéï[ ~¡Ã“YÊ+ñªÆ«"O6©a“ɧîwŸÃ÷ Ù‡ƒK?| q?ÿPŒYú\°h­Ò… -L*ÁI´ýÒ“A*š7² âÆ&ïfpkc| ó¦çÝ,A|-“AÓnvWJkÀÒä³4ú¬Ì>ƒéüëÈ¿v&èá­›aaÝ$}}Ø ð¸væÍåJú`rèà²CÈÝOµ'÷ Áòjù|üR¸èéW² <‡XðˆÁ1 ¿º io!ìÅIúÕ°³Ö–¿­íomýÓ…ð¥-¸Ÿnì¾^,‡¬ >æ§/ˆu¼ÏGçî¶*LßÝÏÞµ%âÊàVËrÅÈšù[oð1>ô.-² 7áwÃs[ŸzKò3^IJFÊa©rÐa˜¢œrÁÃñ;×b2«¹sù)©ÕƒåV—‡²«÷“«É ÌN‹™®ú -ùš®q5UÃr}Šßç$ø-”Òá˜é}¨ŽNï{(æÑPó3ÝÍì’‚4%È'ùt M2PÏvR>1h™!>¸èì’Ä÷sÄ)Ï #µ‹Äj‡Û‰ƒ 9ºI²héQÛKáq)<.…Ç¥°Y -¾RDÑL0ÚD?`Ð<鸡f)|uOMˆOW2‚>-ÇíKòã>1ÏçÛW?¼ãò¬'ÿøüÇ—·ï(kÚ«!%Ä „„ÃHùø¤æŸ2I˜„TçSPóÉ”NAúŸ>[{HØ.ø±°6HÌM#át®c:™çÓ)Åö¹×'ö©•/XÁË×?eAmjÁÝ+„`Z¶b푌«{”­]­[”îÝX‹a[ëÂÌ4…[̦kuƒ éYÃÁòë}$‘ ¹pIõbªî ¹Ð ‹²ˆºðQC¬þp=Žž­ÊÄú?_ˆ£¸Âš’PW{ƒënôb.ù@m,W’tp°$NìWu;¾‘ˆ]kšÁd:ølÉüçV¥§ñ_›u†<à@(uŸ“ö':+Î)ÇIÓö/é$¹¦å3Jâ>çpU¥X¯a²VÂöÿí –Zg)vƒý2º_&#x×ç’›€ËöÈÏÃN#M0É‹ß%Köëô5XäßaÑxûs²a-sùØt>úcH;^ØŽ!íxag8†´ã…áó¥ö{úˆñu¼ø:ZÜÅŠ/ª©¸R*Ã"FÜURYD‡æ@íaዸ|¨ƒ ~pወ^Aá|±Ž‚ 26Ûº …à\×—õUöÊ lë”Uð@HÃ*‚ÀElâ4Äÿj7˜@ OÐ# -¶1=ª`Wàòd¾‡ed‹-8|(¶`)ÕÂ)6OìÕuÈÂaL §pÛ:RÅòØr #ÝRyWê<>vaÎpPy‚±µ´Ÿ¾a‡tãUýA<|û‚øñP~™hç]ÑÀ^´áÈÉÕV«žÿÍáîY‚=£;¯øµ1õµÙpyb$w4ÅÅ9]’³Gª“ {§îµ¥F:¼ÙÄHyÆ+ó"Çç‘yq ã¶JxÞ64ÏE0ób™%rè1†³¡!ðÚ¢–—Ql=fùÜ¢„¯Ô:HB ¦¶"~9ÎWc×0n ãÕ"§iK„Ú„ly˜!iJÞa–¿ÍÛÿ„RUÛ -U禺¯3ÒÏ´oì˜7踾ü¼—r9r‚êzáRO4ÃÂò+$Õ¤çW4+ù „4° Á¬jGPK‚ÚÔš öµ(MaUÑ&ÅÐýiF Ä+ܨ!×Ãx޲EÝWÝ¿“VfßÏcA6Ö@,ZVy‘ª3®¸ËH {ë ã—1Ï´Ë;Ó²ÌbqOýà3ÝûH£òâù¾g¹Å%–·§û:=8Þçu\I oZT¡0^öv÷:›xÿyâ1;˜6Ï'<ÃRBÚ>´K—’õ'ÖŸkD\Dÿ?ž–§åãiù·rZ‚0/ðR[ôqGµÆà—Y¶{Z~)&>-¿ìÌM@ót´3\ñýç>ÉóþQžÓR Z3ÏÇx¾Çx¾Çx¾Çx¾/…Çx¾Çx¾OÿóÏ÷Ï÷¹ó·¹ó¸—ÂãRx\ -÷ÆóáéûIñquâöv‚à“±4µ³œŽ˜P÷¹…úþªëm_]oKu½ÇƒÜSEz%=$õʇ;ÈÖÐýäà -¼­¶hF\âNvº2é)›ôt,‹švÕÏW9VM“T4eÉ^+õ$+gÊJ]·dW?„ÄõA*š¢|ÎÊÿ9»¸š) ÛR…Gåeý;ìB<}ÀÓ2X, ;´ÿwZ@ôµõOîš§aqÃÓ$ -Ý$ÑeÍŠÝÂ+cñC·íloÍøàUÃ=W^|ŒOeë$‰\·Õ?aóX  —úüåøáÛñg:Ã}qUÛC‡£›ªÕ-’é  Z aX”~¸²¨¥m­–´({zmaJ=HiV -U‹Oz°ôéú@‰9ï)lö,10c›–9Þé2žÎ&FSL(µÝÁ}„bC®1RTK…““p¤©–¶@¦9ñ™’÷Íô{Ÿ ùH¿ìP*û6dû›RÕ?ÚmÈn1<ÚmÈX -6äGò§ÿy´!?Ú­EÛ֢ǥð¸—ÂãRص!ÿý`¶&Õ2TëØ»óÂß{¡7_ø{/w^øû.7]¸Û-|ŠTO’Z¤I =OªW®tc}µØ~)K¿§¢ßœ(ë¢_Ã2-êW~ÔêØ[Ë+…qmðÊðëb¹*üšX®¹Aáþ{ûZð+áÞµÀw<²úZp«ä2¹’nù¬µ…râÐ>g³È¬u9sY^­ø»žÁû+þ.æràÉtÓiwë¸ÕÝîj’î^Mè,7¾Níòú¿ý—i’0Ø% û“½Ëdÿïr€aŸ,˜Àzêmò÷.Îd T1U«9Û| ¼ÖS|ît^æÜ«)]yé -Íý “oŸ7%Ÿ¯6 @ >ooWÂK7W,õE ¥ýÝJ}l¯¡Ñ ^_˜öÞ¥0¹ûU|Îìö8(ÃêDøØÅ0ßw Âp9øÅpðœ@y ¿œ°ÞïZñç>žúNü‘” ˜Ø‰®W ç×Ý­Òè^•Hwª\¶F÷©$˜ÓÌ%^¢‚W¨ŒtyJ£‹SŒæšr,𔂗¥éé–”î³Abºå’ÈŒDfæŠäeÆŠd%¢I™£ê=¹|²‡û˜é‚„÷]C»Î©X8ÿþêjô_ aw¹ùäÙÙZž»IÉY‡M‹÷WvÅÅ#ÃçÝ0²°F/ì‰Ã÷‹Üs»ÈÃ7ø\ỼUÄ]âûоƒÜ$"FɉrÃMݵ„n+ D½˜‘’\ðâ7Îsá,— `”ß‚™-‡~»âãRx\ -Káq)ØRøü:c ëp·/ˆ ’÷?¯ÞXOsjõ ‚¢ÃçDE}~…µ/u:×ýú uþ”ÒT÷ø|îÝWÃÊ÷ã÷¤z~úMà{{òÒ.Zšjí:¾ûúÎÜ+Oµõ“kgpÎãÖeªœÏxy¹]Û”©º–[ëaçæVðÒ,>àýºV>`i¯Ö•¿¹>­"’’UòÕ–Ô“Òý)š"Þk_5û[«`©Çå|õáRJb±v©E±®í&î‘‚¹$–ú“\Ã:j¥Da˜äíYŠa]ÈgV -ë€ú )½‘¤t)‡EÕ°2Ý9‘Sg&ÇÎ9ê̺\‹›Ï"E¼±×˜ù^Q¬­jMþeI¬eÙ©ÄE±ºôïd7C~24fL5ŸóOQdúc]üª¬šgûW瘀ÿIªlùï'÷RÞù@YýÞWçÊL†ÁÕЊ»Q“A4ˆÇŠZ_j+ö¶áãlÅûå¸>ãgWér蕹,®m}}óöòæqS ËJt «k›û¥Í¾L×¢PתTײX×ù°©×µ¬Ø•Ì.=nŠv-ËvIá®ÁUîª ›ôâ&³½Z^ªçu_M¯â W,"0ªíåª{í×÷‚•0ìùê·†í×ùꕾvj} ‹r_¾à×Þ]b®æ×îbð ;¥¿üÅb²öþv -M)ºÆ'†\¾t8ì¿(¡†sÉmŒ÷/å— ’sÝ$ü‰7Ú>¤+Þð¤èz|õ6þ-ôø·ûù`“Mv…Xø¦ÎLJü«ô®~¬£öƒ®Úû}Èç»AµÚd¨°Ó›Ç4Ó.ŠWÌt‡+EôÊ¢ã[ ö×ñÑ0þG¯7½Ù#q7î7¦ÅÆ1ÛA¶³õÝÛWŸÒª÷®®#ZYc ÷„°ú VÂJg­Ä®ºë=«^2=¹Ö§‹ÐŒfBQ#J7£\Þœ¹ ôö"3™2|üÞ¢YvC4Ûàâíºósÿ.Èuh¦h¤ËDº {×N5*U†>Hârô¼(š…9÷Á»ÄÍÀiðÃ"q/q…¨A«œQôÐÅj:¡9ZÑéBê9E -¥›HãçPºˆ÷I¶ÿ°h?<(Û·û½~÷ öÇ¢@öƒ@hpÇÞ~ÿÐv—oøpËÞðxæ>Q/ûЇOÕË>4¼ácbx¶ÃÛXÓȶÂK,aR -V_¢ƒ¶!¦«Œ*š‚ÌZ"¥´¬.´\WÇ?J¾u²‚”I÷j¶X¨SF+¾r†Y:!£)§Íˆg,"µ{6 á—Ø»6ÓuÉ[5€<”§Ã"©OÇðy:Þ/R†¦a¨OdëñöWö†¬ŵŸ^ö=öù[IØ»ÏRâ^Åv.lß…w?¤(ö;µÝ5±2ÓèÖ²yØÈç=»¡S•Åý+±I8ª÷R{˜ÅìÈÇYz¸H¢âûAlÉzªs}ýd¡ÿS‚*§á˜!•^ ð}ô½ôýô=õ}õ½½ö>§ÓõzÑoßsßwê}ï¡RqÙÇU/Wý¼ØÉä[Ì·i˜¶2›™ÊR0­Çë>C¯¿0çþ‹õ‹ñ4°òÐ#&à¿Äòjlµzó‘7O¤ßc­>*~·Ïí†ñ‹ØiŠ{ì Ÿ|n7tãA#OÂ¥Ëf"'ó;ÝIz<¿ßÖprÕÒÎàÍÂÜ»ãcã÷ö=ú˜ooïl_›PÎ]Žß*ϯxÖ/ŽÈÜvÆ>’¹ý{F«Ì·?ùëÓÜ~Éjbœ§Ä›´´DץÞ›tÒ›Ô'½®úÁ}<”ŸélÇ›ÉKüg»`ø2ƳkxIËšbÍÖ_ýQaºçN[{80ó#C=?wÍ}LX×Cþ˜ð ÿÈè¼UY&ƒãX'þ¡°šÑmEÎÁõþʰv:Ð)uóؘ?qã»e>ãí/Úpy×Gw]KÁY|­¨¯Û—É×bùÓ°¨ßLSðƒ¿Üë ΂ƒ\î¥W{ñ‘Ž©5.œOY gà+¾ŠÓ&Ó1fÓ„ôš/½êëj0—صÝùÅ¢J°ù0Hê,O1å„ÿ®ÿ#šÿÝŸÙþ-f¢-žóÅsºŽ(fý¹$»Æ¥Sê+Xô€RX8Ã2¦ôžš'MÚ—‡«¡[àZÆš0oQV™üué42îÄêeÙ\˜å»'’ŸãU”HŽÆo¼\ƒ.IÐ,rN!¿€)ÇÄñ ¡Á -8Àì£|›éfœíÝ™þ[¯5ðWF¸-Ŷ>ÀäV'™ÀZÞÿ1oްóq}'%<ƒ^ýìêÇUüÀqÅ{K wªõ«*Üõ«úd˸–e<‹cIÃ"‚e·²ŠWñ7Ñ-ÃSa)Ã"eyëÜ2üdv²7YD™ Ëðv¢‘ÅhàÄŠœ†9i S’ƒ0ôp§A"ž®%àæÊÅ=]š»´?±ÉiÅAP5,b¡4*èJXdó.sy—™¼ÀISÂÿó§„-šdߘ±œåÏžçÁÅs~ùLÃ\WÍï¹^ÍöðYÞÃæ{øhÿág|¥ÉÎsaí 5Í8²ÜŠ!g”虀ž¼{ãq>Ãß\üÍ~1X¬{ŸVú¥\:èžLЃ˷w0ßû ¿è냯/Þ¸áC¯ì=÷ôðcš?,8íÖÓýP)\}éÝd]eª.r!Î%ááÊ X,^ _%óâ²<5“Úº¼ÙÛÝêmé Á4z¾Ú›TòÁôp½×[TkR£{*ƒÞî-é ’‰Ó( çÂt™+ä4d9$ö%Ò‚ùÖø‚y3t£V#åÕJÑa½˜Ôœ‘ I2uHÕaeg&…§Q°Ð¥l; °'µûPýItLV)ÜÖì~ù ŸÈS¯‡~ÑòO—†ŽToæÓUŸûd怒‘ÿ×’œ](¸»IB¶zKVÒŒ¤6øK§I–¡ÚÉË1ì.ÙF˜–þ’ÕD6Îv—ti†<&æiV¹Fïfωó ì>á[¦#1“Ll…å¹üÏÿ×büéL•‰èÂîò% ÈÖÈ+À¥e9"~&ïêÚù8­câ8y:ƒ(Kƒ¨Åáòy b!¹.謻¢«G:ùje¾Tù\.S¾¦£6§¯t$Ÿ“Åó þ¤Â×PÌÿµ|‚~èއo8ß^[¾“úðý;I£þî¦ïûsuÏ#VoÉ7¥ÑJöǶŸ–ÎðGíp¼XIÁ–ºbÄõ¤ô i¹®äœ ÷ãù*„4¬´ï ÒÃiå8>¡Ž‘GÉãÜ»L›‡+×i8fµOâà±/‹ú+µ™ -›Kµ®ÔpOmn@-–Z[æ°vѯ¡ð~¾äÁþ Ф1ÏyÓbQ&iS9Ýa ~h*­à…Òt¿ ßrŸ$t„_$“L{"Éôé¡¶7Œ<Þ0òxÃÈã #7Œ<Þ0r$±øÂ=¯Òã #7Œü—·>^+ñ¸—ÂãRø«ÝRý‰uM×U >õÝ¿9gAÛÍ‚m«,ØÙ›÷•;«{zôðºtc^ÇÜ ‹Àÿ«½*öz³ -ÄÙª=§£gt\“àÄq3E]\n&.#CÓ@¿FZè­Ô½œâ‹|¿ ¯@™žzÜáÜʽ³ö³ùº’ÍŸØ,é\ˆ´#òŽeKà“¹ÊÝ2¢¡gMp¦™Æ5TŠŸW§ý…dNHîÄ">Éð¡ …m`ÂÇ(¬â ˜“&ÇÞaØÄ®‡/¯ò)•‡„®ƒ,•*'T^¨ÜðraǬÆÓ°0c^m/•;®oÜX\À²ñ¦F²â¥y,•,S‹eaäœZ»N~E û©ÇÁÈì1ÅЗ0O3žpžÅaæ!5Äob!˜ºÏ,¿Ó—±ÎÝz,mYE½PO{0ë^L÷–š×¤ aÇêt}O‰ù˜—ø·(!_lcjöu©Ö¥¿eí»×XŽrdX•ûÙ¬Ÿh|:Xd›8‹¸t58KÌ$@-PhM⤈*Þ]æøœèÄÎÊ$Ü~2‡å…D«(2(P¬P¦è!fí€Vñî²oWóá,‡xÉÇ¿ˆ?î!ØáÁïg‡˳z·ýÅ*ÑfY"x]$x/Æê°Î¨Y -žWy4yoµŽ¸Z• \ÎL»Ü-Ìž6½ì«­|nk¯‹ã,w¿‹åÎó6¨ëM<Š,¢÷kÀXP_{ßöüo,¸Ke±™âFû¹Å2¼øàV‡Jk%,®¦”Ú¢N¦º‘šÖ}Ís^¶ÏºƒË}ej,!c(,Oy ‹X"H'®®DDÜ}'ÞñP>tÄàûß¼zùÛ7Ï_¾{þòǯ¾r'ÿÅð›×ø›Ä¿ùíÍ»w·o^‘ôí¿¾¿ysûöäüå/nŸÁi´œ„pšó4Ë¿é¤ÖÓ†ÿÏÿ&ê{.“ôüágúßÿ?þOþå$Ÿüúäÿc7Ÿ¢FÅÔ—Rñ‹átŒðçv -Ê^ân$øÀ¦étáê]{Šï×|:…YzŒ kƒ—[ó ††0@Àªkú៱áØcÌþã~‚sxÙKOTÑåàÛ‚Î -ë71EJÄn ”ûØ <]ôÁ¥Âîò£²¶?/†ïÚvRY[X§ªëC§¿ëíz¢.‡†ßíä¿<ùÃ?ÁO´¨a,–ô‡V:AO|Kþ£<¦ŸžÎsJ'°ê2ê?´æ§2OÈ&š?YiÍÎöHî’c­|Â^áŒBìO€L=¯Ü;XeŽ/n–çXà =Yö ZÎó„ËŒÁIDàÂÒµn\D»Ç E -çƒ!ñ/rYèÙNѶŽàtÇIi#/Jn‹¥ÇNgØ löv 7ƈ&—´mÊò±2Ænò,ã…Säý'â8s-Tt%†P#·™`Ö,H'Ei“gA‹:eél¬µòŠ0ôvZP§4X&qòÂI€)í,Æü2^'%ã Œq¬y¬Š ÎUiŽ¢¬!€¦\¢´šö ƒÎ.À†›[ÎYÞ‡1Úv" Q€ œiÆ1‚•аÃ'¡ ®›Ú„âcË„¢æ8Ê -¹Š–èˆîØ„kŸV#‚qè<“-)‚–‹s. -lÚ1¾ßlå·)Nô-èy¨²Ž€ÕfÂ∺8€aÉû°Reð~&0i§&\øò¾,.èTíýTJÑ%ô}àŠI>c`CÂ3pšƒ ȸáÁ4OᄹñÌþœfιNBë9VC+R§ 4æbu,ð‘$ŸËQP”;“Ž6eæ±HoÓ8+Þ‚ç‚ìæq;Þ:Ò ªkÉ@ Y‚׉õ tÀ5 -ÞŠ5þelæJðVh–þFXX‚"ãœ0Š’&Ö”t—ÇdhëòkŒvé\²#“±@âÙŒS0·c0ÒÝ1ÌUºÐFàPdÕL0°>“YÇ ‡¡Mðj`ÙçÒt1òhÑb‡9m•‰0:›¤·¨?1p*£R™»çI÷XuZRF3'îìø8KÓw6sQÞÑšì}‡Qö>Ù „K¨% 0ŒÅPyëÌÄþâNÐu@̾†Ä<§S›à -,:a|ˆ0ëÖQÁ´–Òƒ 8’!Hɪ¤m-Ó¤„5 ™W¹F€ŽÑ6O8šJ® š³ºsÐU2/uÆÚx°óIb‰ ¬mVbãa¤ -ôKÛòâ°Ç³6‘ù´U° -]S啇`Tæ‡~äKE ŸÊt\¨D],“Á:ïÖC Á©UÝɉY [ß/Âû@g„_7×'FPÑ®¬›3°Ø‚À¨û4'ÿ,m'8óõ¤¼°åb¶; ²î7ä4ü-8,;*Z{¿ 1üéƒÀ~‚âÿ‚6&Ýó°y¨-ˆH1š “ƒA––O¥¤K`ÆKþšòùˆL-®IØ`2çäX!#h§ Îë†AFÏ@ÙyºÆZ˜ÇÅù¥jœe´%7‘`ñs­ -Rxåc¨£ˆ„ ïdK°Íxƒ.Y=ïãhR´‰G °~Tb`F†è$#Í5‚lnV«‚é˜gðÄ«€“‰ã6 Áq陆â%:Ë®ÚàjK›M œ²V*£®Nƒ †‹@Pås_œã$@Ýq²’A47³‚AnÊ#EÓ`¶7M*¢¥ätÈÆâý´ú1Þ )³ÊÒy$#Èt!„€“ô6›¡Èö‚®Ä9ª‹ï7=R*òFÛxó(Ë>³+K&A:‚«9æÀ{ €è;r¼›da“ƒJ7^B AÓS·¶CÖYL²f˜´%h,Ù¤jÇ*ŸëS“#Œ¥AÅ“RÏ4<%øý -lGßW ­IٱХ ;Yºì}L½)Dôæ¨À¹J¯à”S"U‹€1hÌq™' TO>jœ()éŠMlJMxJ¨m€^a´hÔ¥É9À.Û4ÊÀ"Ê.täZA0GËuÙ`¿9ÊâŽb¨ ªëþ Dp³á¶IL&ÃTQˆÁrºˆô˜JȪ“ö m›‚µ*7ÁxWëʧsˆÅõ Ø¢gCb'•6D G`оbÚ¬!˜F]³jô Þ(»â;0„I¥ÖRUâÊÚ¤ÂUÊÜÛ<²™çšÕ’‘QtІ ŽÉ¶]Q°¤´bˆ iʲ ’Ð ûnrª2¯x"à,rgf«ã¬&±I,õ4qšŽNÅ›MÑ(r¸æÀ-*Kr9ÐPnÍ1´½›<Õ½‘ƒW}çAÛnÙ+¢T0&ƒªéøÛ¶Ol«™ìÉ D·ˆŠ®Eñ–Q½ -u;ÅÛ%O=°U•ŠIL]ø)38Ò‘¬bRâ4ò×qì¼j¢šQlCæþ>æü.%׌Z˜ÊÙ*úæèLJ³) µx5(L3 êLÙŽ6™s4]&|Šž6Ö3 ‰ÞñPÏÚV\AmßyÚ,F8ëì÷©`mjn" Фb † ŒmµBûÃ…/7ëVTfÝírµië|%Èñ8dCIFñÒd?Ôjôýj‡H›fí@µS˜ÎFùRRÜDïÜÍuéTý=51øŒû™kMÎw$ìfZ†ú1êâ‚f8±í&ÕŽjÌlêavP.¡z;»1 áŠdàÜÆª‹[eR×¾¼[“u;¢[‰ \"¸c²= -ô«‰œ9F5,XWZ2ŠVlf©!/£‰^@5R7D°¢€0êÀ„Õ™_ô` æÈ c4mÃÄÁŒjå;lšëºj @UADxÖ×›(Œ®“™è3ÐHAš+IÁ"Ÿ±´Œº¿Zã8›LŸÙ¿È@ã -FíÆÆÁÜXh'`£-Õ †ª‚JÔÖHm“زª1dR6&†0ùY(PÐ;=ÚÆ’/«ê°Y^…B¨tÁëæB¨Yðt®]S‹ÃuMÓ_&Fœã,ëˆMc-ÁÄé°«Ë]f0éÎBØZ´mŒŒ<¯#ÏÏ«ùÀ°©•MF–)ØÁÑéÔÌc,º–îí[OêVG®!ŽàÒev[PµæÌ»  ;~R¬Uw7‚gmªŒ³ k׸i೺Hè@?eA©MñÊ™Z¢±’¬®ãZ’#,9†Ú»M¹Í¢Z–Ä u±J¢ 0¥Œ,Žd6‹Z•½a ¢T”l«3›=¾d³ùŠ|Æ@Ùi*^©â_ªùà2£èF‹;…X´ìXL2² mm:cbg‚¶ÍxD™˜GtÅ;©kTU.“Ÿ -ª -YÒRU Q­%#£ˆ,Ðô€d]àâW vÍ@¨˜šÙ@'Ī“Yd IuÂxTgF°HÚŽŠ³ùë ¬«¬Àü÷%cµÐ»éë4ËËÌfn‹˜"è;—¬'V÷¤Û¤»Ù˜Ï‰¤} júï–{ü\Sg¬ÄË窹甧¡oI@âMÆ×«úZf4ü_Þÿ:†K©–ÙÕB GSnsïùsx,mÐPŸ‰ @ -ƒe`P«Viv¦fµºCÓjKÓ–|(šl‰Wý~3£bÕ•Ñ,§ö˜’ö´ŠÔÉ”[aÿÐvLº»farÍñ‚l"LAåTåÛ4]‚ê)Âv!èÖLv"Üó:æ|ɧÄÃ^šùŸ²ŸP7£2iº+ž_sp}e` Ú-2‚:šÓ3›ã±ÎÆHÄ€‡ CG¦¦§¢xË*US0F¢ïƒ°¢°5€M£Z‘«8oØw·hC,I…îhçzÅð5epAìI5˜KÍM -šu±EÓ4+;•chü@µO²Òô WßÅäv#a3”eÒ$‘gl²ª‹¸”•±ᩱ££ÿ5ÓZfƒ?cÖÕ@³¦nMåŽ*þ[÷a5vU/t›Ìâõ”ôKÀe&Ô¢‚}Šºš»çÁY9=²ƒ'íRºz?*†f•*ò´ou§ ‚ƒÆ4Nb×B`V²ë©ÑœòÈÓ50 ¢¬zÊl§eE· Îòdl;ëY“Åh -a…*u&ÅÛjÕs¡©ÜT%Ð@¨ÈÇE•@ƒ…ÜS…•Ëy­<ÀÀluKŽlBªh·ñVë…WÊÈT@©b‚à‘¡^ÅÀúW¦öì¼UˆÂkÜÀºf¢6yúVZIy•ô.6íWvbšÆÔÌÑ Ò¯x¢ “LdõïǪãšÄ$_‘AèÑ¢š"5oV ¦f·èÔ9‡H› -‰ä9a`1¦à8¶Ð%£öIvñYBJk-ì‹ç¡ÆÚ{àtöªŽ}h=VSnkÖêCìTtCÌ8Ægžö·p„ÖÌ–D=^°í¤–ò(F!&‹ÐKŽÀœ,â /ñ‚Jåù5*¼.ZfW96hÒ¡Ì}ùýj6!7cÕ‰8dme ÚÕK¦›Ê3‹¡ !\ÙW³Õˆª¶c[›2²IÊÇŠîò&‡f¯Žªµv3 !0N%¡'ÄßI§×öxeÁlŠ…"˜SÐs'Øpk·òJ v+›áÁ<ºØ¶æ•™Ûµ3«ý?eV}2‚ÉS5 €=÷E£’ú©GÝ"Ù#%Z䌡ðAŒ@1AsEb«Ð«³u -"ˆNd 7ÚR¿’À„(c¥WмšÀ~Ë'¦¡ËxŽEůêed;»Ï «¿DÝ Vœ›Û7U6.FrH’Zè€ÆI˜j’y63îhÖø "’$ÁŽWÕPÚ™ŒV< -œ¢v ˆ€UpÓ˜ Aº)ð¦%]^ TM1Áªé&ë`ÍÒV–Æl«KùÅéª''À½X1ZYg‘¢ÞA¶¤ôѸ}Îî`ÑÕAQqºï¢…šsÝ“òÈ"ÐCjÑž ûÀ¤†Ô“DÇf<p–ÌëÑÒdöâÀå˜s&VcXrR.¥ ˆ©—6¤I1Œfƒ¿ßCæ«΋708„2ô`|EáÚ°Hm )ŸEpÓÍ4€¸XX_àÓ]€Ó4鮵°ä‡84ê+ŠnW n_›t/a QF€&2Ý3äùc È'T—pÊn C¼EñNA²7’å0Žód`Mzà[ DBµp6¨Äç‹Û_–±t ™ë€&Ï¥h §¡çªNw`rI€ æÕô^ÙYg·í³¥i"2œ "QcªRÕET¬ˆe0)¸ÊÁŠÀu"纨àŒóh›¶•Àš"Rˆ,#ö9è¹­˜o%Έг“f‹ü =›ãP”ñ’§›LÕÔ½‰™]EO`öŽ“) §–cPñ$ˆ¸ÀIXÝiØëöeÝ©LÖ Ò»])wvV¦Ár'æüŠc|dáí+ÊVàè2±B¶<( H祂ŎæÁ{*óÈI„`ýXjK©Dà¨4Œ1kUMî œa­âh,N -tL–s,•VåÐ&9#Z1‡ŠÅš.-U (e£K¼À:ö£ùfÇlÑ!£…ìɲ¨F(>&“pGK0)PV?¢ÁlÌÔÎ.¬"ªüÈÆˆ' -ά0ŽìÿPpu¬Fšµ¿“=ŽÉ¼£¨Ç‘CÜ,b –…™cÖs™åi*#±[cO³(XÊÖ2©ª\[G S£šb±ù(…¶r¨`Í5ÜÀê@ G q&©äj- ódSÓÐwªý#•#Â:EÑb”"I3‹*Ü~¬j”hY3ЉÿHˤ… z  ‚kP5¿Z¥¤8GQuGo{p)]CÎ"£‘‰Þ)¸XƈD¨“úcÁÉÚ5Ô,50f4'«²d«YºÛo{ «Ž¢1õ|õÜ QŽ¢QãMµäÕth£©Ø3ª\,àIÝ1Ö‰ÑÅGD 0Ç%5æ ÊI·xŸðÉ!cqKh™¼ðdá¼SQ—ÌT4tˆ2˜¾GQ¬ -Ô“Áª9XäÓQ÷•ƹm;pi=S¥,kõO«cQh°p^,­&ÀlÁz=SêfP'æl5^2e½í~_;‡Ê¬½4w -Ú±iÔƒ˜ÕcjνbQŒä1U¿{2M±-œê1slOÖ…Õçµ_>\¥H§pyMêMão£EhÆ šÒ#’U†@뀫P’¤ -ü=Ëæö_öJ–媅™xÜ€K³T -84M°—V Á“}$‚=f+ì•X†º°²öžÇ³‹AÓ’ ÙÌ–>ÑVu,"RFŸ´ªî¼mdŽÂäòêH0¿Sp³Ú˜«ðDÁ³Zîè§'ûHžPMÀ/«ˆà“úùÕ…û£ -×% º«?Y‚1ébÔØz 鯾¤þ`@¼>…ïˆÎ Žkªîš"¾Å; •XochTºµP•Ebè:â -€ ×Õ@‚F‘øê;‘ëZ f†!äZ‘I’¼0Uæ|Ä0\bÿ%‡úøS2æLz+2Þ+(#€àjeE¢ˆê{äh=¹j®¾À6L-”—¦&69U¨L]V{‘ÖaA!…Y^•boÚ¯q$ÞBñE»1ìR‹y‘Gt¯s¤ D8—A(˜þFt©šÜ•{8ð¥óƒ‡IsžÐÓÔ†„µ{bÛÌ9ˆÜR*SUÄ‹ms¦ JaÔRG«ùz*;ö\âgŒÎ¸pšI}Uð“8°#}4kÆÌòñ\ˆG+ðé •ùF’–z[”×R¢ݱz ô@…8çUǯ¤UðÈÅ×H1_+åyù}*i¥«¾m”ú!€ªJ ºj¤ËþP›éŠ„’ø®Âdw8à}HþâW²NM²nŠªMYmâþ‚v«›ZË©bÐ{n¨ÄuL«¶¸«I³ñX;;й -CGv,b‚[4âJ¨Ä•Îú¶}XëšLÛŠÒ0ñO =ý¹#±¼ÕŒç÷HNÓ@w3MX÷ kQ¡vÐI J• N˜®z·Góáb)áJ‚B•J(<´Êi² -ä¡a–«®{k‹*\L+¬(=ÐÉQðÈù5 ¬˜¦‡ÖµE¨Ä•Þú¶}\ë†BÝŒÆs¢ L߈1U¾Œ"¡©Ï-wÙXe¶k„UFŒŽ»[¥&6wUêŒâš“8EU 6O)¬ÚNZ½Ïcí@é­zl\`-XDÇX’ô@JXé­oÛÇå°nhÀ„Iid…&ŽH œašW¸e^¥î¾É.K‘•k×W*ƒ£‡™kÉ'´ÐçYô»$UñF,.¥: •¼¢¨û¶£ºŽaõ@ê"PðxšÌÇ HQJkF]逕ºÒYß¶«#ÝP@ˆ‹g>]íËŸ #yiIÜ(¼`BƒÝõdwæ_*ú¹–í,ëà`1ó#žKAؾ֮A=#0§ ª•3Š|[ôðŽó -kJlv ¬që¨.f׆)mµ¯½¥«¡ÜiX¾Í-¢þ>’%!ò ?kKxë]Dý-6ÉkVüx›áÝ -Ša<£öOî,À=4êÚC¼ÀL¹Å÷”Û<Êä¯ëëª. -‡³/¼þu†)mµŸ~‰öaÊõØ¿P99ÿ8åä÷b× j׃ž U.y4;ÛÂzøys§¤Æ%RïVàÜ·˜eÁRwµØ×^QDïîÿ÷m‹†`8¬FëÀ’Z±ÀŠÑaTÖ{ @BÐ{ëÚºqu¬[«úruËf¦"Þ­À#GùSéFVžgvOò¸ò˜fÔqID¿k‹·¼ÕÜJ‘oóÛœ9€tó/ÇV—ŸW N¬tÕ·í#êX·£?–ªHq,£ŒÜ‘w+ðˆv+-« 8ä£Tk[œRs@%mKX¶Åx‹¦ü[±: ô@©«à^i­cE’+½ -dêZo}Û>®ŽuKƒc©ŠSÌ>cÞG¦+┺™ãŸ°ˆÅ”t儜çŽ}ÎrSïõÖµuã}ñ DPüµ‘.Ò@ <\îV`t×U­È- ‚Ö«Kwæêè*…¢|ÛÂŽý%Ö”0‚5š®#¥:xVºÓš€JVé¬kë†eH·8šêˆUlüTånNdõáÞ6®„¥Š$LËfs¬‡ydøÖ”Wm³Æ ;¤&ßשQpzîHÑ’-a~½ -TÒJg][7ªŽuKc)ŽXsžkôWJ:dÒ:(:22'x¥Ug•³£f¥)Pi+wõù¶X™SikX;0ö@uéL†Õ%-mP #°Îú¶}XëšGÓó¨Ñ&Ëä†N\'Ë)ÊÓSyKÏF\ÉT W²€}Û¤ù,kJ‚G_š]±Ž– íz @¥®öÖµíãrX748–âˆ÷Hè@à˜Þ»/cÓO¦DJÑ4ÆŽîXylX¹`N«¶t%˼ÂÚÒ[û£§5ý–"ÙmµìÀè¼i®³®mVGº¡ÀÔFdJ\.¼JªÐÝ -ý r+*®9 _Æ;Z ¨d•T@ߣq•¬†µ¥Š ƒ­`yÇŠ®ŽØs= ÒU{ëÚúáÖ Ž¦6âÎéþªQ}¸í~Y¼5ƒ³AªÜú•$jª˜€J¹&Ä·…s§*y kJAkH§ÃŠa¨1¯z @%¯övѶ×°nhp4µ‘.‰²%Š-^µLÜ !™ØµT” Ë¥« -Ô±MÖ±h+•ž–X;°Ì6ªw3tœ\g@ý¾õ}íë¢mÕ¼+¶p ,bwKSe´š¤àÁš;ƒ£àԤ嬗<ú¥`Ë&ŽyÓV.[bíÀå¶6°ÖjZ`ZÜtaúzïkoÙåP®ÀÊâ‡T¹¿†GéùººçÀ®à{ÐJo˜#ÉX…J`5$b¬:µU[ ?PYΕ‘W ×â¸KX+EwpØLïõÖ·íãrX74ør-®`§Úq°zÐÝ -Ú¯ª(TF¼>zUFÁ´è99 ’uŒ¹­Úby€WX;; TUè¨w´uœ¥‡2÷ï+ß·¾ú¶}TézüÇRá𪋠“•°–ÖÝ -ÜïÅš¥É*ÖZAtKCžG–õÚbß¶Øå°wnRtjúaF…»XK3kvï•¶Ò[ß¶ËaÝÐàXJÞÂéå«ÕŒ¸ -Å Î$´9kA`Kg¡ºFÉ•¶*[¹¶XGJ=oŠ´ÃøóÆK¬öÃ9ÚýwîûTÊj_]Û>(‡u=þ£©p˜ÐtΨÀëÝ -,WOqSRoœÞÏHéªMPi¸Š°o›9Ûv‰µ¥Š@Á¡ßÆÒ±Žýú€Þ*uµ·®m—ú¡Á±T8LLJEÕS•…P*ÿÊÝÍA½ôRà–®y)©Ãx`Ió`]ËlQ0¥šì ˜¼o¥†çèO0ýüèO°ÞS×¶Éa]ÿê[‘Ì6 -›JÀܓũP‘ßjX0Œ -äÁÉ•ª”²nÛ8—ßcí@é"è`»¤c­¸ë•®Ú[×Ö×°nhp4õ­P带ÒbiF^G“W±Ã\+«uI`0_¥@¥t*¬Ú&XÖ´bKëóc`¿õëÈõy–= ‘Wz»hÛ‡kX748šú†àZ5ðûêuàqÒ«£¤Ð"ª:Éh>G5‰P×&uñ[[\Ȫ”ÖДÛX [.°Îýö«ÞƒÙ¼Z‹Þº¶}\ëŠGÓá°\YÓ™+óÜWoSSVóÎõ©ŸD ˳$Ãm[¹xz‰µ©†ÀÀR|~tžêæûÓ·{W]KSǸþ¿Ÿ‡ž³Ó^îVàÄå¿âj2¾bõhPÞ5ç\Ï Ä:ˆ¥M«¶“K³6¬è58–i ¬ZöoÑ2ë­oÛÇå°nhðåqÊ ”l%M8™Û%ØØÃКÞ"e1È£*ZÊ·Å´c^aí@éNŒ‚­ÐC:vªôŒ.'ÞuvôÔau¤ -K‰«ÝE9+ïnN®fjUt‡¬7°HÆ8; ’V’ø}ÛªiÐi‡E—,èÀ¡ßБŽV_Ìu@€FÚ¶iÛGå°n(p,ýÚT…)FY&¾:˜{›«9킜œÇÖaJX©oïZb!á¸FÙôq%«»håP¢¬$KúרdÕŽº¶}HëjðGSßPÚ·Œ*´w·'.nÊÝ•zÕݨ€Y!8 RVJSù¶T™±­°v ô@(Øê~:¤4æyÕ*mµ³®mVGº¡À±”7¤Å™CºÛ€ÅNAºª.';=`ù9 k?«O_[½ÊÚaô0Ç$;8Xw‡sä[&—Ÿ ÑµÕ¸j›\ aÝ ÿÚÜZ˜ï<öâC=¯èex%t -ºÜF¥j˜Bv@%kåâw¾mÁZ!i…µ¥JØÖjek¯Ñêz0ö*¾·®­®aÝÐàhÚ[íFÄÀ©Þ­À¨Ú4í†j¶Õ.öç:LI›-Z²·œÂ´FØòq}¿ƒé¶Ô%Ò^žÓ}_€JYU«­¥§áÜ þhj9ÊgÕyFÍœ\‚'«nEiz<½9ØqMåúž›W³‹/µ¶™«2/±.€£Æ".Àj^`­¥ÅMhĵ޺¶}\†uCƒ£©m5Y¡À¾Ý» ØnºKî pSßýÙÔÁµ¤á¾mmÓkv§ó¬å}XWöï·Îj{O­]‘÷ýÇhmá¯BIWÞ:¥ånLZåJÂÍbj瓬ߊ ¢Ãd·±õvóÓì¾Æïè!?ó%€Ž%¬>Æ0~³÷ª·Ô¾;„«1)¹ŽîYÒ0º¥ùnN-F…þŠÈ¹97½G¢ò½Ç -äQáU{êÁ°¶×F\bí@éN‚‚»/ßaíÖY×]¥·®mrÉɆuCƒcégX7/é´%K¥q`¼áHîD¡ aµPE¶k>j°š8YM·x¥É¨*±µôB)µ¥J]‡~¥UÇ:꤮ SÚj_{Ë>(‡rC€c©g|K´x5»ÚAñv€QoQ»U¿ôïJɤtÍ£ú{¬%^Ú>ÅÎŒn/whXÜ*3ª2F÷:ûÏ ÈÈ:[¯¶ìCr8×£?š‚†UX“Ê TQãnnâÄ¡*KT½< -Ä–æ€JZªY±l[í0wX=°—úpàÀ×ô,±Ž½0nÚ[×¶ËaÝÐàX*]n¨9Qñ}·[ºËÜ.*X®": fÕ¬r™S΃èöà›ÚTŠhÈæ"ÖûªúWhô”º¶}$áfÔGÐ̰–kÔê5cUÍlv'—\§]åê1VP®—”ÄSº©“ÈÚR%½5V¤(MÜå5‡µßáz @%¬öÖµíãrX748šfF7«& eM0èàØ¯eÃ;[›„hx^0…,¬•¼¥í´ù¦Pµ¥Š ƒýÍW‚ƒÏr\õ@€FÞºië‡kX748š‚FÌHíÄnp·Ç~°c=Åɨ“tíP5«TêÀÁÞ6mKÓ*CN´P`pq °hÏ©D3.; @¥®vÖµõ£U¤ -7—n1ÍŒy·6¹Ú†n]3ÛUNzŠtã•>¡ÍÓ¦m¯ÊbX=pN¾J•p—Hkº[h6‹š[©}X†uM/Î¥ûÈ2,)‚¿ÿßV•äR@0¯3ë<Øê§”9™¿Ó*­”ãSYLsUYÊÔð&ÝeU–2M®x‡bu@§,z°ÕOqX{¥×_•ÅõÖ·íãêX·48ŽâX¦sÏT²×ª,Ì%Tp\3‡5õJ+8.q¾ûª,8®W-‹VŽV„âj²x°UO1„½ÊŠû´¯ÈâºéÚºÑtœÛ‘I]DÌ-ª*lY<Øj§”…OM§’*+8¶yÔB"V‘© qû¶Y/¥ôX;ÐUdñ`«â°ö*+®¾"‹ë­këÆÕ±nip$g¸DK+ÓŠ,lµS°¿À„bReÇ&÷®úŠ,H‡8­Zz‘áì@WŃ­rŠáìVÜ×}5×S×Ö©ãÜŽÿXJ#väX«g+ëÖA­n -_2Ø+¬€qJ -Õ² RA¢'}Û¬¥Õ=ÖìÕX<Ôê¦8¤½ÂŠë€¯Æâ:ëÛöa9¬k -IcDÄÓ8«¡&$¶º)¸Däâ ^a‡&UE}5$ÃW-“«±g8½ÅÌj±x°UM1œ½ºŠûº¯ÄâzêÛö19œ›ñ¹îHŸUë·J,l5S8™_Rª«à°4”ÚUbA°ê&®-Zã´hžaí@W‰Åƒ­fŠÇšúíFÑ…}›)À÷ÖµíãrX748–îH‡@WÑ´‹[Z YTWA &+»J,ž¦UËäjÎäë$k¶Š)§UVñ_wUX|O]Ûà4Wùÿ±ôFꛕ±µ*,K°ÔKA`IÑ\àÜ|i\µ@u׶έm°v UaY‚¥^ŠÇj•U|\ßÛEÛ>.‡uEƒ£jŽ´Nf­¬bUX–`)™‚}‘»ªÖV¡%Ôu¡UXh|qÝ®—Zu;Ðj°,ÁR-¥£\l'ý¶«À⻹Ü&s¿Ý£– ð¿DºÝÈöpרj¥Ð%n¢S[U¾¨£ÎHDÇû¼Æ\–m뤷!;¬èõD¶Z)k¯ªâzà+°¸Þú¶É±aź¥ÁG~"N¹ð£º -,lµRø’r½ÓAªªÐ5…F@«ÀRè6­©©mV ´†%VtX3¾ÚªM£^­‘f·j›»wm±(Æ‘ÖtX–`{´msÕöcYõ@€J^íí¢m®aÝÐàh*ãD:¨%Ye£n‡¶•'”˜¬¶ö ©Üa:²ÔKÞ[Ƥ«Ñ¡ìÀb ×Cc(ºF§Ö?ð_g˜¾®ýô-û€ÊåØJv£E5)Áƒ£ž±xç…*‰zâDyþnE[2E#8][<”7X;p¹¥ ,¥R–X¹¦Ê²Z}eÙ×޲ʡ\àß-wOâö|PæÝ -luRh'6Õ4¤¢ -Ùî%×U_áKøâº-^ݧrœbu@¯Á9p—®:Ö^QÅõÀW_q½umݸœ$¸¡Á—kp¸·å¦¼^}ÅC­N -utTÞîˆ}–ÄqW}…¯ÇS¿œµ­zÿ§ÃꀽúЇÚöï8{E÷}_}ÅõÕµu£2¤›ñK}£ë¤G“V_ñ`«“Â’ã(¢­·Ó%­Én’Óê+|5žjÁÖv²Ã©cu@W}Ń­NŠÃÚ+ª¸øê+®·®­WǺ¥Á±8ä\QëHhõÕB)´’†4KEZI½>V}…îÆËtkm'W]:X¯¾â¡V'Åã´Š*þû®úŠïkoëÕ±nÆ4õ Yý¬‚U_ñ`«“Âî9z¥¢ -e Ëo®ú -9ü“εAºÕ)ÅꀮúŠ[Õ*ªø¸ê+¾·½­WǺ¥Á±Ô7<Ü¥¾N¯¾²„J©ñ+ë}£Ò¶eU=´ú -»üu´ålÑ.åh2°ƒZsô'˜~~ô'XïioëÆÔ±n†ÕX½ÆZõ¶:)Ô¿IÍRQ…”ù¬å‚¬ú -,Q Ú¶àíÏvõ¡`u@W}e –´[Õ*ªø¸ê+¾·®­®bÝÒàhªådj´ U_Y‚a”³Œ£Wß—xabeRö.öØb¾+Wý Ú–Ns‹Ý‹¶½[ZŸ‹^ë³-ºg‡t]´íä[ -MqÃŽÊ}¬öŠm¤ÌVï™Bk(Õž$[IÑ싨!ˆ||X€½´ÅÝk—*VtµW–`ÊêXbýÿÙ{ûæHn›_ôè;Ì?®ŠŸº=i¾³ÿeÉInîQ씟“ª[·¶d­ÖÖ±^|´Ú8Χ¿ø$›Ý=’zf¥ÕHn»lÍ`øU<õ#Pã,vP¶G·ju4¦Áal1{÷–Ü+CpÊ’Âg‚*·rùthKs5`F?˜ -˜§Öªü`})‹0|­—íaUî•\²¤Ô–|*õªÜ+õ`û²V}«Óx,ÎAðÈôf帖D)<Útá˜3ª1orºÒ¢bÐä7{û’xj:ßl–&{`ɽR{Áªj²äS©{¯r¯ÔíËV(UBàùGSÞ4’üfEɽRƒK– ×¹|ã“ò©µþéÀ’{Ó…¯ÊÜÓ„Q«=°Ê½Rƒsš”ºÑ’O¥@•{¥l_¶B«4:ÇRݨå¶×!ç^‚ÓÕ9¶W–M9=by@͔ÔZgâ°d@ÇaØb «˜d.YRê6K>•ºû*÷J=Ò¾l…RßêýGÐÝpv¦—*ªÜ+5¸dIᡪœ:åSZ]ë$+yZû(ßR6WߪÕXå^‚S–”ºÕ’O¥A•{¥mU¶F·´:™ƒGÓÝloB¬r¯ Á!ù<иü„˜—DF®ËW>‡/2´ÁMʯâ¨ÕX°Ô`ØBnÀïˬ2T#ЕzQ¶*ÛãUµ:™ƒGÓÞ°Æ6+–%K F²½Ìl³(K¨Éãísñ10ONìÊ¡›Ë_4EyKö°*Ëì”/û¿+oÇ FHÀ<¹½ÞP•í‘-­NfàÑt7 Âæ8å’€eNA² Tý=™\°¿Î. XlsÌ]]¶ÍºWÕj, X†à”A`Øjç'ýw=¿íGZÊõUí°Þ,$kK­¿Uàœ:…ŽÚ\ƒä*ÄkKtIÂ⌧sd¬ÅW\SûæzX­·Uà’B¥n2gZ©ûîs²ÔƒìKÖ¥ÒäñG -¯3xëVgÏÅœ—¥— *-é,Ye\+ŒX -Ú¯ò²`r(~UþYØ+­öÀ*/K .TêVK®•zU^–z´UÙ¯ªÕÉ<–îfºÊÒ\ò²Ôà’A…Ç[¼ÐRð4p³>g½)yY0$Ô¸QYGbM^³Òj¬ò²Ôà’D¥n5g[©Ðçe©ÇÚ—ì*S{ir2¥º™n”år-9T0ÚlÓ*ÙV€XÏ3JfÌ9V°”uÓl/5PW;ÚM³¨Ô–|+õªÜ,õ`«²Ý4ßËtM3ðQαç%7Ëœ²¨ðxû¤ûébÐôA•›óCÎjZÊúJ()­ÖÀ’›¥—,*u«%ßJ=‚*7K=ÚªlWÕêdK…£–c‰’*¹Y†à2†þB=Y³.cEàþÐ*e‘ 7 qe¶zPIÐRƒK>•ºÍ’y¥î¿ÊÒRµ*ÛãTµ:Áÿt8jÔ»üàYÉÒ2Wç˜vq˜¥hå¤iU–€ueiaŠÃ¶¶ZK––Ü uU«%óJ=‚*KK=ÚªlWÕêdM‡ƒ Òf#GÉÒRƒK>°Ê®“Ù „‹6?CQ²´ðñR\'«²ùEøªÕXei‚s:„ªÕ’y¥A•¥¥mU¶F·´:™ƒGÓá˜-'Éœ¥¥ëþ˜k•î¹Kæ ×çÉ’¥…÷jÌJUemÌé„jA#ædB½¿Ä, UêFKæ•zU––z°UÙÛÜèd7Ön°Ì9KËšò©ð˜{+—d^aüŠ dia¢*ÂkU–Ä?jµ–+Ò4åS©ÐteQ•ÑǃW”Ú£UZÏÀ^fi©Âï>vÕÇÊc‡Ëƒ¬Â1-^ŽÀF¬FÚ©!çœHo1·¡¸& –€ö:°5Ã²Ú e‡´ZÓŽÜŸ >K¦$ˆCÇtÓ˜ Œ<°ÂtX*ë:$Ⱦª™`*`5° 3vL4ƒQDh>ø¶^æ™uW6q`FDù”áøM`A„D9ñƒ‚mÌKê}…['ÞŽ=¯S*.…+KÖ"ð®âL@:ùÇóKn’®ErR»@)–‰à½Yr!‰CE‡4!»0±vØŽ1¦#Úä€ðq•"jwÂúè'H‚‹rÒ·:Ÿ³Ã„´õŽRéQGQ5ž×±ö†… mˆi`ÊgG*¶›½›à$YÞV¢IÈo)º’G[ñä3P¯cJB­0sòZê#7AO鎙ímA–!ä«%XñÒ|O×üˆ‰¸i‘[hy9ºä2á–.VìŒäÏ ²J2Oâ¹ÇV4)šôV4!gNžôr ãèwVw,Å9Q^òmm‰é4UÎAÕ–˜“á‘6í'ÆFŽY• ZD‹N‡´’tT§}IÓà¢J‹fáMšÉ¹õœP¢5 ‰) -Íä×êZö-.Q|¾ß’¶9±l'FÍ®$ú!Då Б׬Ô8[…úÒ¤ÆVÜ´û4Ô:/€KÁ”˜~•÷ÁÑæÅ:æc + ù³/ÿßüéêíá͇÷?3¿=»¹Ðøæëë«¿Ç¿%¦ß4><ûñüªþáàë_ð‹jå§ïþç_þ|~AÍü±|¤SæÿüÛñ××oÏðqpüÜùë?üûòâŠ~jhX7ç?|¸={ƒ†N°›“Q‰ÓŸÎ/ÞÞœ]áw½úã_¯nûßð¿ÛtŽýáË¿¾ùòâ—ŸNÞ(:ξ¿:?¥ó©VWø×ÉÅ©qþ¶:øê"W'—\‚†2ÿ×§Fåú‡ÿ}vz{xýáê-íðúßs1zÇ‹BEoßß_¥ÂpPç“£ªÚö³¹ØýtvþãO·³ËÅ÷§_ÏßÞþ4¥Tú“c4ŸHµÂåß{Ço³ñø-ãsÿp÷…MÞ~¸ùaî$Üœ½ÿp1ÃåâŸ~Y×­›‹Ó'ïÏþ|sö>œ]Î_äQ­OŽ¡ž‹ÞÕ‡ËoNoOþu6ÿ¨«|rÄ®®¿»=¿=}€öø½çÒÿ8¿ØÁAOŽ!6ÜR¨OÏæâ(Ug"—ûÙyðêžÁo*yãì5v÷õž™ßcx~õÀÞ«…E”ýäöÝõ‡›Ó³¿ÜœüòÓùé|´¶Àêzh|=&׿œÝœÜ^ßÌÆ§¯ðl»æèúò—ë÷ç·s6ÍS €EþûþãWgïV_ì¹¶gmoÑömoÑö>EÛ{QÚÞl ßËTöfi‹²·oÊÞ»›šÝ‹¯¯Ïß/êÞKd‚‹º·¨{‹º·êÞáÙ¿Î.¾ûéäíõ¯¯àŠOÙW¨ mÓËЄýZt¡m0yµÚl7z-ç8 -_ž‚7[ÿyûö«³Ÿ`@[(u¥g“ þròáýûó“«CYÀ—"KÏ^›·óùáÛç`ˆó™Ïß>‡µ`°ïÜìúÝ»÷g·‡Ÿ‚§=Ó¶ÿ†1|AþÂ$¼O¯/®oþûןD™ÉŸ»˜oÚH¥— ô¸¼ÿåìô›쇗'ÌöîyÿáæÝÉéÙw§'ÛÞ Ò3\ ÍÆŽV÷ÃÅÉÍŸþýËõÕÙÕü…›VüôXn‹äÑõÕûÛ“ì+¾$Ý„4úgî$ýgö¬üç9”M·*{®7«m–åÑ5ç'‘Aþ~}~u{œlJÏa<û.mÕã$\¼ yh'¾ß)l)6,RгHAË%ɾ1ƒÙBÍÏó9ÀÏÏÁæ#bæ#bž‘ÙGõÏ€jDì^#òÀÚÕˆ¨ýgÆûX¾Ê ø‹óÛ¿Ÿœ?¤m½¼3óäæüö§Ë³Ûù+õ»=;_Ž®¼½™xëí÷L ù·³›Ï0“/HÚ–u¼Æµxº,.C;’å—}st}}qxsvöŸÙ7{ë/ô{ -y®QêÕ¹F¹Ùí¹…w r{µžQj=;Âüæäíù‡ù¼$&5íU9{ÍGäí|Džã4›ÈKQ3ßž_œÌ÷‹x‰*æß®o~ùéúâúÇß^jò -ÙÚ«afóCröœ™½ºË…™í%3k^Ëê«áaÛ"í3›Éâq»7K±÷Ûc¶ôµ÷Ûc¾ùBùv¾hü2³(Ìö^²(L\²(,YF‹ò€ãOEoÛ9ß?“×ýgÓÞ{¤¼"‰a6•í½Ä0“—"1|9û–äè§“««³‹ïÎ.ÎN·± L+~r$¿}©µ+’ÓŠÏv}uþþ—‹“ӳ˳«Û¿üò‚£v•ÿ]M>ªÁǹëÉŸæ H¹øó•½çõÛ¥îÜg^?“—Âë/O¨©Ù>&/Iö>Bóß2z/…ßm±Wö}×ÏÖË÷~×ÏÆä¥ìúù1ºŸ&ñʾì¾Ùóòîæúr¾—þô†¿„œÊî‡WŸæÛû¤ôþÚùn¯çŸQ×Ï€ÈÉů'¿Í^b·'7[1)ÿéh6Norè¯/.?<‡z8ŸñõX•î¿æÑÏÄoTë‚®ÎNfÇWœž\œþíúí|ôú -Ï`?¿šmU>9=ýpùáawˆzáª*Ÿ·›3Vèg£÷öíùíù¿¶@®Tx†Kmùß_\lãï~ñl*ÉÉÕùåɳ¥†}©y蚸8Ãì™fwújœaæc²8ÃìÍRìýöx5Î0ó1y)†×ÿ€äü$s‹;Ì&ÓÕ⳸à e¶üù2Üa¶8öÞæÉ ¯Æf>&/EfXÜaw˜}9ŒðyÅî0[pÈ}çõ¯Æf>&/…×/î0ûÅï¶Ø+û¾ë_;Ì|L^Ê®ß7w˜½¾ÿy9Þ<[l¹m™Ç3­áK̸…ಠ-O¶ -O—Mä,ÂÓ à™:I¿âì#o¶³|͈^Î5ßXöB²½ÊœÙKžœ…£mÁÑüÍF~áh G[8Úžs´?Ý`ц¶ï í „ºð³…ŸÍág‹€¶ð³…Ÿ-üìåó³úRçÍv~¯Œ­ÍFþwt‡·l›9Û&üž·Ílä—m³l›¿Ÿÿûìâï'¿½Ù.p½X~Gïl¹våfûƒÊP¿ÝÂ%´ªñ’8ßkKòZ³Š¨ù µÿiEÔJ}¡Û•rôÿvEÿ}AŸéïôÃêµ¹lÏd%/=Êû_Be.ŽK•%Ê£v~õöìÝùÕùü >šŒ³“Û¯¶`ŸUgXºËë‡Vâu'ˆÙê>½øÃ6ï¹§þ6¸¼_ýÅ`±ïì`뛘}3ߊ%ì9{;½¾üåú=‰ß|x`³¿<ÖðÐÜ¿ì ³£¼r/ˆ!Ì6þ<Ÿüü,`>"¸ Õˆ˜g@d¶ðç.ÔjDì^#òÀÚÕˆ¨g@d'zßÌ]Ž™—tt>}ÞÀOm=¾9¿ýéòìv¾Üö»=C_ÎÇN»n3€å:ù1®“·Ë˜¹¦–å:ù>ô–ëäå:y¹N~¢­ˆ eÝ~±Õ¶\®÷ê -yyƒcµ\!/WÈŸré–+äý›–+äå -y¹B~|ëÄ ½B~Mw­oÏß½û0?“ÿ¾³‚-Ñy)Ü`vzº÷nÞ‘¸÷Ýviþ•ö÷Þ2-îÑõ)æWó—mRï“£øÛÙÅÅõ¯sñ¼8ÿñ§[ú½9E>ÜÙhŽ«íïBÊ>ÚŽHu£Ûbt{tê}MOà -ÃùâÇ›³³«/H^9û‚´åó¯¿ø×ùõÅÙí7go¿¸¾9¹úqöQùR¬qÛ0ÏÅ$·˜äžÃ®³˜ä“Üb’û¸Ó:ξG:ùÏùå‡Ûžä«÷O.ÿÉÉËÏÆé삾leò©j<›½ç«sVÀŽqD?—GÌW¢ '1á‘ük2;½ÿåì”Îß›Wèá¯^·±f>vi‰ÿôï_H˜ÛÂ\3­ø Ûb¹µQjZñ¤™¬¹O`’Zì6‹Ýf±Ûܧ@ÁJ#v›dÄaóÍb·Yì6‹Ýf±Û,v›Ån³ØmöÌns‘ ¯Â…b1B=½껤ü½@+Ô« ÞÁµXØ–OÂ^bù‰ö<‡Æ|D–{æT¶ï94¶õ´ÝûCóU¾irq~û÷“ó‡ìø/ïÌ\rgìëÙ¹äŸZÎÎgGdÏÏÎô³}??·=j^Êѹäúýž/çzkj]rNm3€gêüUäœúî§“·×¿.ï}ÿ1 §^'úgx)RÀìüoKDþ'ßB³Ö|û ªÀþý D6‘ßæ#òÛžs€}çf×ïÞ½?»Å–¸9{»ŸÞ™·=Óöÿ†1ý}(»¯êkÔöeU>ͥ XE5ÛcÕlÉü‚r+Ó~6»ŸÎvå«ËÅ?=Nv>N¿ž¿Ý‹2•þä5ÊÍÆh¾ÿ2ü6˜Ì—â[Œ‹QãÑqò‹QcoEáøZŒóYŒ/@ý]Œû{ì.F}ää‹Qc1jì³Qãöd ߖŤñ¢o›OŸÎáåSc²nC.çcòRôÊv=;OÐ'ïÏþ|sö>œ]ΗÿGµ>½n¶oíÕ‡ËoNoOþµEŽºÊ'Çìêú»ÛóÛÓ,†µe¥ÿq~±‚ƒ:ŸÃw7'4»__ŸÏÇ‘Ê3ÑË=½œSa‹ýúîæúrþ1É…ŸýÌ~?ãözþ²^?*¯5mÓkÊڴŶ¤.º½%uѓඤ.ZRmÔa_Bê¢'1ýãÃÍ.ˆ_¿<;â+˽²…¿ç‰%/ÉSnÙWajíÙΛ‚ ƒëä°zN²öúmÓËð!›Ï~{ÍÇãÕúÝ£|}Fñö•[Åg{ú,Fñ)‚Ïk¿­¢ç4‰/êÞ«V÷¶aì‹Â·(|¯Gá›}ö/ -ߢð=7N‹Â·Ÿx, -ß‹Røfçsx™úÞlô}oßô½=r‚Z4¾Eã[4¾Eã{ßÿº¾~ûãÍÉ|JYÔ½=P÷Ü+T÷¶Àée¨{z- -ß6˜¼Z•ïU> ±UŒøžÇ%½ÆŒ³UÖ%ãÅ'gKÏûY2^|¤8›ó@¼ -Þ¼äïØ[6öî‚T@yÇü¿¸89ýù‹•€®99=¿ýí¿·° ¿¿ýíb¾Í-•þô>ÜÛ¼Ù¾ï;k+d^Úfú3ñí¥Ih³ï†ÑívÍžŸ®ï93êÑkbÏpÄ.æìg2gï ¿{M÷¶/žî9;Ø—Âf»¥½ÿpóîäôì»Ó“m$ÒA¥OoŸ­ˆËâ]_½¿=yèM¾Z+×ûä(þúӱϸ‹ ß›²G…å¸Úþ®£l£íhtPç%Е™½yOþs~ùa‹+žRþ“/5ÓÚ«Iíågç‰:» /[›«Ï&c}uÎ|ï8]‰>‡×yðqbR‹´÷< -àöoô."Ò>ˆH³9T^á?ýû—뫳-„¤iÅý òX·–§'¢à"/=¿¼´ˆK‹¸4w ß%Fõå¥W齃à´È‚‹É|1™ç(«¹ òó|Nðós0‚ùˆ<;ªFÄì5"øAÔˆØ}Ö~~ dˆzD¶½ŠÙûCóUú_œßþýäü!óå™'7ç·?]žmñÈÈrvîƒÛó³s>"ËÙ¹oˆìùÙ¹“~¶ïçç¶GÍrt.Gçž/ǽ¼Ò¸²Ð“³Ä°O7€D¯ðíòlÝó¥¯>§îòÒÜ’déNô–$K;l¨U›þÝô©@殚O¹ø 8öýPû U}ÿ°«ÕË;Ó.O¨©ÙÙv^Ãàø°¿eô^ -Çx…ákŽj[R|ìïVj^MŽf¶Þ±ïI>>‰!êãôÍ’c_YÀîK³ÿ×*[‹¤û¾`™ÇRýã¦ç^\ùö5ìBm/iÍk|)[H­çÇF-Âör=Â^ú绳›?Ÿß<½ÑçåÜ'ëÕì;‚Û“.Îþçv&ËAO¾æÜûk´…ýùÃÕé·/ˆ›¬Ãª]-tö"éì//‰ÎÔÂÎ^(™>—‹ +;-ÿÇÍÉÕûw3^‘Øzß1”aßM!»Èj/Aþ”åú$èbùÛCØsîË‹‹E×ùÈ-¸øjn3€gê|«çŸ>ûò¯ª}ó§«·å(€ o¾¾¾ú;5ÁiJžýx~Uÿpðõ/܆•Ÿ¾ûíò‡ë‹ƒ?|}öëJ>¯ÔçÒ¿íꛃv\«I6]ûÐùhøC«5)ßë®UÞ&Ç¡žôþDÿü¾ü?ôáèו]ýmõÿþíê-AÿùíA·v«@ÿ]ò§¸v]çýõm«VùGü==hòÇ‹ƒ¦*ÐÔ›\…ŠóAÊóçR(ÕîK4ÒCùxqPT.uNËØ/Þ|Oè´ëv€4ýy{àWø|õÏÿuðÙ›ÜÔ%}.íç/Mþ6ù’?_iýá˫뫕µÊp£ß˜vãí€é|öÆÒ:­”]ëü`@üöìäBœO¨5÷WeþN»ûìæªûîâ\R0iüåæüíÿ8ã›ØÏÞdŠ® -Kóþö†’ÿHÄýÙjÿðšÈ¦.ù§+HûùpþV˜Çgoô´9dEº¹íCýþ¯_­þ{j|#ÔøF½±o>_}Á5Û7„6‘ò´Þô  7.Àïm®Ìsõ{˜ƵË;°°KatÁ+OÞþxF|­YýýüêçÏ{N9“ýŶmWÚaf/µn­ò.M¿;åWÚ®3€ÎøŽ~7kÓù>gÖQY½ÒzmZÔ±ko55©Ö:DªâÖÞ(ú­²UÜ:êh© ñm¯¨Œ§n 0ßuð±Ëß™ùªè:]Jĵ¶Ñr«Æ–EUhÿ ˜È#S- - M)MÝ(“£!Àv%!h»P¨Dx„e¼Ê0N3 †àc£¸’ÁÑd¹sšN|ï¢áñ›VÑú€~1Ñ*®£ŒdU§VŠx¸Â$ÀçWʯ•¶èÈa(T »Ž+á7BWÊ¢aÔÖ °*b¸èÁu¼cZªL•xØD<*ª$ô ß0*tŽ2j2y -cP«ƒâ2ÚÚ4«^wÒˆ aÅß1JXs‹C©ëœG³tb#sšé 4`ì -4¡½ÍuBˆ+&“Çì -teZT­€°ò­áJL´DŸXìôj i/ÎÍô½åÂò¹éLµ›¾zꢩûHãhú¤¡6ýX>LäDîi¶馯ÓÒô󒦮©ç.MoSæ7-@S¯¯RS/SZʦ_Ë´ÚMYîLME™nšžpi5=m1ýuéCÕzcU*ns˜'n“ÁÝ`ž¸cYfŒVyx1 8†L®ßX‚¨Ñi;òîkêíÇ´™ìâ¦ÞƼÕ]]*qƒ¦°ž}•öCâÌWœe˜0á<‘G>`NMÏ2ÿ*e2‡k -‹c6èó>:R6­ “M]š¬ -Ò–]…Tˆl5„Ìk@ý) Ý»Ufëéëé“~×e°˜ñܳuÞ¥fëÜd -kŒëG ŒL`DhÓN1=Ú˜˜Àedb0wH¸Ì¦7š~ziˆê¼–ùKÌtb"ºÁR:U–’˜V;äÕË$¨,¨áy¶û2Þ©.‘– Âýº˜éu˜¯ûžF™Œm¿É2_O{Œûa¾n¬Ù¯ú†íÛ²¯@w²›LÞ|f5ÚŸNN§êM,ƒH]Ž\¤Î¼@É …Mǘyœ C®â¸ŒvQ%¾#ç4oÞ.r%00Ÿ9XËçZà¥'g;Ö½gìL%Ø”Ì, 5¡£DäF‘!2;Å•˜cîüjȺêbë5Ç7I@I”MœYº•3#XAÜ€)qïT1Ë'<§fhmTÄߎèÜPq³¶Á€ª°)µ:üñÀºuë‰Ðä/Mðžæ”DKLäuxyðŽº?<$uá¿>`l±ƒ4O³£º–H¾]+Hô4°È-ÕŒQ[ŒD9Q†Nû@¹…± "ˆA‘ –4‘¥IµŽ¼8p +DïJË£éÍYûÖurú+0-Ž:£F|ŒrŽ„ 1£4‘1(‘(‚¢³Öƒ¡E9I|´^Ó?¢ÃFYŵQ‘#˜dCž!ä¤g¢ùŽ*mÍ'!¡ˆˆxM û<‡é¿ñYc¼­K8ïä¨QØ;Mè€6z®cÖN˹GRžà?ÝzÞ†K†Ø©¸Ž°·ËB´™é¶ÐâL£ÝÞbøÄhìžÏ…<:È?5RØ®¤²- -;›;ð"TÒ~ÁèxjyXŽõ,fÃãnyó·‘¥Là†ŽÂç«b¥ãÄÖå¨ñšÛp-ø=fÝi#ýtT"6pämÑNÒ÷xG‡€F˜$ V•‰„85ÄLZÖE‰‚Ž¢)ËÇQë¯Á¶ÒQ¢Ä´I{;Ó¢g®ŠÁe@‹Âécù‰+«U©‹öq>%²fÜ•§’eLÈjU†Èt¼ª¢´žñ ÌQ¾L•µ«j¦x6™uz-Wi¶y²mW–ƒWÃt2M™°íáUEW¼¢™¬úE¯¨Jè‚)Ç -•ÑÀ4…#¤§-þ¥[òcÕBbÆ澬²g2çÑXµJÛ  Ã×vUíì%Ãô¦:Ï[Éùž7£íâªß‹Ø­m`7+Ï ³<¡ý~O`ãCb `ºãQÉaC§Íªg+ÌyäÀdXø*s&¬2¸LϼÀÜ2oËŒ/ñ½LC=gÌÜ3“la®Ì[ ïåoGvBߥ6˲Ԧõ¢EÍ`!m$Ùäcd°›j§=Þ—6‰aJõ¬¢’Õ -?)]a9Í„/U‚aa^}©Ìߊ|É’©"sAPQl+IU(­H± FÓA‘ïù¹P¬V½8,dmU—GâôÑÁŸICøª–²=ŒõR:†ª¹Û L6“DÇôì»l©ÕÐ"™i“e¬Ë;iIÍN‚0ÛÆq «RX × ža¼„¡0a¡ÁªLÐZ؃‰àeÃÈ>É<5j#Y‰'H‚X»[1Ò¼°Á?xŸvÉC:*5न“ÄîŢÝG4,–W̉ØõSw€…2[~ídNƒiÓh™yËv '²+Ö%Ú>÷¿¥ê}íÔGÝEH?Ž4Ô2Ò„NM¹ œ§¥ÌJž»zêð›ØÒü¢¶ãÃ0-)2|Y§´š¼˜Z6?¯÷˜$*ŠHT“Kdºš_E{L¡Áôe2 gÎt^‘9&ÕEnWö¦è•ö•¼ÄbwÿøÚ…ÆÛ·K=G•Œ-7ƒë/F]] þJ ÄTGèOæg4ƒ Vi•k0^¦ñ:N—zL cr™RÔˆæ˜&c!É)ÕòôÒ™°G„_í‰ñ~É5ËŽâÆ}¬·]ê¾lÍáæ «á×2ž!˜ð žàkf’'RvÑ«<Ó…)qûvÀ¹x½Ò¡/ †õ4¦0@±J‡ŠG‚"¼îK€b‚«˜o±a¢bªã“%2Ufžžé¶âû™´Ëáɾ©7DÃ;bðõøàÝÁ}/î%Ãû‰‰Z}ù _ž…Ëñ¼Ê—ý—ñ2V¹"¡STQÙˆGDÊ5F„<&ôñV@Évo§Ñ†ã:B”EÏ#d 8&<5Æ|å^„¢5Ÿš2±1£ã£4£ñM7Wš²÷ɰaº¦GÉä°Ù´2ÓSkr¬m € äøÍ4&Å'‡ïô|ŸâRqzÚO‚±Ô8’.¦ÈDNÉÓ?–g¦2ÏX2’š²ºMYÞ¼üM^ÿ‰ÔÇõ¦Òa-<¶9M ÎSÜ;oºlŸ£Æ÷寇µ†ÍN±/‹™^6ëÀóÉh¡²À)ÎÙtBøVE¹z&²¦}µ¢3”ÆD›ïŸ—Ð@ […,¸K¿©f4ðsTÓÑòÓYžîÚéáÜNx$-4±AÏÖ;ê3]”ßá¢ÜöNÀ$ ¾éÃÕÛÕûŸN~9[]rIñÖ«û¼ó7ˆ"bn-$@JÜVL1x[AA$Ù­EÖ¡¶¨Ö.âUÛA``tk‘!ÕÚRh n/6P¥]®¶µèÀ ¶½ððٛćÏÞì$@@ÏÞ^„ Ôv"ˆøw#XÏßE Š»‰l'ØI˜ÀßIœ@Å -©¶ƒHŠ; ¨¸“X‘l;Òåö¢…ÔÛE¸fñBì6Û Pƒ?ö¨Ìf4[þ¾¡‡âk6‡ËД®¾¹9¹úñlû€:ˆà û4hâ®3ƒsv:+ŽPÇ|yi½cÏ*Z¹ŽA“É^6ü÷˜/¬ø×\úX°×s›Çrñ+hé™ÛÒžŽ øëõ¿sT‚ -7ÓŠÓ{n'÷ÖTÝåÁ4õ¨ÒÏM=øÔLßqž !pà1MQÚñANàñÁ°™Cö††e(yHL¾¿ ÓPOSþ¹ú5µÑ7‘†Ðw“†À\WV†T£ÔOLž—~ZšâEÙÏ΄f¹„ê—ж#A¯:°3}»Â.Ô°ÖŽÅtÓÁuWMþB’nÀí¾3$ézøÒO=B•iá|OLÌ+¸Ú+ŽnT[8A¦ká½£æ!EØE9ò4€KeÚÄ¤äœæ# }‰[œ|paÆHH&3Ûãb•.× öå©W|ùQž]haÈcF\>Ò % Àb ?¬›¼†$;ÉÃŽÙL¼˜ ‚¦Á n”©Ä ø¸g&M“ÇÇt%DBâø€ñÒ|¤ ¦\ˆ±oò|0mòµÕÏý¯¹AÜOé&¥ŠLŒ[õãe¬t\UH¥y©0çiYñŸèª9̳ÔOtž¤~1dŽªãQqßi ýš²ÛŠeñ;­{Æ·'Žv•çåø üœ 2Ü„u²J7ÐŽšÁP˜tšÉp›)JÍïB2=é4ù×~›ÜF?ËM¦~)„’‰Hûõj&kÚL×½™GSÓN³¶š $ØL µÙ@Îͪo6lŽfÃj6lµf¸#Óð·Ì~µ½C½MOTÍ”U4™®*†Òlà;_:Îþ4 -8Á-\…œG˜}:ò’²L:(|džqr_!S-s˜?Ȧ;)/SÝY1S³²"ÜYé°þPçßêŸÒ8ªrG}?yõhäÇzÌ©…<¨ã~àýÔòÒV”S¼üf¦®-ó2éa0 -áDøMwýHsß=6S”u9ºÇó´a:§“¾ai ¨» -›¦ŸŒ Ô ”ÒÿÝñR<ä ñ ª›Lßt g £©eí|8ÿš,ÂéÇK‰1>$ìO)@T¿¥È主 t'×ÅCò„N1¡bQ£&ó‘·Bõs3ü}JUŸMÝéJèñh†ˆL·}59Ípîš4yÞ@Ye©*ì—t0ºMxlÄxã䔹»ªt)§÷’f sLËjL—ÂÎÛåÀÓ 骪Չdz[¨CD`+|LÉ•.ý¢´*šâÃNîRåÀZ#\\¬pÇðÕëŸ)œƒpPe+¢e L1U˜f,Jv‘M¡ˆ|oÛ&‡ÕÈjmqÃD)>°¯Áa>Iãkú*LAM‡yÓ³‡Kg‰Ì×bÓbùI®ÛñqÇùG¾£Fˆ3•Ösvj’g[^™šãƒ<™À€qaVÙÖš§B’³º“^ â~0Ê'Ó5/™0&¬¥¨k(Àv©¾L­¦k}ÝN“±ê®Ù0ª2KÕàË4U86¦¢LT5cåg©`2l<ÿÒŠŽ«é‡DÙäù«h·©‰·ËîÕ=—-p|ÿÝˆŽÆØÈw#Š„ª¢ØÕYM•.8(+X lç°[¸Ws`+D0RÁMó½2âÁþÏKl4XÏ5‚XÔ7Tíܺƒ©–„'ä"èðtç^çöj;ñƒŽŽ´G­¯GºÞè9M²~ y°î·‘«Œ¿‘k‘Ç‘ê#žà„ëp¾Ãlz[ÎÃ$cÞü}Ì}8¥Ž9_ŒyÛõÇ[ 1BN§ '‚¥~²ëa‡Ÿp#XÙ'üþBŽ$çcáIlóžp%öLšð%6sO8/܆QnâNrù“Ø–§Ó´‰G‰9yÌ¥:]§Mœª¢ÓŠWU$]q«Šú›!ùO9V½™&G|÷øæR¢ÓÕ_nÎή>*½PÌù…HH±‚@ÿÈaAví#ßË©8êSÒ uÑHìx›®•uìnbo>;øÃ©D­»VKPD^ÒüœOa˜¾Ê/Ä_%½GŽ•ô;maeÅ“¤0Þ©Ú(Å›œ8‚ÉÙ…”„°k¹®P($îÚÚ³ 1à4…DŒÊøNs`s¾»Hç–¨9åN‰ið1xI¡Ø§×Dûú‡#ÓÄw Ç×yn%½P@J äˆF¶€õ¸“Äßhrz¡(ÞÎrpmIàLLy.‚¸Ê£³‹™q-{ï)Ž4’q†•Œ›/ ˆ¢9 ‚Ø“¯CÇÆecʸ|)¸kRJ\B£ãÀ4màƒ)©n ø¯ï¬ÜÉDÜyÀ&E…@f¦ˆ’’ãf¢I®œ™@VAËÕEªPž61eòðqê…ßz´m4å{Î.ƒÜª¤Sí¦¯žºhê>Ò8š~ 2Ò¦j† ܵ:Í5£ÜÔ8ó¬4ý´¤©kê¹KóÛôœV ©–€W©©—)­dS–2­uS;DSQD¦š¦'›DXMOY‰úäCÔ‰fƒS)QL.žÎ„˜QgRÇa-gZWmJb1^³ªàm¥ši_ñÞ“ŒeóÑöwüánêMÌ}PŠyAºãÈ6f:¯†³)·²FFElÅ®ÛI—x¾N-”Sf\¹DælMam Ó…D/NKb¡ LN¢;¡2Ÿâò,R+1-*«uú.%ŠtÊ$v’x¥ãÜL‰a×™…bJ-DSU  É -”Ú@GÛwÄ<=gÞÁh0^fRi¼Lñ]ÞÌÓ¸NÉËqÏâ–Ï3ÓgJS‡¹•ô> Àäû®L¾fÎbsZ¾%çU eÙ kR’}[gò²‘%Ä£”ñ]ötvÖ×ËS/”'»©«8%جjVjds2‘+IãBü<Xrp\&3ml¤n°£då]—ƒ~cJ(s°¶Þ½2†|ʨ˜Ž—7•$m)œÂ0ŸrÉÇÔÉüf•7l ¾vÇJt¾%´<²Ƭ-9Ï}:ß»\'‚,˜G*9$9»…pÑn•iLX-KîB‡6ñcñá®8v\UܼbôŠØˆ°ò(4­CK¢toÛ²“<õïCJx€F"¿à«.8(™Þèi1––g—3*ò4¸4U–3à˜–Ù›Ì¥-OmÃ3-iG§ëèüŸÏÓ#||ÊÅ€¡¤ …ÂÄXÚ˜ -$c™e,ÔLåžÌž3wÎÌ9sÝ©x5–ÀÆ"šPŸIä¨%­²’ý‰™ßÛ,–´B‰¥0ËicúÎIäNfHÌ´R*áÙ­%®–Ù^æz™3öŒ13ÏÌ;3sqßôõh,`ϹC3¬ìûáˆè<' ‚W·)¯FJ¬t‡œ¿À -AÚ ´ËHZÐZG⽓[d4<qÅLãtr‹L›cNˆxm„–¢ã{e‡“„B¬:lLa'i˜:$A“]59­Ø§°3]Î'½¤°s%…I)ìÒ¡8¼NRØ¥ˆÄÙû*Bg†i…øû‘ä°ËÙþ §Ò¢:jNWS»’jÐH蟿pÊ+“rØå”uìBø~”2Ø™ºDÀΧvvU|ÍŽR;A9pÖ»”Ü+¥°“ü_%Id -*­Ø…”ÀN¯RÎÇqþºNr -)Îq)ÙÆÂ*×Mù뺔Êl•2¡¦‹Våd©:§3«”¾®¤KKy!%å 'T+NXš“×¥cF‡œ0,¦ÜŽ&Å£jë}lÌÉëLJ^×¥äu*%¯‹*ÕáL€’.ÊX:•’×Ù8J^Çó&”È¡UâŸ:Ì^§ûìuGƒìu­.ùuKÍ:å©4ÎéëüªôŸò”•rú:½ªpàôuqÕcY²×¥ëÉš3­I o½.t£ôuv”¾.eâc"[‚b -³²â~U¼"'«bÊ\焺le®ë„…–ÙeJªש’¶îh˜¶®«Lú<ÊÐ¥¼u Ê[‰Çf¾ yëºUµS|vÚ€ƒ¬u)i[圧²ßã9›hfœµÎå,Æ®/¬¤J.ÄcNeÇ „T›“'w…‡õ,,³¹Ìå2Ìl0³ÊžSfnš™é¦\v’a(Hè?~f‰6a˜%:ädyÞID~5†à«•) R%8á!YT%£*yV­*sQ§JÈùZ»\f¼)±e¬Ö©/å(UtÖ+ZhFÄÒŒ‰)±­®¢·fL’͘f›1Q7cªoF»¢™î›f¼µšÑÖkÆ[³ïÝf¸µ›éÞoì!È©Te¿,¢…ÅÀEä(gˆVÌ…|ކ?kâRÍ”ÉazV׌yá C4®4Žr†èž£6#ŽÛT̸3ꦢä\½ÎûÈ´Üd!ÚÅŸ¦F(áÜTHó¬4ý´¤©kê¹KóÛô<8ƒéש©ª>W]ð7e±9ôgs3:¾W…¤šž¦†Ù¡»D¬Þؤ“j—ª³‡7'‡©*7´ìŠd¨Fl¬¤–&3ï¦ÞMiÇ5õ–“1·mSíÛ´³û2iïI¬0ˆJZ'†Ž«Âhš 7ªDòúR™« ³°¾J •ÜоUSn蜜{áÜЙþ£ G›^.N¹¡íª1ó&só%¹Ð’\hI.´$Z’ é%¹Ð’\hL¤Kr¡%¹Ð’\hI.´/É…™=y¾¼,ð½ -HhpÙÃã)V$Žñd}w%^Aª+4šu6¹ö' -e7F-†mÎq -$꘮Ú幯ΕA„òèáLº½ç6²ÊrFyœ+ü°MÄUñÑðÏ™¼,¤Ò:ezÎ1Üò"rMyûHs†|ܵ>…€´im«ÈEÑJ,-¬·‹{ß^¹¿Àú§4Z‰ì¥âËmŸéÄæìõ. ÅùüDKΗïÄ9,®Ù!N¼wR&ŽÚJF•Hœ‚Ymuivx•Ä9A¥ÛmÛcmÒË0%0Dâ¶3D¼’º6åÄ•RݺK÷ -ù‚!®»Ð¥ÐäØéäÕ)“ø§å H8I`–ÕG+²±OÁÐ aO+žÂª ÍMÊš+»¹RÃÊIR*\¶)…å ¶MºŒwì`BSbÅ5—y²n”-W<—h%^üTù -¦åw_¼ê!pQ íšÉ14›[tßMùܙ᫻¬G§YÜðZßÙqh¹®ó)R» ï³_džX|Tz£"Ma`k»éA¼#M<ãËa›)ûBF©eÆÙ³IЂô„uoY´Ö›Àª!?d–ˤŽ¥š×È@šïJR,´•œŒ8s1yƒÂR%vx­cî&²Q‘/è`S)õµd‰¶2´*G´KYýS,»ä²¨DG¹ë[Q.ÑòS+ñ©Äþ.gü–dŒ¸hjvj‘¼þ*ù‘1»òÉ~_|ã›\@Y¡9c3X<ò:äÜþ Óí¸6ßþµ8X ó·„]JñÏL)§à?åÿâ±T%ùWâ#¹!%ôéA3È“žòüÛPµ0J=-I†0“¯}”4è!¹Þð`Gi®£f‚6'ÌVéÎS˜=¦o0WÌV´Î¬FJE\¤¹Ð/Òx—¦‹é\Øç¼Õ{¼iÓó€Ú%õ?Æü]¦1¦. Ü)*””ÿ5Õ•·K˜TÙ³˜-)“gp%BO)žØ=^ ëuÞq]K)ÕS¾õòAü+K¾õ*õ¿Ki•û?½èÇÂÖéÁ`0);¬eÀuúÿUÉ+zP‰–ùå=MPŸr§s6õ rwù¥â,5pB|/ ñs!‘ˆ\BBOgø>+z¢²ü J¡ø’¤ÿ4=À“?|  á÷ˆÄ©+¿ жÌNzÉç¼¼ pˆ·²äÁ†µHDb)k-Ç®wY)rS„ Ý®¦’Ô}i³Úä(1 ½§uĵµ„ÞÃ;>„–€×­b>|´*ã‚AqN\òðtf“‡w6齃÷§©š,ñB6¦eÝN¤L*×öB¥èP»ˆ•Òå.‚¥ÔÜE´LjìÖÂeRÛv/Qs'S‚!v1%¶b!“ -;‰™²½ ™"7·5ãŽÂ&2Jm/n"†tó³7;‰œÐ¨w:9 h{±“ƒ“¶<©Ò¢§ÔÚVøän)~²­n;QV;ˆ Xã„PPÔöb(¨wKA”¡í вáha”™ÁNâ(3 Ò¾H*,v[¡T8ú.b©œ"»¦·‹h*çó©d$ÛE<•.wPSFÍíETI7°½*òÒöbªÔÛEP -»òÿ îª$9eFýR®Ó$ -ÉKZÐòLbäs]a¢EŽ£¡2«m Y!&c!®ËâŠ,~¸-?‹ÊèIûˆô}âï(2”Î/ç%¶PÍ9¨ÃŠ+¿iñr/ö»;ì?±ª:ÚEN·œ×JDeOd×ïœké`tQ¡ùÍŽËÒ¡\ŠžÎnñðî&žxQÝìÝ¢ú†•MæåmÖ–Lì°º|·ýúRµ]VøgQ[U‚õ%çkhU%}S!<ÉçHý¨†B¼.i. ³ä™Ò˜;vÅÔùM5H;çÙÄxµ\ž éHIÆóò()k(Âñ%L£õãÑ«‡™‘2¿u~Û¿Ï6x“³âÛÌÕÝ€½Ó'„å€#Сl`õ9ªÙ'oBøÕI*«’—7 ̬˜˜t5o2ß;éÉÑIUõkN„BŠªA è¿Ó2 dŽŽ2ÈaQÞ|¹ÔáéÜöïjÏyñÍ4z÷ÞÛ@t¢¿-ÙIöà­ ·Ñ¶¤ÇÜa{â“´4[“OÒöÈÕ¶'Á{D1 µì—}¦­ÈQä"R²¹!$¦”éä²}Ì‘ÂÁ$à²0©°.¤@¾0ÐD.ñ·‚M(q& -þÌ©ŽÊ³À’ߡ̱ZÐ 5,øD5M/u)qöiÿåð ÊèW1+ºÕÐRØÂÀn–Ò,§sÒ뤃gFT ´) (¾`œ€Y~³ÞjE%䤓ÉÞ‰;P'®óìQØ'X‘¡…¯”:6“‘à|Ðͤ°ŽœC©/‹\ò³>¼³aR}%ãð åûLjú«Ò[mARkk”jÛRaîlK:[JLµ¶£E™Ùm©ñ>FÁ|ÚKz£Ø!|Þƒ°½ŸÝ§—â³eÏp K Z\5³:S8r lN¼8²5±SØçK ¶ XŸäÁt’ñ‚­œßZ"cН€Ý#Jh£(/ø -¨­Q­&(í¸=üÛyÐL²³< Ö0âÑyövçLFœœß‹,Jôey/Îjõð®VŠÈ2hõž}8]^n»À¢qo½Ä¹³-Yªm½Ìé ›hëß™²éÑRȼÿùìös‰•œ›ß i:¤ÜKtÈ<‚-œQaWVI"k%›ð̼ÜÚ#š&& 5,ìÄ.­ža4©ÙÚ#l¬:ˆÕ©õÁKñ,…dgšÔ8;2„[%Á-·Jß9zê÷Gçowì)¼7€†Ã=fbýŠƒüa/a¾á°× ÑbʇàÔI’j ña×+ß9æŸß-.%¨…0ìCó´„sñŒ÷Ñ4÷"o½)‘{ÍßEÅÀ¸J ;jÁû8šàŠ90¬ÿé -ÿI£§JÊú_å÷‚?^n19Cü¨?êN¯éñ/4úÜfÆ.÷ÚãŸÇ•!fÔ‚õq4Áø7ãÁ]V 4þƒTŸl¦sÐ`8®"“f<͸{‰ÑÍC3F£4œñl¦SQXÊŒ§³ÏøÑsž¦ÃÁldHFƒ)3T“Á¤9˜ !ÍX±£6ì 9·©&"C2¹Ñ‚cê·š†<´¾Hµ½MðMÒˆâkØK,©Q—œ¦±µb©É™ñЇ¼AÁº¡ä å„Ç´ŒV®º -èà½sñµ‰|?K^ZÂë= -öø˜Þ®h.5º(q;žåJúÑ›(ɆM;üÊ96TkÐO@P•N_|úô§ñÞT ñ˜¿é”¨¯´cÒÏè'f•»@SÕ^G± I…¡ØÂ2žòLÇÃ)=÷© —$÷ŒOË2¦ -\Ëó[ Åã Œh8ð ê89«IútË‘èÕ莪Ñn¾@*¼« ¡JÕdÔó˜[(#­béìÅuyÇ9Ôˆ¾X¾ÄDiöñEÒ -'ä‘AºÈW¬\ƒÖÙ@-ǤZWjIJæto¤ o˜i¾%õón€Gˆ°ê+I¦—b0Ø) ]¯p"ç7lDHPÄùØåVº‚¤tÉuŽ*\‘+3JNïHg9'! Ç~=.l{™ÌÑQ:›ñ‚•þy!Œ¤³£=/¡E ÂKV4öÈ.S,ÒDt^œ·2Z gÚ,m©—;Ìöß²œ8¸/eIÄCN}KRuX`e\¥¥<ö1~§9A¸Jy÷T…†-”z‰µâ^#”̃?êñ˜ÿlÉ -n -2Ñd×ÄÛVÓÔ¹tV¯€õ»üikau–T#"ðÇ{¬D¦iŦà” ¨®$G'ç“*Ó“'g•Ëuä'mÊ´””ÄòcSÕi¤0/k¿¨}M=´ e9WùáñAa’O)·1æÿúo©7»J±fèR‰T Éã+‘ýÓ¹¤TƒO.í—NÒ(ŽÊpv ìâ¦.Ó§Ò…€u¹âÆÇ‹œu•P®“.ly¼åsvþ­Im¦(Z~/URÙÓ2¾‹‘Fím‰Æø¯Q4ÝÕœ–D\GdÁ8hßÒ‹ŠCYÄ)D^í0Ý} §Nà—¶lÊ‚Í_rýü¡¯Âݤ¯Gy黼ú¢ú£æú®8Â1âø`<ÄÜL#BkÆ3™Èdaùš™Oh~¢‘„…Òù½iw:§Žç‚:Èw]©[¾g{:G˨ü¼‰|ËeûJj•{h¸?%@ÖrÓ›…Üù ë„»L÷=†2’Hç¼à]ËÈ·á½ÔôT›|Å8çžåt«ô ²œãu#ÙÕIøþ?/KUÈñ.eÁ¼§ªgK§·0íÚëáÖ½â)Žám3¸?O8m ð„¯Ä“«ß7ÙA2ïI£,¸ðàßÀlààˆœ…wòÍÏsBWVLë]‹ëm'Y+ÃA™kÎ&»¡8 )]ÍYföq8·yœLªç#ûšä÷EÊÿ0”Ó•žÎTkÃ%­)^‡f‡f¢ÇFÏ Å^Òù«A½;OmxÑ|l‘è0¤ËÂtßÁÃ¥¬ÃìtØÿ¼ïÄ —ص—õÑ -ZØqº*û6È“¨ÃcbËžwèÙyR‰[â£Q]p`¢åÍãáFÇB€·'Äñ -è’3’ä{až#weí”uNñr -¦?\z·„_V¼´£YÀTFÒ±"Á„ñ»Ï¥¢ü¢bŤÆFÐ} -õø¹Ö6tþóÕ¿#íùêÇÕ¿<=ýpùíõ-«ÁUOŽN96Œ\"»ËØû2ýè7ÔËLxÃHÿX_ýñëëÛoÏN¯oÞ勆.‡ÎºäÎe£‚û‹ž˜޾üë_Ò^ùÇ»ë›Kù)aI›ûíõgo¾ük÷†ñÝíogoú®¥Ô–³Vñ¾{®dŽøêúמfø}" ç¾%öâ:6Öi×Z~ÔGÁ wïPNÁ©W9ù-Ás@¦ÜcG/‹Ub±Jì‘U"ø$§ü½ëÑÅe-"\%;6ôåOCiÙ‰Ÿ`’–¹îã ËKŒ‚Q—mÀiwŸ¸lò(ª;dY8t¨8–¶°5î¨âµ/¡À<«—ÃÙ½@õfÃÿã‰Ìe/î&)­2_¥\•v\Ãð̘NÏþJœÅ&P©É¤Ò*axt»õùÙÞá8’¼CT4EíJoÅéï¼ÙeΰŸ ýCùµC¶É¾~^¨n$vÃågÃýU­â×¶Owîópû>é€2úñÅm“3!ç î³/+-µ,OjÈ–gÅ - -•<"S@õò·&ä§éI‘2u1\즗Âz:½榰„Âñ«|ºõ£æ¼¬Ký …ëñ”~à”8ÕØ…ôÌ=RzPªš©)¨t¹t¿ž‘Ȥý=c2´Ë°Œ„Cp'³4€Ü$^NæŠ#6dzµaP§Ä4àÊu6J,Ê£÷O¢Çlµ*Õ9^‰óçë›åVu¹U]ô—EYnU—[ÕåVu¹U]nU—[ÕåVõ¥ÝªNîP/¦¦Í†kÕ —¯Ÿô^ÕÉswÞ«BêÕÔõ-‚ÆZ·Õµê¤ãÃí;~ª[Õfõj}‡Úl¸c½ó^µÙt±:½Ž¬¯+§U6ÞþjuÓà9 Tuµº™MÇ.á"^«TËýê“Ú%ŽÏÞÝ.÷«ËýêbŸXìËýêr¿ú$÷«xˇ“]´òâŸ$$MDñuQ†åÖcÂR$ï”/X«Š@}óUÿ}¡ª`‡×Wƒ J<Š? “\BÃûTªáeî{«šN®”†7ªÛtz¸}§t"YKòò#KÚ-¿ácßsÍÄaù¾ì¸‚åûKÀ܆w ƒÙÊ·œUÅÔÞ Ê7l(VȈ£mÛÁ(ûù¥ÁœŠœk¨Ð‚Éâ-§æ'U2ˆÖÛ$b°ü¾n´´¶ùsþ-×Ε 5¤ï55˜"q-׃šq³MÝg3Qi  º"üÒóÙ’&©ÚY(¬7N5ÌÈ/fXÃ1éI$šåÀÿ ‘¦/ø•“Ê-”ª­1eßï¸Ò¸ÕºËÉ€&cž {4Åÿ.ý²w! ›ÏÐ rôë‘R…þëqýµŸÌé„O–å¨N…Àgo6`EÀq‹“N‡cqŒÐãñÚUèG1™¿;µìÌf%?=ÞóóPÈ ß"9íe‹ä r'‘~Í?OŠßÉ•;TÐh:»*a -–šÞËÆ9ÛƒrüòŒÂ[Ga Ô·xû[¡ÙëÜ@ ¥u F"¹¿.–ägH‰nÝááâa,~ùqÄ€w¶Œ‘„Æ–›”üžˬSÑqþ5ÿx<)žY—÷wkÎ~™é;1Wµ:,¼ðôѓө†X -”!Mªü‚œÝ¼Óë5#`õG -°$H…Gt²ìêHô ;2~‰Ä5¼=3@ÄÖô¥)?çº *çfñ…ަê›È©¹à¤™º“ñªÑUÃ> ñ TJÜOR© Ä6ï¯ÃëxŠY’T¼ŽCááÁÑK¬ÓFóZ¼mÏhÝ_Ù1M¢î¶ëùp—žIÞ*&ÁG•IË’;¾Ôl¢Ißa -JË.÷f@’~´,»ü–«rͲÔN®[ß“Z -7㦚ºŸf2Šf8ÊfˆÄÑ©"xöÔ-÷WC@9åí Ï£ -©ßn­?Mž!2¬ô¿ò³¤¹ºÔî‰}0¦Ôנ츥º›É †ƒâpt0Æé!ѲU‘+{$ê‘ñk°õÐ E–¯Çõ×~ÆFS:n5„¼îÌ¥ÐÒÄô 5^Ì£âp™~ Ìò*#9Õ=(â%:î‘7¶á~áT§dïˆù»’ ¡iC£c.À^£qÛ6Ä܆¼¢ÂŽšñ„dÈ‘8ƶ«Kyöb?üJy³ØP¯$.Ä…¯7ä6zv\“¦çSN|%×!¾òu²wâKºV¸¦Ù¦ÃxQ‰Mê -ç˜S5ÁA:æár›Šà±o+ ¸HÍx­VÈZz’GoéûȦPª*Ce÷ÏØâÉ⌠clU2ÏŠígóB5o“e>š®üݾ­›ÝE†Î/¸Ò_³²x›—rÕV‹âðJrý¿Ï.Ø[žyïWOű½u·<{K)è±cOÎHtE»KDWÃ¹ç ¿ï[›qfÜ(vB;Š•·n•å{®ÓWÉÍæVsŸ<Fž´6ên<œéˆßÁ‘»Å¦Ï/%‘*’ûÓÓî$Œä:µbB”AW f\¼·HåÙ½„ÊGqÌ; ).ÍŒ®¯–›nJÛ¹ã†ÓðhÓ¼0a5©‘[«šô=ÝÞÌxðFؤ5Ƨ'­ZžÚ¸ðY²9u~$†À6><*?ÿœR/f^oHvè,eÚ±÷#›¼—éÐëÖqý ELó¹÷WØ#J~ - -g^—Güb½a®3ÉÐâ)ª7<x~ ÌžÓÄÁ«^=9qUv‚o4ÒUk¹£–…P¥ËvØ­'œî!§Š(ÕƒHãë$+)Âï.‰±†r˜ ºþŠ&0„ š¶–£=º´àqFÐÄœ­Œóqk Oâ°lÉS 4{ @0òxh»/Ó“ŠJËÈ€·ÔO‡j•ã÷Öñ47m?~œ´DÎä‚ÕŠß7Ör?ðžÒê×p¹äI$MÆ¡>|ÀæñÌ9uý7Úë¸T mÏ\š›0DÖÙ×b"¤ÀK‹Ï÷Ò4.¯ÚÚ´àx©ËEÄ“â¦ì‡Ç×AÂ&)ó½Þ¹¶A{¶…NÞ/§ãš@8cºhÑhÔ´Œ¥ðv`õL¢˜PÓbšt®$ ôàaû"QÇIîUÓÑq?ٌؤ"‹K©×Jã!è‚H\ÇY ®B{¦²D D³r*о´"±äž„ø -‘%œÀ3Ä"”L[Ú(_K/’RÈ# sÊöôûž€çÛá×,/\_ž%yA=¼`l2ó¨ae¢#S#y“;Ú “@¦•»¯cÐí ȶ­×Ùgœ•|q4,(s§BŸº,:ãaÅ%:¸µÓ‘7 aÜ…Æ-qŒÝ€Ô€ÚÅwßòáãœß¼•ºÚsc—t -ÊC@è‡!ųl -*Õn9Æ 8“sê"yšE& -¢{àË•<¤ªØh”÷[qh?’iWŽŽS0}‹ý)É;å»×¼{¾>ûu%Ÿ?ßå*†Ðàfí »f] ;Ûuzgð±‘ÏÕÇwwÞ¶²IìêZA*M7“Ïj- •Ò»æÐ@î]÷M7“Ïš?W¥wôÐH±ê›n&ŸSpÿñQzÇìòÊ^ÊGiº™|¶ë”î,|”ÞGQrË <|"ážE¼³›Zåñ—ùxNU -4uÅ&W¡âücòü¹JµûôP>^ÔE•KÓ2ö‹|¾¾ïIÜ;šä/ÇùK“¿M¾äÏý•‹¶Ï8ÿQ¼ëªËþ7ý¦¯>ê²ýqä>¤cÛ÷fÇcè?=JÇw7,ԓРóÿmž§WzÈ|sóêY^|`AMå›;5WöbÓÛ8Xò¿,£×"”Gy ŽƒkXôo*PÃÅ]_¼r‹ÐÛ2ˆC”ÌÔ€F4«ÂúäO§ãßÊSåñˆOg¸óy*€ ;eៈ‘ÕbÕΙiŠÄ0`úäûFîK‹ˆkˆm[ö%"`!²î#©œ v¹š9¦Ç¿#J7g -n8ú¡iœÞÍòÃø¦Å’,Üi9–4’Šïb5DA¬S“d¨:PIÐQÚ±‘¤T`$^+IÎÀÍÀøÇ;=}`BR-ß0€kú¾fÿ½´žAy¹…<Ä~üG.³üXp§&!žÖ²³Q –—ˬŠaC¬) ŠþÚË_øå2¤Pâ®”ñìÁ8÷F´¤ÚÀy¶¥$¦ÈþDaW…sÚf¾“c…ßæ8Ö¬ÝÉwšy®¨q\kô€4yGÄ· «Üì}!O:âG™:ÚEÔpm××.€ª‡ -–†QÚ‘aæáç+"|÷‰Ö4¿UTs,‚Š0ÿõª¯Ã…„ùÓ‘ð,×ÿ–yT®œ¿×ÓU@i¹F¢—Û)¾˜Ú-uǤ×Ë -˜‡6z–döa=—Éäq½é$×k xqš -ëÉ”L{¬„^|bŸˆžÕÀn¨Ù‹Ê°— B›z˜jù&ãC8‚²Ür"¢® ÓŽø~UF#êFW­d@îêô € ›y ä QlãÌ}›Âd@}©2辩 nsÎ@eïãÞ°ü%^#‘K¡¥ñi/‘LòXá4˜îXM·‚!“ÈýÚ´ì*VÁ¬Øõ`œQÚ$wHIs²ÎÞ1 +6¶T…ÂÚò-ni§Rg§¬¼"Uê²õ<÷–r鑆T -•Q—†Æ¸}ütÓACì_Ó&‘LÛÞs"E]É£ÇiÆ%|ËHîq«W@b~ƒ¸(åLtrKƒ ]ÈLEÛùªL'IWúV ÷tzP@v-æéÒ -Ò§·¦ê)dry4}™4Þ¾•N?³°¼#ÈPRV¥/˜Y‹áÁÕŠ8Ž<úÙÁsµ•Gß$£G`Ój’.3$¡8¾Ô±)YKàÚÅ$oå¢}ÚE%÷m© -”:ã ‘³lh_•¦´'mÕľ» €Ž›†”A=©•1^?¹ÈÆ¢lzM5LBSó«}ç®jFQ €´£ƒÄ\·ìŒ{ÙCº¥H¬žïöÏŽ 0¹Û(Ì4&Ãô #®Q}+:âÕ)ÜM­J#ÈÍÃÏîåŽ2— i0T#À­Œ1zN wr›yqú‚9ötüh%*S« œÕ`u8c¼äj)°€×ÔpŠâþ´kùfR‰ÙÑØô¶¶X¹t)¥nF –– -$÷‡Íža$Òy1RK¸edNSúËÓƒ~T¥Tyii‚ßcp`œ¡>s`ùBÓŒH­ü"™…ôç¡gûŠc'¨¶c­&ƒPU‹ßŒw_‡ñÉwäƒÈß±åº8C$bÀöM@éæô ‡)Dã™UnE¬úâ߯ÀéAK•ñ§F&ø<1Ó¡ Ò1—>ãå6:ñœÁ1[4Õ̘µÆÓ@bL»b{€eŸ ª;ÏW˜|i«q}Ý¥8itLâ'¦šÂ^‚f·ÿâÀ¥CÇ"ƒ¸I€Y§+9…  Hp9 -œÈS²°uéŽ]ãêkDu2n~Š}©:°'6.ýñ†¿¥áÎëîO8 }_,§÷⇠-[)Ü{qfO•ÀøŽòˆÓ‰_JÞÖìÌðˆËøá¼Þ¬êÄ»í‚bGe8qTÛÁïƒfÍ æ÷ù€ìû{oÄЊÚÀAgåo>åz 1±á¨ep‚…à-\žì3Ó9‰eµ."Øùô‰TC·©.ÉiˆÍ%¹‡ØÂºõdÆDdo?Ûvݼn᯵ŠN.ÀIE×k’LSa%³J…3̱ZÂe¢£ð1ó@¾º‡œ‰·Z–§p.æ´{FÛ™ÎÙÙÄ´É®t/Þohb‰žW×3ðРÑÑöÇÖd¯ÐÎFñ)“d|3ëø:¸Åæòðrdc1]œêGÔ—pX“NŸÝ@ œ\ð½|‡‡æ)Ø’WYÒ àÂ7ŠVdevB€ï”g!o1ƒÅÉÃilèˆcÙ­;öÅÐ1yðb´Ì>ˆ$1ç„ÖØñ>‰'@‘ÙGÆ£6È ttÀÜR¡NN˜Y ‚Å…ªLgn7~ wß1Iv翬' † 4x¼4Ó¢ =ÃÆÌl®,€yæÐìªâÙ«I t§“¨Ù))l#’Hiæ¤k;(r|ñõ© ÕOê+MÛ/t :ñ9é%ˆ‹M3®äçõ àš½gp ׆ªˆt¼ÿÁF¬æ1wØI÷bôãÐ…c;­ÒÓ„(€‚ƒ~~.jkm§ “T'æj'ýp0› jçìi¯Ø1[²uÁãù {g¯c§Øÿ³ûq)É*l8â†ø½ÔưüËf k{£Q%•—y¸üGØœèQ}ˆýÄÄ‹‹ˆ“#8À „ô Ÿ-~@ۋ䞬sŸB$І$nÈ;¬{!M­ˆ.춆ï=D{М[è´•üµlCÐRâfpâ«6˜¹™ˆƒ“ÈÒ>Ø”2âŽN[ÇAn´ -»4PgkV DAµëd[ƒk {Ƶ&FÉè„ï! EdK$6Šu"¢:­‘P‚m‚Ö`ujkߑ͂™²-Æ1¡‡|s@Ì5k­m7¯ãCöŒn¬…‹R+O_êù€ó«CB½—Tf:3Ç7×>"îWl*ƒÓ$'†õ±4DÃzЧ=È*›r±Ÿt'Ö3¶%ËSN|‘Å{—þFn؉–€µR©ƒÊͺf×P¸½ñ¢Ò­\³ÙÁ˜ý¯¼aÿt±µ&£g””º ‹QdX±†h'þÈÐ -ù‰ÅSfkì·Fû³âRŠÝ-G’H=¹É±)߉°CVQØÉYÌ&åz%ÈûÐÓyÜUo‰†Ebç$ÈŠÿ&(Ñ©åxÈj]dDq -:¥-ˆ’™Q+Ë\4íJÌ´žà´Z´•‰©"–B1ÏYÞh®"QyµrT›„¬°fgñŽÎ ú$oÓ³0jüjBhSÕMÊ٤⬌ÞXK^2b?®ÙeÞIü ­©ã„ÿyÈ•úhõeÛÕyáÃx8®?/C²8¿kqe÷WÇ‚Ž|ÚÁ’é±yr¾ó®GTÔ¹~döB§1¿ÀNÒ)Ì<áÛ­(öèÅp¦%~áa°e{”µb§b›ˆDvïd§ù!¶åh'*]`qj ÇüV¶l²8‡uò-,1Á 4Hç””2“Ø"¬‘M„7qü…˜¸ T|‚¾+Dš‹Ð¹ÆÆ˜áÄí,lXv¯_Kê“5îeˆáÙ Á] i4 Ô¯±±7rtHäˆdZð)†[A ÇxVú=¬FÚ&¥ìøŸ|mqNC³]Jý0©ìH8\³­”(”¶\°>Û8:p%]Ï!ÍéõP®Š´S¬îéV©M‰¥@鳨ç—8ÑŒˆ|ÐvmüxIc»Uy -À™6˜g–3Àß9ÿL£ªwÈàR0”sÉjéBŠvBÚc'ξSžä$0ý Õ´b 4"f¸´ñ]29t8¯±9}® -)lW[s¤‚a›4M±>Þ%?©È0­<‰ -Á±TtØ0WÓˆÅêRØiÙˆÐìª Ñ™x8á¿Ä»h6Óà‚ñ×-Kì”Þ¦Ë^“1×OâÎrç¥m%’:6ÒwàD6ÒîëØÀ¨cŠ¥N·::´Ñ}+›9=ìa%K Ä±Ñ¤/°ÂDßÂX¥E76‚ÎR?[GíÈWDð­'‰ß­9Ä÷/ <îŶÁÒû¼¾áWlHq‰É¸aÍU‘+‘T^ˆÄÉéwÑQfŽÕuËŽN‹ûÑÒÅ–kỗ³‘dõÜ:ÊÀ²Ñ%ú¶8 Ø8]iŸpÜŠ±i•@Óé}+–;¢¼ - qê¼ì—p0Ž"†SîTI@€Þ­3 ø0;P?°hS`ôDüí`õ27Ë?ß¾ù%ð[pÿòœ#€$çŽó%ðņâûð“Bo‰zpÓÊ«0ž'{šsHJh&çk`ó.q30-¾L æXâwãùÚYÂè\+ñœ[™ú Í© ®i¨éF#8­‹:¥Åž[Á–£Ú,iQ+<(­­8¾fÿ,›Ó,t’]Óx/Lò0i®\‘G:ò§•µå»8hYš1Y˜CžG‹k\•Y:~çu‹=o‘»á*D¶*O+z"›³ÞÀ¼t8w¸¬ÿDÌ108>^ÊØ~ežÄ Ñ!ÌÜWJžˆYÿñú±¬Ž]sR@;v<¬ø.»K!Ét°q§üQ ë]ò `Põm©ÝψÎ`!›R3³ÃÅWÛäHY‰ªN~Ì©ú‰;÷qËì”®WK|cŒiBH;¢9¥C-©`$PkÄœëI_V°pÇdéDcò*ïÒó¯ñIË#.iª_>jG{Oí@¼)Z/\†‰|·ìúpÛ®£M÷VîNÒöû~h›º¦N ©Î %x£î@Lò&Ý6äDÃÚ vN 5‹¾žÈõ¿Júdž&é“ħô9ÃÛ'ŠPA6¦Q„Š€>"Bÿ]*ÕoK„Ê‹PY‚Sr’ÕOœ²sžÕ%8e NyIÁ)^ßœ'ŸQl -@„¦¨O𢿄¦°CÓ 2¥Fì‘SÚôuþR‚SÔüà]Å‹\Ö°:8EM‚SÜjœ¢ÛG -N‘†Á)n5 NQ“à=hhŒÛ#§è4åùK NùØè”0ŽN “èÎ2ˆN!Õu¢Ã$:…@ƒè´2ŒN Óè”ð Ñ):9Dç/%:Å=fxŠøC¢S-6e™Â=½üÀQ(ëÀëÕ00…sŽíK` -¦LÉ”À”£G -LIù®šü¥¦¸O˜Â8SºI`J·!0¥¦Èìík`J§2÷•/90Å«G LÁÃû˜ÂŒ¼ŠÀ&™ûSÂŒÀ=#0%I %0ESàñ(¡)ÈLø±¡)>ÊA¿§±)A¢5X¾½76Å•H½©nŠM ÷ǦÄyÝÞ›2¨yolÊ#^bSž96%ˆ ö2bS¨Îö¡)Á<šYe MYBS–ДÝBShj†¡)°rÖ¡)mç§¡)펡)𫄦¨íCSºQhJ7 Méâý¡)í$4EïyhJ(¡)1EkðÔðÑçÍ$A"a~pÊ zO‰ÃSbVU½šÙwŽOQ9>EÞþžÔ”•8?DeTƒTBŽQyÏÑ%FåîìG‰Q±éåÚ£’,z}ŒŠÙ%F…¥†QŒŠn'1*a£b6Ĩt“•8+FE=£2˜ÇgˆQÑÉÜ¡$#üæPs¨H¬cT¸N -ø¸;D¦[ QÑuˆŠK!*m˜Ùo¢âSˆŠÞV„ñðÖ†•Fœ"T‚^"T>]„J«†1*êÁ;ŠQ±£7‰QÑ£ÿpŒ -?Ðõ4!*áá•,oíK„Š’›Tì$TDu9TDuƒ•ð1­šÂSH¬Já)‰Cpx -± OÙPqSŸ}xŠIá)vSEOicO ažrÏ`ÇÁ)8¨–à”Ç N ݧÀx9 NaÿăSÔ$8ÅÍ Néâ3§ &q‚ST Ó0jvpŠ ›koœò`ßw§Œ«Î N¹kÜKpÊ' NqœW“apŠz88¥§¸nûà¼hõÔÁ)vëà;N©çë‚SH/ )8%E‰¸°ŒM¡uMÑ­šVα)´õRlŠW%6¥íRlŠ×k MQ)4eS5L‰ãRîjŽK K\ʾťˆÏ]q)Õ¯—î‹K©~\âR^r\Ê]¤”ãR¶$¦»ãRî"§—²%A-q)ãR¾ýî»A8ʼk'r#ŠþììUÖƒHHôa¬å ØŽ—VãBÄ8å7ñ~l_$ Û(ßS7rIà ~–sfHè~ÐM¤·q1”R&µ42Æçô®§|þøÏ¿ÿׯˆ¬þpz~sJ«¬ß|¾ú‚¾i±ôôcµÚ1¥ `JÉÜd$Oƒø%-â‘Å{‚\\!ÄJ”ï•ÎËóÂÜ’“'ÐÄCµm2ãÐ2ÃñD‰o>:hŸD$ÈÍX5ˆßAÊ€cvQì4Íî0ŽŸ¯ÅsÞw&âë…£ Rp”çeñ¦B”Ú¡.×Uˆ,pˆ­è“6j1?ÇÄ(• x‹5†4he2Ákgéé÷€Wj¹× »kw’.r4œ£ÉïysjVVá¡wÅÙÃ`'Îh¯ôÉ¥ïÎNnNúœCˆ>”—ýŸ}ÀÜŽ@h’>]2(ÂÎæW6yà²ÎX*Ý€Àòf5G¬óÇ€Œ>:»¡c¤5ˆ%™&‰0Çó–ãò2œ¥+*Ç‹ŠÕ6ƒðº¦µ)•>éb¼‚X³ñ–v”wÄ1;œ„”„r ßñüVµ¼:,Iq-‰ê1WRÏÈ»ßðè…U³E ©õØèòÈ<œxàØAú”yäè®<bà9©„mÒ!ù©ç…Èßà×ÁŸ2×n0Ôv2WËÜÊCìš]uŽp'n‡¸Æ"ƒȥp|I!c²'³[;ßr%Í.|ls“ UñL„)Ë"9-?Ãl9PYåÑʯ#3ˆx ¿êܪ(b¬á{G"Bkt¿$ãU;š¬ãýÏÃg”–Dén¦©ctÌl‘@$gÙ&V”Ž%7x_ý5ËH·'7«fEºàoŸ'!)½>“­µ ÚÖ¢5ÁwŠQ„Z²2À{>ŠohË Ü=jÇ/Ì“Zà’ØÞ²hÖ*f×-+Ǿóø²á÷ ÍL;› ¨k\#ÀÀãü†ÕÂ˦ï:˜ÅÆæ0Ú -Ä„Èg\MÀUÇãZÓãz5–¢­i#wæÑh0£TÛÊS€^³ÅYø÷Ó_’ 8%iФܧ˜khL°„_Àß¿“0QöîcǾƒÈ€ûL©ˆ#µ2šÐâë<ßá~ž§Ôà=)b®tÌÆ2ð0‡ë~ÆÞ€ŠÃïàîc…ˆ¾¡‘5¶žmàXèg¼ˆ> éýãÉïͤ‘fÚQ3M3r³±fþ͆ij6Ìf5ÛÇ}”8<&±p‰¶­âHñ¬áþ$5/žž›Uÿ?{ßÝÆò½ÿ{¾P±ƒ;;³ÍEì½'QcPQBÉý$|_ûoÊ.,EÀ4Y|nîÍÝ]¦Ï™óœgÊQ *7ïÊã9IÈÖQ+¨JˆlˆÛ˜n›œ}EkzéùD¸: -ÞPÇÈM›¬¸Šj( ×€þ¢ò׿ªˆTë5UFvsˆhS"ÑæLÚµwCq¯sÖ)³\sOh:û\8¸&‡³ׯvbòÖ”›^–Úxì‘3NÌsêྸ'ä"=ÁEMŸ ùÛþzlG]n{i´u¹ë¨ÁvÔ];éõ¶#•֚ؔõ¢íÈþ„íÈz²ý¥yíØTÿh›fжiÍÞlGÇy¥íH;ÙŽô¶ccίµ;™Š)÷f*Ò®¦"ýS±¹(LESk6Å@ú%SQœnù[¦¢éΦ¢Z£w,«'“±1¹×™Œz‹Éèo±?l2Ší»Êxs^k2Šq)7Ö“ÅHêã/dï1Ó77¥ûÕãëeüµc£h¾`0¶•öކcs²¯7õ6†c£äÿKÃñõf\6õ”–Üq&ý+fœXT³Ô®r±(-yª/Q÷ÿÞgï]sWe˜Ú­¡¼§ÔPóoÍ‘} »r'°ønŠ£ibCÈ%ê`<M³ÅNnÝi¦&CÚâøÓ®p÷C•>Ml¦fÛ n#Ô²pVë5ïÉ$Dª9Ýaâp°]4Ã`Ê"$ŽÐ-zÎRå]4í½ˆÝ“ÁL©c4å ¥eRѤÂÖéÚ¶­öô9Ävwd©ÙFSGVζչ)9©èùqë¢Ê‘£¡™¶÷Aýõ¾ªWMm„U.=Pu8Ì;³'=%Pé¥Ë!rêŸÈ}Dö8™%Z˜¥÷ÍÖ¬8 ãe¡þ¯|?úòvËÕTLM.Ò4–5Ú&ê¥Yw÷¨»Rìy•Tÿù?¨¤¥¿wSž$ò~”¿Q±<¤Iú,w‹­€D¬ãQ± C^¨.ïT:i_,åRG~!òˆ¾®Þ‰z·híU6µtkJ7RBÉ6#LH¹Ü…L¥G*y^Û-±¿òÿò|ŸRu^uëþ+ó‚TwÁ¢s£©EæÍ–’ëɯi8áòö•M¹im¼¿ulRQÜÎÚâlÒñ™“Pš=)Mq¬RÙ¤åb‰(™&‰-!mÖa˜­üÆJ齈£óò4U†™i)ìÉï-3lavŠ•~^-"É23…Q&ŽÉ3!š8ÏäOÄOЗЗЗA_Z ô[ 9Ÿ¥‹óÌÝi'÷?Ô﹦½˜¯þùb̽)N‰:Gì~nUÛnÄé=GO¶cÒ¤à}ÊZTî®±aêK" #T§òUT¢R]Éâo¹#ÅÿY|ðô¹x&ººIN¬sCMºx0”:*¶ÁRáÑI®r*ïÀÊuONº !ñ¤¡­:Y:•ò¶vhÔÐÅM“âü“ØØÖÆ ¥Œ<9#&Š‹c‘†P D±bátPž4ÕÅ—¶)ýŽ«C -¦pd'Îm‰ýÿÒÏZ›¨säy]Û’¢ÔM7¿˜g¼ÇP…‡XÊMr·åly}EŸ4Ôùå–H[B9k–—7G3M¹7ÄláJIÁü…Üâ½äf‹“†ÂĸtÓ’[âÿŽÌ¿ áT—nèbz@L}˜Ê±ÐŸš\i™)á˜%]Ê}wîუN:K0Ò:–Øä¹yêðZ*¨ä -Ê‘êÔ’gJÚE5‰:x"þƤ×8•Â;„tJÉ•›ãnïo‰Êy€T²Ò]¡püîBe¹ -”µ•³TwµÝ/ó= y³Ô¼¾¯ÿ˜7,û“K?§É[. —¿õ¾òcâŽ]ºíÐÄ´†éº½›)ˆpX»ëûd(T©´¼VË%`«êéÍŸÄÊtS¬hKºÑ–Ì…ÛâÆî6ùÅÑä¨ÑD"6ï„1áè¨Ó¢­XQ;@O-µeH\»&½@¸¿˜’ÚZª|Ò„ã%6êG÷E\±ª,Δt‰+\­qÊ×xpÿ•ùÆ!_‡6›UáX.…Ö *½ýZʺܗ»ëÿÆ”óâ¨)Ç[êvM›/ë]î~YjùÄ{¯9žLZ†q“®pó_’…ì(ý/¶Í-ý²ã(/Ò …&v’Wq´™uCΊ4J«H½kLÑ+BÅ7 -ëk2¿>S‡ñô‰ý*K§U’Å·VYnøú*iŽÜ´‘çÈÍ/I4Ö,ÓüS³ÌðO­ríÿسd‹Ý-²-šâ—¤[µasY[%¼÷ ⻪ÍO‚± -oÑbÿݳëµìܱÍêí)Ù›D9Ü—¥ªkµd«6þšbE[Ò6æÍ¤Ÿév‡ß:ÎÉŠ»ÚÅœð&£‹ƒ—Â\~i +癚&½û -{MƒÃ”þ"˜¸˜ÆëPÝ?˜ÕRé« c\S8¤Êyüoä}Î܈‹±ÆK/|}dº#¶ù‹„ Õ5î1±â¨KÎ(᜻ÞcꙩÀ¢ÏÈ_DSíÒkªF´¹ž-³úg…MºÌ´»÷¸!ÜÚM²&=ÁšzWiÓuyc£´½2ëø¯dmX¹%Ý÷ßýй­ÿž¹MšÍmÓn±[L»I»K€ñiwÓn±[|Ÿ<»Å+Ú’n´%sÏn!ͦéÍÜŽŠ‰C›È ðʉ§;Ù/Qfˆ3ÑRÈ{ÌÆ[À©¼qƒÔoûðų†LïÛÐÔÔh£³¬×æÿ•¼…Í.®qk´»ë=fzŠÏRoÊFvï¯ yf‚t $Ü©Kc‚É}§DN«®5Ø‚àî5Ø ‚˜6X)žYví½AˆlŸÊ“nr¼OÑ–t£-™¯ºtÁ_FÏüõWD&nتš íÑE×QáÖ¨‰gîNSÆšrKMY¥A|*ÇĽIÛ1q(ƒv‹-:\w—#ïø¯ä-\¶[âþ¢W,{6 - kÛÖDP™µ¯Bi¾6‹¡ÿcÏ‚ØP8O…yùKÂèÙûâèY«½ -dÓ>0ë¥)G•*iáÓv>m·0»…xmàãÓþO.Ÿ6›Ù‡éKºþ¡‘OwTòýKÍ-ý7øt£JWÕ´{áÓ/ÆìΧ»eú2Ÿ~1æ¯óiÒ†O7ÊrÃ×WI³«såÙåÓ¯•h—O“V>MZùt£\û?ö,Ù :ª™O¿Zº=>MÚðiÒOÿ!Ãö¶Z©ò‡ÉjÙ=JêN…HÉç/>¨?¯ò»¾Œ åZ=îªÇ¨ûL›žÕãð_‹ZÿÞ\oz®E%õ¨õï ÁIÓ³µžiý«/¬ÞøèŪײþÕ”6>z±X-Vý«/(k|ôbÉ•µ’¬·ÔÕßìN'&eá{6¼¨ZLô¤Úâæ>zÁÝg­é™¹QÅ3U1½G/´znz¤n<‘¶.ãiî“T¯«ªú£îÓj¤¦ÕH=(©«ªú#ñi5­¦Õ´zP­®ªêš« -mmòW´É‰8q¹›)—}Gÿ†Ñò’ÈÖåã%™õIЯ­/ô‹Rë Ó·bûÛš^ª0¥æ¤TzL©s÷YozöT]´®!}ß‚“¦g/ªVYW®t²O¤¡ty]Sûô>i|ô4¹ˆ­°£> Ñ»ã†ÞT®fÔ`µ²¦ßIÃó•Ϩ•Ïhú]oxjD4Ñ:Ò44¸ÖôLüQõzT_ÿæÐQëCG¶èȽB©¾fñ·,.£Þ_f½¿L_÷MÏ^ÁBè'UËêýX句¾cMÏ5UÛAK»ŠIoznÐÒ®ÓëzLocEûõf'£Ûðéß3ó˜Ö LënA_±îê¹ÅeÍA|%Œú•¨ÌÞ¨Öhâ+_-¬ŒHc5MÊêŠÏߴ陸£êõ¨¾ž#Í¡}uWö¾ªd£vw{6>zU4k54jå7ê`6>zõ«…xVóê»oÊÃhzôG4kñêÓ#õŒëO¦?³z$ÿüŠUÏÁjÎ÷®^ûçfoÒQæËѪehÕò3›ÊfÔ~ý5À}¯àgˆ×›ýBþ°”ÍWxy£QõYB¢ÿ‡¡ý¢øÅV¿æªüïƒÛÇLª2¤nÐ ÅKÕòCh/™OÞgJ¡ƒR:Sšìü[Hý¸šÌå²÷¥dñ!›rCžòÚφôP± |OòçÖ “¡(OÂÞè¾MP™Äz.YéžÊðÇÂ*h +“hÁz)BkXUb´Æàyç]ûÐôêC²”*Ô+ÉCÉ$Ú=Íü¯Jd¿s¡)uNôT&‘,fJ™tè¤R*¤¨¯jÖ 2ÃÉÎìy¶œåÖƒH°5…“J2õô[)¼¶ ñd9›ªGW¬D*tpwWÎp@#/Çw#lårUi;J±d±ÈMu”q›o¢!ÑÐ.oÊÐÚÝï;ú4[‘Éé2ŸÜAÉ Ì ØéBâg*¸Jz+_Î*ßuÞcíÊŽD¶\Ì%¨WdVÅt;•×óxHÞòí˜Âo®CÍ{³4Íð“PÛó\&\™ÙòžB-JWÚÏÊ -*Ô2å@ŸžMdîBó¡!¯"²8¢xó!YÿÐüoÑd©Ò¦Çâ¹L>ýŠïÔž³2±zcô6¹\/}=ú …ïPÕB>]ÍVz©ƒ?•?>„üý¡æ¬q‡³rfí{&NK™YÔùUN«Ýt=TŒ?´¿LWnOËwòqö˜Æ˜Eu³u‘ÜZSïÇZ\§JC³kÿˤª¢ò·ž…ˆ®Ùý jM=áBAÏñ_‰!-ÐëXümÍý‹ï­õÕ/¶O7Ò¡ŠÊÆH” -ÅÐÉC2]ø¯³I"ªp±d¶½-ÒVÍúè,'-ZûÏ_Öç*øz£•S¹Ò¤ê9¿”*—R“ªÂbÖ+4ñP(ýœô[BÅd¶Ôâ{FÌIðšæ}J'KOþTosyÙѺà6WUÙÆlïS¡˜Lõ è]Ûño©Nf8>Õy’}.æjªó¯­Ý{BqÈõp¥K uªS(w(÷À)÷ãd™¿gf:«öZ°5»/¡Þôº§ ÅŠ¼Â‘šžÊ+&UÕZî9Y~jøÌeå€åÍÿ§‹Ù˜øÀ<}]Pú»´æ›œ\'1è$è$è$è¤þÑIÂ)[?ë$Ììþé™Ý¦f6j0#û'fdÛMêSßDp–ŽL+¦›âþf÷êvLþá4¬þædÞÿîë/,-¶‘Z,,Æþ¢nKèÄ$Rbå¢ðQ)<;´Í8@´€WéUˆÖç ‹@´¿h¦¥ ‡5\Ǥˆi¶nK(£Þþ.C]X¥ g±Î:l“ѱOpöoà̱յ˜L·ä}±†ðq,}ˈ›l”yçxæÏÞžaŽhôÏç5^6ïl„S4€ À`°ù[`Ó‹GQ€Î¿«R‹+Ó7€`í}÷ !fÜtQj˹4S­!“ -?¶¾ÝÆ–¥Ì‘wÇkÔ‘W±Ù6ïÐ-gJáÛ”3Lšn9TÞ!«T¯!î"ýMÍ;8JøUú*X{I¡¯¸¾"TcTœ•5LbK­bËõ›Y⨷¸ F©?9BeAQýKEå^‚¢Q›Š[R¥žw›¬Ý}<ÐT½h*š*hš -–UP–gYqueºeE-ýþ²Ý;UX}¾% - ç†^©jþæy\h“ÎڤϷ7C›€¨õ¹ÝÓe÷Q»q¹sl"·/YÓÄ|2.¬þ€ŸŸwª¹°ºï7u¼½uVXÊýó8à0Û”û°-K\*ïÓvt£Í³Xã x•^gØÅúÎà ‹€FoqÒ]·)e‚ˆkt©íPND,CgØÚú¾Oº›Z#ðSA}®t»Qª±lKº°t¢&‚˜ÎLì5úE½…-ùïLóÁr†åü–3ÕK“E-“ƒªØÂ³8;°œß·å¬Þa)ÖÇÖËR„ØG¬ƘôÿBˆeéóж~Ÿ‰ ŠN•^…g}~Ú xF8 -uð¨áî×møÙ}çªÏO súŸCÁÃ. ë_næâɘF4Åœ„[hxêxçÌ©ÏO“ÅÀœCÁ¡—˜SL75BíçÀ0 j€B½s -Õçgù>€OàÁGl„ 1PmúÎpœ_yçàÓçÇ1­³o6%Ž&v¢šÔfâ,ZÌ$ŽAåƒeâ¨;B„e©ÅHýjfiæ?ßÈð޶·½ÓIí6mMí@Sž¿tƴߟs%ü*…wïPç™”HÏa³]‡aŽC<‡Q¦P}¦Xu‹¶¼Ù—!ÁêBÔ)>‡1.·ü‰i†ÁÔ1.Õ&6#¿oX³úü`í¯,¤3ÃV.cŽMM"WË™iÙLz¾d”ˆ"Lx½nÌÑ€hoŽh¦ë"”:¦#d1›èšÌ$f3Bp_í;4œï|g€†e ÀÑ[,k0Ê­g¹¨nè1M×8•ŠéÄÑA©Þ÷Ú†…ó@ è/"3Åú±5âÈ{L;F8“|^½-‘·¿Ð‘L@ ô×!H#¦EE×éVŒY6‘!jXVõù M.z µIu©6 ݶå–Xf -Ç*òÆ9K³Ãö¬_S78J÷ΖܒÊ,µA‹XboªfÙºåø6hÉáœ% H´Ô^-8Õ‚ÉüÖËØÄ„S­>6 ßÏúüÞNàœbÐÍþ‘«z±)Ëf†Cå~cCcÞ.cBÿ€³úA‘ÂÁ©Ò«Ð¬ÏÏš‹pÜ/(ª¸Ãq?Ë&†˜TR§ý8ÐpKÈ/*¬¿z>¹­º9i†V ¥|¦TþSê¦)ÑšŠéØ\ÿg’\v…xUË/ Á?®v]u×süWêILy¿R;ýbû@£´jjÑ`™@‹ï},º¨”,ó÷ìÏLgDª‹%³/ Q=¡ÞPˆg¶ÅM›‰B±’¥§¦KŤj¢ZË='ËO ’¹¬„-KwI³1ñ¹ï©B®4˜Ló:É1>ß'^ÖÊË,CÓ‰$aŽ)w|š–¦K~æhœ}y„Kßç\Z;ghª¤ÒCÖŸ,s‡Až“€ÐF®ð_çA“(Š'Étá¿•¹?©Þ´9qï}åG±};Ö]j¼ø þ|L¾¶Ñë-wŸRzßÃ…Û\^v+õ°å6W•Ä8ó¾ŠÉföÚAcä¯"ˆ2Œóç½Ãòoè®>åÕb…òMuÅú܇ ¬Ø?eÅ.]z¿Y±ý }þ…íÔ·ú‡o¬‚Å¢a=ô×ø}«©½ƒjåOñAR½™Îo¤ÃÊ/ð?½•ÿ‘èß¿ÕsòÀ€þ†zΤç$û\ÌÕôÜ_ïÁC®4+ÝKhôy mFú¾„zß—ð¯žõÀœ¬†X °úßÔè·n0À¤Ãûžtx·Sžoªz §Ïo"€áÐ×#;‰°“è«$S Ö - TTTÒÀª¤R)ù#´YàýQÈWx›^Mð¦*V®&¡¤ ¤§¤NKÉ|ù®PzþS|Ý—`{÷4ÍÓNåT2—9¿9Ì”R™|eR•¢á§õdŠgî*,w¦²PIV27‰Ì})“‘ª«9ÅÍ—SÜìâq2åuiÐŽ¥Ì].“ª|j÷ñ£_K³ùÃBVeYKø¹ð]T¯Ò”f2Ÿ.÷8æÞde¤¦šL“XTÞKuË2ýÊJÜ\æzÏ0-füÝUÚ€_¿òb=`½àD´ìáJ–ü¦}LÓuq7¡†tTÜÎdÖ –þï®[¯þüù#´'çêþŒ]ÏpÕ)Ú»W’î)ÇãŽl“ä/J:°o‡²`éLŽbýEªþKThpFO¶ºâm˜žÀ÷‹}ü†Ûë1½òÆÉo΃4¤õËÇ"tƒ W{ºmRéVµ’x{úõÆñÎAx/©rINbDõ©-E>J?Ý@ª_‹É¬šñúž)ID2jöG:Yzò§íÍ¢˜œðà˜ý+Uö%ÿš¬æ*×rSþ_r#Ò~®<²²åܬåÓ+¥Š,rY|1Ä—›ýBþ°ÄCgó÷ѨúÏðAt˜Ìe*•ŒT³‡·=vâò˜Ç–æoÓëIÙm5:L½®Å&.²•Œ¯ç]\8ô5çæ8Ô±¥[FßT€áx#:Τ½(&q”›çZ\Ó Ìn,`=æ§LNL¹ªÈ¦n™Ìiœo¨]‰à%—DÜH±jùs$ºA§1.©Å]ý‘ô¢Ú65MCܱ`:ÄlÛ¬ª;ܨñ\ÕkPÝtMÔÓæÍ§Ñ¶ẗ¼çfaÒMLÇ”¾HËv,y¢néLE3-&,ÃTڳ·Žå&¹HÚX¤N(¾ÈŒZñ¨¦ì/Ât&Ó§:ugp&‰‰‚áˆ[„!Œð”ÝduÞ”‹ºÍ“¥f³XÂu·Ó¶¼Ž"JŒ˜ÁÓWÔJÛ,ÿ´±èhMÉòæ—®Á5Ó”¥µ Ó0C Âcs¡aTÝy²²jÉŠÒþ7OW«§«y;Øð.’³-B5£!]I"Œé¨Û(c:%”÷„›®!Š+Š_4/]fÚX:Jl›5¦+¦ÇäOâ)Œ²½½tuѺT6/õ„Á¶y5U*Ô±d*:m)Ûm\Ûr¡´1U"ûŒw¸/UCã¬ÄQVL…Fí†ÂAZS—ø¸«+oí®„1M4‚# -kzÉZL8yo¨²ci^8"5]2 ’õ$LW¬’5d—Ùœ-Z̈&µ¥—xb¼ŠjàSÞ -޼ó={Â^äÝ„dé˜è"Óë"^9¬(e–!ÅÒ¶¤dé¦fJ/³ZŒi¢Å7"F˜?1M´ á&K¸ö«^y>^:†xÝ\««*QÊjU%¤–¬Í˜òƒ¯Ù²ŒÌ° ÃíÝR…4¹ÔK-`¶ÒCž–§3KŽf.ë }[/¢)*¬T¾h<¡öL‘J“)IeÔuohÚ–Ae»ºÉŒcŒ11fDå)ï Ã_HBE!mÛë‡@¥8 ¦F eSMɇ¿¨)×Ȫ8¼g¬z·»å4yºLÖ©b*|ÐM>Xåf†.S$µ›¼ÑBUŠîh‘ƒEh"¢i5©6tY®ˆ;%Ôºn `uý+.:ZÉ&šÓ¼³DɼNfŽaÈ2ðšóº‹”xS¹8Á¦Ó Ò<•i¨®ò†Ÿå)x¼áÇUšHNVÊÒ5)"D³‰Ôš\^My·;ÿÑõh­R2lž’¨±SÓ9„K¡;¡ïèJ5Ú–.¥ƒºú¢Þ|ª|ž²Ñ½ös´;Á€ :CcMc§Ž;J󌽄ìPÙ+:ñ0V·Å˜å£žé(8ª³ÛÂòdÆT—Jð‡<:R®m9XjÍÇõ¾¼¸†ñ¤Õ\%Ë4ÓÖ$X˜ê«Ô7LHR­C ¸â¾1œ­šžU¶†Á›MÚ¼ ÔäjБXPƒF¨¹fÐ(úÙ®%jÊŠ25Fd¢¼Kl™Ç}iMÑšJt{IWÚ\%j‹¢ÊAmµÖ4-¥mê0å#ÝTÆ ¸­ƒøqÀå“Ùé¾NPÀÀ0åØñt.%†#„˜Cl¥÷)F)SŽíh²WÜ`JóˆÒ«K­Tº¦ÛDâ—­{Éš:UƒÂbšLÖf–cÙÙ~QÍ]èñã—„¯š¶¤ÜΓÝe2®í%ÖR>,)å†l·Ïj¹2E»KHª´ j– ï#*ãò´UÓò Ì9Þ(†¡®Jò0Ö¥||Õ›Ö- ÖkWfYJCZÌL52-"ǪɼlFÝ++ñF—¦t²JU¶+•ªX©–K1N -w•4ùCçÙû¼ 0“n€—æ,ÛÆqç)®'Ó™P¥Rì£[Z¡ë©´NíNsøzJívOuH¨)xÛF4 $·ñåzO¸m$‘üÄÉ·j²”)‡Vò÷9Σ’Q.}i^‡Š-Q¤À©c\þÔbÑÄáÊþéÁþZˆqµ±*ýßPÓ7…¡¼ÆÉr#Âáý«ˆ¢Bz¡±k(ªJk˜ endstream endobj 1822 0 obj <>stream -¦)Q€3?‡(=Íé•Âf÷V»æ„ÀêbÔLÓaJª;óL®8¤n18w“_ÿϵ/…AcÕgx@bÔ’fp#áœ#¸%µ(/ª,õÊÓü µä 4êéh®å¥)c¡uăfY21ƒ½ÄRVûÏo+ˆ¿…õT! ×bŽáÐ,Ã59¼b5?¸ ëR5KÞÆÿöTˆnR©9¸±•Þå0e(¸ç¦ŽåÂéN…rmNNK¥×9¯4•¹ÅûºûXµ ›Ü„-…ÈÒ ±<-ÇáÌ”E$ ´äƒAù¼]ûÏ•IDàÿÛ3BÄ=>’žñ•RÇM~Ël$l^Éš<+D“ôLµ^ç“ÜpSdW7”‰P¨%ì"Qãÿ=’*-&&:ÿí»‹Ìmhµ+­U¨k#ÐtLoଵÝ»S«Æ¿áhÒMÐk)!­¡Q¹%®Rí ó, ˳St•¾'bÊð“F…Õlùñ¡Rxkš´içònmÉ{­|J!zc‚œ_X²qˆŸn©uQqÚRÀWnj©—O—#Áò«Îu‰!V·D#‹Â˜–Ùh–*ƒÁ•Zÿıºè•æa¼6¹èÍ!ÖgýÓCûE51)ñ¦&w³åŠʵӦäÚjZøֽÀÏ£´LŽÊtmS¢©ŸN~<ßr"™ÿ74±Yxæ–ÀÄf&Wäÿ‹'ËOYpŽï©‡Ia2|ç¥ÖÂÄñɉRÍñV ECÇÙû‡ŠÿC¢ð_Þÿ¾›¹køý¬è‹s‹æ¿d)íÿ¶^(¹ŸJ·üý ”Ìß‹¬O*ÜÜð½Ç«•J!Ï…©õ›îÿvš¼m $>4„P©©F^ýô}FFýUûÐA}¢ü“;-Ê —M=eDùäĬWXôüíVëD,ÈífÊåÆ/{…R¦öå0Y-ûÞr2ú~æ¿ê°†—™t»” ¿C_ W…Tõ™Kg"YIEnf½÷М|ó­wð÷‰Ë½L:[}æ5+rUwμæR€„j œd*Õbh='Î)?ä6ïV±$!8"7º&ƲZñáå %K•ÛïïPJ*fºÝ ƒÖÖ ei/‹,/E²’á3ù´ëÆáÅÀOùBê©P­„î•ÆAI} J”`/S~¨ñ“Sÿ¾šª‘…ÖC÷R z [ʤUHª5”ã Z)ò‚v.‰îKYž -)r«4ŸúÁKM‡ÊîÙ“JQoæ®=â«\×°µÊ‘†þbPúž fþW ­¥³•äm6—­üp³Zš­Â´Ë]5ÉÇÛa¡èua³Œ¶ž‹ôI„w2Ò÷©\,Tš>yÇ%#7-ÍGó¢°¡•*gR¾SnÍ_hŸIuBÅd‘’rö¹šKÖ{yöãÞî~!i;yÎÿ{ÎåùÏQ>ÊJY®*2nÉg†Ìýƒ$þ@ú¾P©‡l.]Ê4 ¹÷«ø«ò£è¶ïÄX¾|ó=Y*Ïû´?è÷dM¶å÷ò áò5¥ä–¤ÜðÐÖÉò™&Çõ¢«Ý[Æ ù‡óWëu›•ÚžôP7.\u(Ìé^?è?Ôý¿Ù¤cKôTÿl’Ãc/‚ßµWƒ4Ðç¾÷<ÔEÐ7–hQ½Tµ\)<¿­&û{r8WNŠ-(ÂÌäC¬WqüëãâD85뛢 Â(-ßý×Çhh@ïުϜRrû¸—v­}[Õ×½NÉ\å4yßK•¼o[£Yb‰»‰i´Ó þšI"º•è¥jµ o[7j›†Ù­Zå\6•é­Zµ ý.„ÕR®—úÈ`ý^—J²tßìÕB¾±uÔ#¹M¦žÄ8É÷Äeü¡ß¶~µY€—*–Êärb¶d«¼yº·ÛKåšc¼m») ±k|%—½Ï÷R5_àþ®•ØæÞs­|ß¶VzíàØ‹½•‘3ý½t•²ßkô_6-Úu­°¿åN…ìA¹×-–·Síÿ%Ky9qßU»ç{œÃ©¿¼]µ ««Ìý¯'îóÖaºÖ­"?z©È~"p¿Ùbì7ͯ‘T:YIFË™”šåÛÙÏRxërH&ìéÐó@Ðs]Ó©%öwšGÏ™FÅ–3ÐsÐsÐsÐsÐó£ç¤«=4zvÞ^·÷;/§JÕÛÛLéFl¶(†Î4g@ºÃÀÐÁÐÁÐÁІ¡ÇGÂu£• C×5"ü¡·¯:ú«ë††††þžzZœ¶0Ž®ptptptptpôþãèÌ6lÓvÚ… 8G§¦ðÿŽŽŽŽŽŽŽÞ_bPŽž-‹ƒ¾/iîÀòtJÁÓÁÓÁÓÁÓÁÓû§3Í †fkÝÖœƒGÓ-Ûqt44444}iz×=ºA£éÝkžÞ¿`$R.œâ)ï¡" å¯dòvå))ÿw¤œRǼýí–aŠÛ§@ÊAÊAÊAÊAÊAÊAÊûLî@ÊߌËZ²£¤¼µÅ@ÊAÊAʃMʉEœÁóÚn麥Ák;H9H9H9H9H9HyßÉHù›qY§ëirrrròMÊ cše™Dk7ƒÍÊg-DzmGÍÁÌÁÌÁÌÁÌÁÌÁÌûPî‚ÄÌ'¾U“¹låÇV>UÊ$Ë™ÁsÜ>8ûÚ»O;€­¿Ò[oW°u°õÅÖ-Ýr(£ÝŽe“­;šiÙ8q¶¶¶¶¶¶Þwrh¶>€NÜgË;ø:ø:ø:øú@ñu›iÔ¢úà9q—|]§F×[ÞÁ×û».àëàë}Å0À×Á×Á×Á×_L‡îƒ³#œœœœ}8»¡Qæ¶I“³3iݪÎÞßuggï+–ÎÎÎþž9{"ƒñýÎÖ»o[¥%¶Þ®`ë`ëÿŠ­ë†Ã »1 ;â K—é‚­·¯Ø:Øú«ë¶¶¶¶¶ŽñàëàëàëàëàëÿНS[×LÝÐÕu‹iÄ_______ï7¹ 6_ÇŽxpvpvpvpvpöÄk›èºÃÿ8ÊN4Ífpºººº>€t ]—ÎdÀ×û”¯ 5œ(oü€¬©ëâX'ø9ø9ø9øù€ðsâšc™ƒèeŽPÆ x˜AAAA@‚Žõtðó¨Ú3œ¥àŒzßòsfàçàçàçàçÃÏuͦÑ ¼;Ö‰Aô®ŽòÀÏû».àçàç}Å(ÀÏÁÏÁÏß%?/æ’?@Ïû—ž›&è9è9è9èùàÐsBLC³™i =7mÍ‚û8ÐsÐsÐsÐsÐsÐ󾓻`Ñód.Þû™Ÿ3 üüüü|`ø9Ñ-fY¦®uCÒàñsá2ÎÖuËè¶3½¿ëŽŽÞW¬ý]rô²PÀ»ÜOï_ž®uAà鯴ÁÀÓÛ•<<ý_Cç,9<ž®›9ݪŽÞßuGGï+VŽŽŽþ.9º:†ŽË×ú˜¡ã :::ú1t]s˜i™Ä”» s¬žƒ¨ƒ¨ƒ¨ƒ¨ƒ¨ÿëîºÅ,‡jZ7:L¦nÙö¹ƒ©ƒ©ƒ©ƒ©ƒ©ƒ©÷¡ÜŠ©—…Þåæ(ܺ÷3S׺Ž!0õWZa`êíʦ¦þ˜:Ñl˰»®;¨ë1ívê $$$$$$$$ýH:–ÔAÔAÔAÔAÔAÔÿQ7,êXŒ‘Á»M,©ÛÔ1ÌnæØz×ll½¯øØ:Ø:Øúûeë{…Ræ¦Z4žnèÂÓu<<<<}€xºCmG³ÈàyŽ“<Ý0©‰Cêàéàéàéàéàéàé}'wåéØú¦¦¦¦¦þO˜º©Ä64Òm“x@™ºE‰Õm³˜z×LL½¯¸˜:˜:˜ú{gêØÿ¶¶¶¶¶þ-Ó‡™¶Þ.Xðɺãh¶ŽÃê ë ë ë ëHÖõ®Ü"hd]§ ë}KÖK™T¡”¼½ïÌ4„£›8:8:8:8úàptfÍ´¨9ˆÝÖ4ˤ8¢ŽŽŽŽ>€}ðÔÁÑ_Pî}ÄÑpß;³»Ž¤ °ô®Ó `é¯4ÁÀÒÛ•,,ý±tð™)}d"K×£8 ––––––ÞwrH–>˜{Þ 2(¾äÀÔÁÔÁÔÁÔˆ©[×5“:¬ ªë¦æ0“8¨:¨:¨:¨:¨:¨:¨z¿É] ¨z.û}ݽΖwf¢ƒ¢ƒ¢ƒ¢E§†åœÍ&E7©¦á\:(:(:(:(:(:(zßÉ]ð(:v¼ƒ¤ƒ¤ƒ¤ƒ¤ƒ¤ÿ’n0Y¦9€ÎãI·›à`:H:H:H:H:H:HzßÉ]I:6¼ƒ¨ƒ¨ƒ¨ƒ¨ƒ¨ÿ#2ËL“XÕ»][@žN,Ê Ãb6®dQQQQQQ§]Yˆú›©öT2Ïu¶¼÷/I׺*ôW` éíÊ’’þo˜,¥Ôb–c àbº$éÓnuIïﺀ¤ƒ¤÷­III—$½\½}ÎV@Òû—¤ãºtttô"é†Auƒ‘tònhLÇfwÐsÐsÐsÐsÐóÐslvA¹÷=/< 57h×ËÅBÍáÕÔÔÔ|¨¹å8ºi“n—”š›–®ãê5PsPsPsPsPsP󾓻 QóA=…nttttô~#è„نΘ3€ ÝfÅt0t0t0t0t0ô0ôî5C3Õ~WÍåNR¥L&¿–¯dJƒ·’ÞÃnuuuuõNÔ JmÓ2ÌÁÛåNlf[¸LLLLLL½ïä.ÐL}@Ö{ðŠ¾¾¾¾¾þïùºA™É Ú YƒÇ×uÓv¼Æ¯ƒ¯ƒ¯ƒ¯ƒ¯ƒ¯÷Ü”¯ïf’ß3XYï_¦Ž‹ØÀÔÁÔÁÔŠ©ÛºÉ³éà1uÛ°H· `êý]0u0õ¾â`ê`ê`ê`êââôÂ/—ÀrõîÒÁÕÁÕÁÕÁÕÁÕÿ9W75¢;–n W§¦cíô¸:¸:¸:¸:¸:¸:¸:¸ú/suì‚_____ÿG|ݲtª“AÜ?+Üæi15PvPvPvPvPvPvPö~“»€Rv÷à:–×û—®ãÐ:è:è:èúÑup²n6x«éÌÒ Ç;;;;;;;ï7¹ ;Çú9ø9ø9ø9ø9øù¿àç¦a[Óºm  ?·-¦u;s~Þßu??ï+F~~~þžù9ޤƒ£ƒ£ƒ£ƒ£ƒ£ÿ#ŽN(Ñ '³Ý.I74¦GIIIIIIï;¹ IOþËc“{ßtêh è è è èƒDЉcétðVÑ NÏI·yôþ® :z_Q -ttôwMбÏý_Qt[cúàÝÂ&¼Ä鸅 ½ïä.˜[ÝAÓAÓAÓAÓAÓÿMgºcÔ±p%Ý`f×Kå@Óû». é é}E,@ÓAÓAÓß%MÿVM沕ØêÞ¿Ý" è è è èƒCЙcRÃ&Ýî% A·£Ýn‘Aïﺀ ƒ ÷¥AAA×[ÝAÑAÑAÑAÑAÑÿ E7™C(µÛ 8E·m è è è è è è èý&wÁ¤èØêšššššþh:u4ÃÒ¼•ôYbQf8DsºÕ \½¿ë®®ÞWì\\ýoÒ põ¾åêåêís¶2ˆ«é†¸§vhzÛ@Ó_i‚¦·+h:hú?ZMwt8Ì醥¥é¦f9š šššššššÞor(šžJæ¹®MïgšÞý€=hú+M0ÐôvåMMÿG4P±æÜÕzPiºÎ,ÒÍw=hz×44½¯ˆh:h:hú»¤éÞjú`n|7XW×è¡êXQUUU ªnÇ1ƒÞùtEÕ1ônþëAÕû». ê ê}E.@ÕAÕAÕß%U÷VÔAÕû›ªcUTTT}€¨ºÉlÛ6œ<£N©Ipi:H:H:H:H:HzHºÞuû1Hú›©öÂÓ@ny7ÄÏ;3Msssó!çD£Ž8¾Íï²tbÚšvvvvv>xìœ 9']«vþv»ÝS¥êmÛ“iß§wü»:î¤P-¥2qÁÿˆºû¨ü†¦èáþ†ÎÖ ¥çäKJÑ߀wÙ\¦càð‡~óɆÎìANùœd*^£ro³x­qþ™×Çš RJæËÅ$O.Õ“nk ÿæ2йr\\+™Ò‹;š›EÛ Ûç•Êöx®™ÕB®Pê‰B6„ïóÊeó¼rÉTo}æýÆ#ëòŸ4îó«z﹩ïÞo»ƒË?£7Ú:Ø4ç€v×)?€6@  Ðh´ÚýÚݼh´Úm€6@  ÐîÐîæÉ  Ðh´Úm€vŸ€v7wm€6@  Ðh´û´ €6@  Ðh´ÚÁm  Ðh´Úm€v0@»›¿&€6@  Ðh´Ú}Ú6@  Ðh´Úí`€v·Û˜Úm€6@  Ðh÷ h¸DjµÚ@m 6P;(¨ Ÿh@m 6P¨ Ôjµá ¨ ÔjµÚ@í  6¼¢µÚ@m 6P¨Ô†[4 6P¨ Ôjµƒ‚Úð‹ÔjµÚ@m vPPŽÑ€Ú@m 6P¨ ÔjÏG'š¡ãÀà ðx¼ÞAoÊÝ´(V¹Þo€7Àà ð -x3؆i`Úà ðx¼ÞïÀ€·EmÍÒáà ðx¼Þï €·I™n8¶™¼Þo€7Ààð6lbk6¬¼Þo€7Ààðv8zk. x¼Þo€7À;(àmÛL'Æ5€7Àà ðx¼ƒÞ±™iâò€7Àà ðx¼ÞDc¶øóæ@o 7Ðè ôz½‰f[†íØ@o 7Ðè ôz½ƒ‚Þ:Õ‰®S,{½Þ@o 7Ðèô¦„ØÓq}7Ðè ôz½ÞABoÇÒ){½Þ@o 7Ðè ôÖ Ó¨ôz½Þ@o 7Ð; è­k:µ¨®aÝè ôz½Þ@ïÀ ·¥êh˜9z½Þ@o 7Ð;0èM)µ˜åXðÖôz½Þ@o w`Лqü&ÄÀýb@o 7Ðè ôz½MjÛ&!X÷z½Þ@o 7Ð;0èmë¼uO©@o 7Ðè ôz½ͰtFÞ@o 7Ðè ôz½Ó´Á½Þ@o 7Ðè ôz3Í Ä"N»¾z½Þ@o 7ÐèݯèM9Çc@o 7Ðè ôz ½ ÍÖpb è ôz½Þ@ïÀ 7¡”ŽÎ€Þ@o 7Ðè ôz½uÇ6¨cÃS*Ðè ôz½ÞBo‡™¶O©@o 7Ðè ôz½™A4Ó¢ðµôz½Þ@o wpÐÛ1©aã¼7Ðè ôz½ÞÁAoð™É4 7Ðè ôz½ÞAo“9„RëÞ@o 7Ðè ôz½MbiTÇyo 7Ðè ôz½ƒÞŽ®‡ÁS*Ðè ôz½ÞAoƒhql 7Ðè ôz½ÞBoÇ1ƒbÝè ôz½Þ@ïÀ 7nƒì9z½Þ@o 7Ð;8èm9ŽnÚwŒ½Þ@o 7Ðèô6™mÛ†CÁ½Þ@o 7Ðè ô -z[–NubPìZz½Þ@o 7Ð;(èíØD×þ/Ðè ôz½Þ@7Ѩcj–ÃpE(àð ø|¾ßoݤ¦m2 ÞÖ߀oÀ7àð ø|[̲L]ÃÒ7àð ø|¾ß‚o‡jN¾߀oÀ7àðøfLãì›h ð ø|¾߀oÀw`àÛÒ9ûf8õ ø|¾߀oÀw€àÛfµ¨wç€oÀ7àð ø|¾ 1S߀oÀ7àð ø|5lj›ð ø|¾߀oÀw`à›0Í6, -·-€oÀ7àð ø|¾uÃáÜÀÖ5À7àð ø|¾ƒߔڦe˜€oÀ7àð ø|¾ß¶®™ºµoÀ7àð ø|¾ƒße&Ã}¡€oÀ7àð ø| ¾-êXŒ\Yø|¾߀oÀwpàÛÖMF&Ï߀oÀ7àð ø|;Ôv4‹àààð ø|¾ßoS#ºcéØ7àð ø|¾ß‚oƒØ†Fpãàð ø|¾ßo‹ò?Ä4°óð ø|¾߀ïÀÀ·­ëšIø|¾߀oÀ7à;8ðM Ë1t[×߀oÀ7àð ø|Lc–iâ¾oÀ7àð ø|¾ƒߦÅÝ¡àð ø|¾߀ïÀÀ·m›šn踲ð ø|¾߀ïÀÀ·£ÙÄ4l ìð ø|¾߀ïàÀ·nkÌ6 ð ø|¾߀oÀw`à›c·mÚ¶®¾߀oÀ7àðø64Ç2©ø|¾߀oÀ7à;8ðmQ¢3‡¾߀oÀ7àð ø|[&s4 -¯k€oÀ7àð ø|¾mf蚎­k€oÀ7àð ø|¾‹9†fcòð ø|¾߀ï À·®Y”Pð ø|¾߀oÀw`à[§³,Ç|¾߀oÀ7àðø¶)'à„0À7àð ø|¾ßo‡™–I,¬}¾߀oÀ7àðø&šAm]ÇÁ1À7àð ø|¾ßÄ44›™Øºø|¾߀oÀwpà['†mØ ç¾߀oÀ7àð ø|SÇÒ5SÃä9àð ø|¾ßÁoF-jØ&Ï߀oÀ7àðý -øþk¥)+ÙçìϤ¸~)Sùî¿·.Âs¦’L'+Éß-‡ó›åIRÕçL¾'{ÇØUZÇ™$WZñ\&“ÞÍÜUÎë)knÁVK…âJ)“\á:ç{¦e@Nh!ï‰iòŸ5tïÑИ÷hZî×IM7½ŸêEwËYËSdãö—Imêie+áÖc5™ÿž,Ÿd6[+[D Ý儎ÉgJ¡b)SΔ¾gB…ï™R‘gU)wŽP¨VrÙ|&T®” -Ožbµüк -* -}TM沕¡ÝÌ÷LN…´ŒZІdKÉ2WìÑï™T¥P -Ý&sÉ|ªKÑS¹l1”*<s™ÿ…J™{> ËM˜óBÙ+™ÿ¹=AxSÇ|í<ñ´²µ^Íå¼v<Ï”Êb|WJM…áá“%.C¼ØåU^ -Þ"d#t4„ºxȦKa\ïd~4·†kÏ·™tKH­&– Oª·åLe½À»îX(#ÒmÊz˜XÅå!o³¢wZšìdý"´ö¿b¡T B«''-Ý B¬ŠÖ翯”*·…dɃãf3¸é½ÞÎ*•ÍÓ½ÝP<™zº/ªùthë9yŸ &+žp[–¥“ºÐ´‹äÃJÒ=`褒¬4'¾ðgåŒ[Œ•²/rMU´Oº½4Có»ÖPì“\6• ­ó¾íóN ‰î*ä¹0†N¹þ ©,ÌÞ¢”Cu ³×ds¥iÆ/Æc¿ºñìWÆÓÝÎw^4uê˭ؾ[k·hºÑ“ß…h¿˜£Ý¾YºÄ²~)–ùK±Œ¶²Õ%kßú]bÑFEÙ[$·£uíU±H;ÝÐ-’Öh…t‹ägó=o/PMú¨'Y ]dóé­àÜî,Ÿý_[åæ´—L5Õ÷k.46Z¢ZäC„«O_â™^MOOd…êôÛÁ*¦Ò¨ªî -¹4‡âýšõÕT—ºú­n[­|*Wå¼ïãÞa{|*¼¬¾eñÝîiTÝz+‚xT¹ö’ÅÝBJZýö`§§þé™CŸ&.²éÊÃf&{ÿPéžøI‘ó`a,+?V3¹\«õÓg£°ËU¯£síû ©ª¥yœçºäv,WåG.SöOv,ïñš‘ÁºWw³PÊþäÆN2×snÄU¸ØæÚaxcï×~ó쿦߉A¼P©ž©ïçcÑ/þzZ(ú~3¼ß6rnýgŠÕ\Ýœl±xÿI&·™¬ð ¹Ì‰‘UöñƒÂn‰‰”­„?¤ÿçÓ$‘«÷/^ªPJgÒ­ -Íî* ?ûäÉ å urÊæ¥É^(g=lâr/“ÎVŸCÇ™r!W©^7¨¢‡V¶q6[¼~Š=n+ÙŠ§þ´˜^-AÓ™;Ñ6ÿ ÍܨûZ‚¹²Ïæï -]‚ ®Êési šŒå6YjV?-o…J)ÜÝÅr™»æIŒ—W -ŞÖ@©[è[©kæä ÁŸ“¥§rc©{\+ua}¥î!´¿Ôä¥>©Õ±ZÎpM)•yùå~¼ËWbé\±tWhφ¤Ë±Tó, áøÈsyÔ7øZBþ¯+•Ú ¸v!ï›C¾.UÈs]^©Ï ´k¦z85KôrŠ¥t©Ëäؤkéµö’ æÍã”Ë/çœzŽy3Z©çO/gì X¨<ølÌö}ÞP͡ХXªZî,=< ×&ÉjΓHíd’‡ó©Ëy1ÔƒÏRœHdJ‡n„%n䕺èA¿>ÚvH§šJòr ‡6&kK ¹8Ù‹Žæê¹±l­ æJ±g»SÁJéX¡tëXx7Ì÷–)¶æPenZe¼´º†ûÞ¡ä2P1—úÑAŒe˜T¾Ü©Iy˜ -gjùû.²[æx—0R§uâ’§wÛY©¹†.i¦\½õjEÛ«·\}¶øx›Øß1H>sŸ¬OË¿¨póNÇ;†É‘”$K-fN³R~Hrªš)wÐbE¥Ãê¬fa5)Ïæéï¶ -–›w5u¡˜ê`ˆÈåU—ÒÕŽj‡Ì£wÀJ¥Wó©ž‚ Ìç n?Ôã–PÝ´0×üu)8‹ÄB™[n)'+\y^Mœ\^M†¾ëK$DNÐ7Î4…ëÕYoYiâ2¡Ô¿Èqö<›Îf÷ -·<.­ÉÍÀ\FÚ¼ K†åJÎCI·<\ëÒº"š¾Þi½Ä)¦ESæò=ª˜î9qÕµÄ~ 匓ςì²f>ëÒgÑNE@Ùµ·b¬ƒýY è“éŽá’åÛlå9ÙA ‰ *L/Æ¥@tÏj,:™Ê"dmFá6—L¹vžn½„“…’`”]—È©^ñ¡PúY›”iJN_øÓzÁ°ø.¶ª» n¸ï= …ÅrpÔ{jÞ%Їr’eÅ ªÏàú<çŸÞªC»Éü}U®¼ŠÕ&¯OtX!–mg´—BÖ(D>ß^×K9äEæ6å}åS×\®s¨òS¶È…)ß4ˆ`%n”ÊQ¼RoÙ&ÝÒÞM_/†¯n/G Cm9³Q -¶ ·[ù»‚_š&¿š{T{qb贅½&)*&óžáF cþÌj!ÝEmßjÉl<ëõüÊÉêÖ–m$2¢qÄápx­ênÇoŸ––hbö`Ó™_OFJ‹ñ“»½‘]:¿—.´ðÛ<^ž;X®8Ùõ½«ŸöÁ§êÃúØÆnñçÏŸáðä×D8<5>OlElcwíàgýžKX_.mþ0Z¯§+Öõ}Ž?DŽø_ÃöF|9³!Ë3ö ~7–ϯ¿Mò‡ñqùºö5µµ-^çåkœÚóÄë -|ú95'^SòuÅ>¢Eþ01,Ò^X±ïøÓä¢x=ŠlŒÇVføó”4|¼yÚ§üif_Ä^[Í–OgÅ«,¨‘ˆGËü!Jä¯ë«™Ò7ñz&^£k_—¾Mˆ‡$ÿË1âúÃmI¾Êº8¼d¦ñ\ÿ}}õîzñ§ùÙ,>¬ÝžjÃë ‰êJŒî~˜¢ñÙèáÊé·rd}->¥ó¶ž¸^»»LÜoF;UúE6™lL:‘?½2~Ð[tOOŒ^Îi_ÏÉñÏŸcÅÑÒ²ingïÍÓè§ÏúZ8Ÿ}x^šöúc("þ–],:ïìÎí¼©§Ïê£ï×Ñoš‘aÑÎÓ7ò#Í?oójŽï|៟²^Øá9Ñ;7ü—­ãzi-)-ñ£“6½Ú‘ø§ÏÇ+ÇécñµÙ&Ê3»ÿöe:±ô´¸6Vø8µ¿2¿ÆŸæÒ3Ëß>eã>Qª§zÀåL¤ë«~zìéÛÊsᾺ¾°¾u`š;©óÕìâæÜôÚÞ.Yþö!eM¯í®ï›t´šúùsöi{'<½T)Yn å·çVNf–ó«Ùûte(b=_-Å™òkíóÝz|ynÿñivçnšYϗ䬩4{ó[å̓µ[m¦º²óiäŽ÷äãt<ê]&¶Ò[ãC‘xn9Gã9#rkY³å;ºRJm‘é'çZ á£mžónaå¤~˜Ž¯éw+¤^^¿]±£±áÄ]ôŠ&â{{KÍ]ªúò§”áŸá‘I p»8<œÞ| ‡ŒËli5þ°]åvûjrêz8<¹ÿñ[xjΙ’2.û•‡pGìĵxYŸ(ØÚOó"š›^.OÞÛ⧨íðXxxìz.<2“ØêÓ·áˆÅ‡îØâÁe|NÛO|È]†'×N -á©ùXxúh8ž9ÿrŽ^­=†c·ÑÉðì}v1¬=…IÙÊ„éHe4L«gfØ[Ø›3#_¹)…íå=vÖÙfxî,ü%<ŸJñ -/Ž]Xᥥíƒð‡óÅûðržL‡ãsS‰ðêåÈMxm¬4^?ü¶ÞŒ¯Â[Å‘ðN´ºÞMFnÂû¦'ÇcæVøèv%>ÙÚcá3íãYø¼ú8þX˜Y ¾Y|à¹\}<³Â_ŽrWᯧÆLøöüø$œþX ߥ—vÜׄŸÆ´ÍðóܧoáÂAl#ü-uñ-\™Ñ7‡Ã[ÉêðH1¾7<žxøx6<½úAŽ–#_‡µ½äü0%{ÏC‘aãqn{ØÞŸžŸË_ /'†—KŸ¾ ¯>Ÿ ¯ÙaÃ[×[¹áݫ̓áƒô>Îå‡Ï*ç§ÃŸ4žÎÕJnxøæ$|3|ûÌs¾›ßÒ‡³g<ç‘âõpñÐÞâ¹TÆÏÌ‘á“ÒèÈûð02™½½‰ž˜›#„~²GŒ1:=b?'Ë# _çïF–?$ö·F6O´õ‘Ý‹§Å‘ë#6rú¸ù429>rí‡G’‡ÉÒHæþäyäQßyŠŒäWFÊc+÷£ÃîFÇgVïG§¿l<Œjó;£FøìyÔ¹ºù6º´S ®&Èøè&]‰ŽîM_£Ç3åÅÑ‹ØÜÆèÕìùáhrnärônoçaôék¹:Z¬lÄ"áùêâP$2öq72]¿Šýd>bVV¦# ûcK‘¸vwÙx8zˆìí,NFN¬ØräÓpåcäKîé[$ý˜5#7_#Å»ÔóX8dcãOé£±ØØsqŒYÃócs‡ärl9»21Û0ÏwÆö>>åÇNÇfÇ>mÜŽ%µ,»Ï—cùÄEl¬¼+_DÇ£™Ùãìü:6>45ß)°ñ­ƒ“ôøáÕÒ‡ñ‹ìDqüKõaoüÎü4=þ¼»u3^yZþÀõßøÒbx"vç|œ0snbñÑ®L¬­ÏœØãZqâ426qu•LM¤·‹»¹¸fNTâ;ÓãñLjrvuúpÒÚÝ]šüð¥›Üø–(OÆžÒ“·W/&¿Â;“Ù¥SžËä·œmLEߦ§bc—#SæuâÛÔ‡Mö4µIG3SGc…äÔ§BæË7Ó®¦ž²×—S•ÂÍåôääýõ´nn¦ç7‡o§_µ»éý™Dnúbïci:9\ŽL?îÙ±éÊð±5™™¸‰Ïèë[û3 ÑÂåÌZy=;s*Ì|º>¤3©¯tmæùöé":œ?}ŠF#KÓQk.º]ÙÿvÝÉÝ¢çÆ~½ºØ‹>ÅŽ¢ÕûÏZl:~¹3Çns±å‡"Ï%¶s>q;ß]%wÎ6c¹í|nvx›.ÌFogíôˆ1»ZÝü2{0W¡³ŸÏ¶¿ÌrA4f¿~¹Õ&&V4z6ò¤}0’ëÚvåpD;¿O\h·GÔÐò<_ٚ؊²?9KO&ÈVRÛ#gK'·dµ@ò›‡çzä[vE×ǧõ¥ÂZNßYýòIÿ8ÛйéiéßvGÆédâ$OM6ù•®_Ïè¡ߦ×Îè2}ܽ·ÙðÅ6a³•Õi¶¸`±íOÓÃìãÔh…e>–Y™Ž–é§©Šá\XÃÆÆêjÄ8›=˜4RÑ{Íø63e™SSñ¦M¾nšëñÙóôøäƼÍMäÌoΧ1kꊙ–3™^çx¶ñeç£u¾¤?YéRaÊ*§¶ì\Ø ››E{g5ÎìÏKóûvvgùÑ9XÖ=³sèÄÇ΋ÎÑÚÂó53ÊÇ»½037•ýt47·>æ:ëÃÆÜ§ÌCq.{º˜ŠÌîä -óluc}>‘/ÏŸ&®wçÓÛãó•¤v± MŒ ˫مÇÔÖBÒ¾š\øv÷ùëbôçÕÅ¥©ôäâ~ò!µxs>º³XÜ6èÒÌÆNii1q{½´¿3µµtóy÷þR1[û®>}XÚ/]8(î~H®Ï$>”ŠIgyö`cvyÅ¢ãË'‘ðrúù©¸þrý´B“—Ù•µô§û•‹û‹»•ÇñäC||áé1îUŸã;E­ÿ߉K©é¡ÈjlŠ®®è»K«'•ÊöêÝíÆybôc5°öˉíƒX,q}ñ°’(~Ý;Y›[Ê®Åí©Éµ³«ðÊZvêùÓúøÅcy}~öÁYßÏ<­ßTÊá¹ÉÅ #jÙØšÜç¹l\GR{ߦ'K›š³³º™8,=m~|X[Ú|žÊÝoÍœî,m­LN>n]¦V·ÒödUßß^ÊŒLoŸœ>\o?œg–v&.Ë;‹Ÿ¿œïpìp}™­ìNØ¥O»‹7z|(²{2¾2µûp~ù¸7IÂç{KÙøêÞéYVß{ŒÏ‡÷§­û‡ýsírÿÂÙß^¸JÄöÖç_4ýàr¸:sðmíiüPHŽn}¸ªÞT¾TŽÂ×wÕ#{½0|tàLD†"GwÓæäñÄì¡vü>ZÇçöì‡ãçý³í“ÙÌØÙÉÆìñíÉ—ƒÉâixøjúÔ>ý°pz87qpz_¹»=›JœÅ/wæÎ>Ÿ,•NçŸÎ/‹ä|ïaiïünlíñb2~†"+÷wgŸíÈðEénií£¹yýøñ`zbþãýÓ^êÓô×QëSâúìöÓõ¥n'³wŸçv?|>™+|~^›Ü½$wå©Ëzÿå2ýåvéjr1¾Zd?_]Ý—®Ã×±±¡ÈõüþÜíõÙÑÉîuá4g}aIsäËAøóÝ—¬5uv;;[»Ùš ÖMêãÃô×I¶Uýºš'O_¿\VRÉÑ­Û«ä‡åó‹äçåÓduëðèvþøððö<}~x[šº=NÙû•ó¡Hê¤L.S…­dÚœ¹L¥´Rúùür2ö5#s¸ø9žÉ­ÎßÑÍo©»ƒ‹Õ»§»ezOuºup2vsÿT.„èQ~þápöùü!÷T*eÙÕä|öèlî2›ßßåÖç£y˜Úz<¹š~~,Þo->9c¹ôÓybÅz*?“¹…µ#;÷©J2Ïß—ž—NžŸ¿èëÛùñ g<¿6N®ò©Ym±0cÅ*…íMzQx¸]Z(êÚÁHñðäæk±0ÞŠ|³¿.ß.¶’Ã¥0eJ˱ëóÒÍ”µQžŒÜ9ÿ·TcÐmøjBžhü}%]¸Í„ëî. ±™@œ‘û+÷­p -:P?ùöjX–£ùɱ?To¼˜}8»œ^¸XŸO~œÙ¦cÑøriãùaî>Þ^ÏLŒ¯f“±ò¨y¶¹fŽÌ-Ÿm,í±s»Wã{Ë¥jÊZ_Ó÷ì'é#šVN<&îg´Ñåù/±©å…™by¹¼£ÏE–çwÃ%/Ðv%~¿y´»¼À2'œµ,¥±Øø}KV»éOoT×qö9:ÃiÏnyeë¤ò0½dŽT×lô"þ˜¿Š$î´íÛ¶‰ZÎu~tyµrº;9S¸¹ëå…§õëå¹rìy:1©®Ol¤ï†"²±Ö¿ÞTw×– ;çîâ•Õë3ihޝc‰Ùý¶¼À-"•/ryõËý—û&S8µGWN¢#yU†Étu(âŒGKÓWÕ•Ý“±o¢ü“ËóÛœ[›óç×Ë+ùÔøóôâÞü,'‚‹ÙÖ6Gj)¦ÛåsÞlÖxƺ Zz.»:›äýKö'¢3™xÎ:|V5ø´Y^ÝZ¹X›q ζ[—æÈ’µZø2½pž¾œÓoG®e²Kù¯Ð’95"ºäÒ¼0ò¢–âO“fÔÍóô®F®Gö³É…±õðôç’ÈÅ?|‘©È Cívx‹Éçé¥õ÷iábmG_YûªÓ?é[\t?jÓKKk3zâÃý¢›ÎÅâÂ|úqÿ‹ìÉZyzqÃÍ…Šo× -p]/™X<2L~3ÂñÄljA¬™ùÙ|L­œ&§w³;ßÖ’ÉñѸy{v´°™¸YZ9}HUVGS{+§:å½Ïéö§'ýyíã×ÕZ)©mÓ/OõÄì\¬´éuاBâîd--Û“'›œœ^™¿P=$RЬÝéó8û¸½¾\*=œ±¹½‹²‡l#[2yçMÍLÇ Î—æ¦l¬¸¿Ý½vR+’âvÒôbub=‘#qmÛ˜ãmhY•Î’y[Xž?­ ¯œnWª­MÙÔ“¾v÷:þc),¾r=ö-–]in§ê±“YŸ+N®>˜ÇŸ×nµ…©D¦TšÑ8ÚÌ× -¢š£Ö»+7ÛDJÛBô뺩;±ÄÖ£•Tc_u¨}òíygåàK|o}õnÛÖÈÎmz}5ýüI*Ï6}°Ï™‹õ´ÍÊ.G¼ÍӑŦ2 Ex)2‰§H†gu´ 'T´»¹‹Bki›Ã¥øÓLe£8|ë8Óól¿©Eæ·Ê…»Õl9k -m½<Ô'G¶6뵚ÏÌ=ó‘|<)Äkozqûó¶—éý×c”ÿÙڨܤŸWN¾n'f³‹ë*»ñMsåt¯p¿|~º•\_³>E¦µµ«Zs×f -ûúú˜9÷‘÷yÕYK=}ó2$—TŠyìr|—«ÇÅñ•ã\qÊî(¹ÉÕß8³Ž¦b+;ŸNòÜ~­«pï÷›åSkì`u÷Û)i€Œ©±ÄÝÊø— 8^_¿™ ?Èjp›Ïð!eÜ6ýêö¾øý©i|±§8ˆnÖfNS‹¼.øÀþ8:½´hRù«;é–=J‹ª…EÓÄÎÎft}a͘”¿ŠºÜOåUðÓ½åH<·­ÅD_]ÖǧeÈN±åóÛYëpsï˜Ü~9[¡cáÑ5}rôË*ÙXÝ]OK\ÄÉ¢–¹û@f&V?Ô¾qû¤1Ž -)¿‰×¸PŠ«2¢|5Ovõ#ñ뢌]Ë`U|‹«¤V¢ë–Më7Ÿ‹k"È×É"¸ø¨eöëé¨\D~I,× -¿T‹1/ƒˆÒÊ"É2ðºðtVTQD5U…E¡D뜊oó2±z.2‰æ&En—©|u[L¤xÒØ˜2μøUVãC½)U`Q8ÕŠùûù£ZœÈö¬å²à«K½ó–:vmÏÑÔ C‘¦ŽPqDcÕÓ–ÕíÔØ‹²VõW™T-çz8oèË¥v"×±KT‘åS­V*Óú«’±¶‚уXˆÀ»µZÕE¥YfU]^l¬EUS9r¼æX¬×Y>hרM#u(RkÂŦjÖÚd®1‰¥Y­Ç•¿6eêöK}Üù$¦¡W—êR+‹–Xi3Tæk%<¬)%¤ª.ë²e²½6µ¯ åE69ï}ÑŽµ´—Ú)@YµÚÐ|ÊQ-¶PË@–ñØ´Éä|RÍ_«©ežÇ.î9+ù•ã»ûnVî›cåô|'¿¾LÈÓPd#²qÃÛĘ0}¶Iõ(²°~S9Zž×ÃÓkç7=(‹ŽúÌ ŸUÐÌ’üá¸$ b ÌÁÓ>jFNXvâæ87ý&/_dSÖüçÝõú4º-y@c…¦%AŠØ…mÍZ‹ÎܱÄ·oÌŸKü&³rœ?9[9©l=¯MïÎN4þš[_v"ETOÖÉ—Ê`ëòôÛÊÁjüPØ0®uõÜÐ0œ -+¬±¦>cÚO¯XWÛljíÒÔ×v ¬›×[+;GÜNvKvyÚ(dJ®é·kÆ9l_ÅjÜ!Ö™;tfºð¸ƒH̲ή3;‰»£òÉlöð’›ÍkßV•½MõáËÎdèE*4ñ“¡º„Šª)†ýqå`=ñxq³š}4gçïž#÷ܾ"¼M–¾ZÖqº -­ÛG®{’»®'Å%ÙMl˜…9U›XJÜG'?¨ ŽèÒWn¨ŒÿöÞ»»±ìºýÿ­…ï@‘sˆI€9‚$$Š ‚‚'xÆžç·f¤Î±BwË’ì±%Ë–ƒ²,‡Î±bǪîVK²gÜ-ËVwe²Öz眛/n.—g¼dm£Q¸—'ÿÎgï³ÛÆBºð¹bŽCÙËÞ’¦a°Ñç`2‹†Tê€Æƒ<¶æñÅIkŸR1ÆÖ9€ÉìÐ,(ùŸ)ýÓêß­æ CÆôZ)ìOf -ÞM Ž§6GÆ5Æ.vJ­_a))ØKÕ®M%7猰O§“ýF -C ÒT!ðc×êðÐ.®¼éÕ¢a :h¯94þ}>ûæAë²Ï»žOMFA_ -û㸂ß.hbSã3óé¤~ƒx@-öÚͻۮLÚò¹JÒ‘Ù6ÇÒ.˜—ÄöŠ:` gJ%be-`-¹øî˜ˆö“›fÐÒ²ßu„ÔÔÒ` lìïÙ ‡£½DY;€ÆÇQ·Ò5c’Ò8ºuË”12_>$*˜õFƒ¹B?P·Õ̲'b3™S`^B GtNíGs€f ¤k;ªpÉm¢`‹l7Ûh’ýS`Sµ¬–A³ÍT©n¯DƒsZ ÍHæpïõ7Û“§b³så¨ °gK¯D 5Y3¹;³ */]Ûä[1vòÍY½ôÂ$¢×I·( -ã׿ðĆ’WuF½´†@ôn•œÖOîÓI÷’Ã. %JÐòiÅæièçKÛh<Á¼„=£í¤ezÃŒ -aè7w6~Xm˜ýíØä´µØYõm‚_0€y¡‰7; -YÁŠÉ€€²2—.·­ìJáÃ}0É[jèêS¥À¹jÇ|•ú–Åž7á¿)òØìà¡9­«ùõ¬GöJ~ÄAAòWØäqs|oß¶ ÖËî’'˜(Dƒu¿½³kø{p^À›^ßTÍÀûz%°±Q9ì|eÉœ´ù—´éDÕ³›M–íñ=ß€Ïæ0îDS{hÂh;LÇ*Bç¡õÅešäXlz6zع6š‰ÐX3HkÊžˆg1“OÌGHéЃóïðÎúrrd}z2îZp´:&~u@ ˜‡m*­äýÙ•t ‚ñI´€…–ósƒ±ÍäÖ@Ñå Ô- í¨¢Ô Û¬Öà¢[ÖjJpu§*Ö¥:SòÆZ曜I—†f@ÿŒ+©ÕS­udƒìÏL+U‰t*M`Ìè\ŽÍΩ‹%2B›Ç­Tø²Èc›0ñÏž’H'bE "FGÁ>–4ͺI›!ÖZÿn,5óú§·ü®µø>èdÜÆû -de¨*éͦYR<ZØì|d7:®/@ÿ²ÛGÕø®¶5wú粡—VROq1QŠÎ²kÙêGªFÇ'ZƒÜp¹*ü:€Š°ä§ŠØ}êñ´¾0ÙŠå -ö Z¥¡ÜøFrcßo¢ŸY€–éÀ.?±»Eí¿Ø&\[ÛvÓJž^`®q¼v*¹éÝKV ;~­1œŽíô#s(k½€Ù‡Gyñ„u%™Ë [1QÍ15cN§ì›ºt 6ÝOLè‚ìü³VO( Ç=šº;9RÞÓtì?{“z06Åi¸—Z’¹‘þØ-™6µ' 騭Us~PI« &;Paçàßø9Î5ÈV¬Ó ÓcÊ¥wÖ»Jœ]E5ÌÓ7|‚iÝÈ~Ì¿½2>NNŽÍ¤5uØ\ª[Qg|ÉEaƒÀ7JÀBgx1ïÌ@"þ?6[ôœµÀ—†2ÐX¼^J9;16°séâs)]³R„‰=X¶¦i Í®¹À[ËL>îÐoÎra׎n@•9«mOèš“RѲ'4>Á…Oß—Ñ)œ+G²<“YÉh2EX/»mÚË­|ºf?:ˆDtF ådOt,i™Ø¦­Ú°ÇTKô&ƒ\ JD÷Ðac°ê_ŸÇà<£sôžÒMG:hê§øŽ5FgÛõÍ´.—ñÓ'­Õ©•ø`/6S©obÚ¢ÃÓ¿ßï÷¢IJÑlý@%Å_P- Îá²7851›iÏ9:Š»‘Ùßi¶ß-Üó¤×Æ4~~ `"0< Fll#?À=Ý„Láó׬ë©J-kyovh¡˜*¯ôÇ÷C4M¬1šô_3½C;·gFÃ]GO!CÙ,IÌÈ=2Npd´}žjhÓCíz5îjǦ4mšNŽ^Ù×ùÀjIíÅOšŒ&G6¦ZÉQ. AG°s£Ø^y‰F©ÖЈš¨y´ ¤ñNá5Ï%Áâblc`®;SlÊPr}ßNߎGÛ-ÛÈrf˜…¼/@@YŸ Œ¯VÚéµUÇ>\cNò0}‰¾”BÕ8mû‡8ÇÆAcÛ]ÌaQ—ܪxZ¹V(]Ú³Xµì¬š¶Àl4 ÞÀªqžÙóâÔ8@à*Ç\ZmÍo_ÈYc¾L³Ý€@7R^Œ6õ‹ýÉÜhñ0Y^í§& Éük.À¢7ë`ûX±z•‰!© ÿÖ”«l6]jÍ騶:Ë<Œó  `; ¡LÖ5oû@}¦LfÉ7»’ªÌÆ’[î¡ÖîEn\ÄžErilŸÂ§$…æB¥AG‰íåáÃtl2ZŒ5Û5¦iÐã9´û§“ë‰ònÒ°c]÷;SÕÔÒæHŠ4O¢WfâgÒ7• Ÿóå ڶЈM.ygײÖt²CÇ’S@âК“éƒØàŸ³úønpØŒ (¬·À7Ӟݠ7°Ý/tª?îÖ§­`Û$·h»%þ|ve|ìæbÓµüš'|¨ß¥«ÌpŒãÚá|ÊTŒ}ßãØ§Œ³h°ï]Ù#>4Œ&+‹Õi€¶p6S(Õ×ÐI‡gäÉÉÁí„!°›ÓžÆT6DŸØ¢s‡qÔ$Â:ê˜ÒµàzöÌMnXRçLi]ôæ©iSrT½i£÷{¹n÷ÌnÆKHkòÞ«lòå6ŒYÚ:HnÖŠFd:â´_ã[}ܭó™¶¥¾Ë-é}ÔìCmj½Ý¿ê›È:gýNÓh0]2ÍX}!Ë™MÕXl›YÎZbk;­…§Þ>F“ÉêžL¬vØ´Bdq§0@?­¦6€Àhy~Œê?CžòïXZ›Ñ¤³û¤Z¤…AKrÔ8à¦×¼×L­WLЋ`ÁÁÝï‚_‚òÚ0ÃÒ]ôFƒ«ævl6á-­shØVs9V‹UÓTã°RœºX0,ÎŽ#³ödq«èúþÌ^ÔJö‹É €¿aÐa†(šBQ<”;’E=äŸïˆÜ9Ø(ú· ­YxµUÜžØQ/k^Œ†õämÐ|€Ø»[0ØN°ßÄý¹JZN5v'ÃïŽî -G¹Üѯ+®:ÖÞkíÔ÷ª1f`H!÷%)0Òm2™.ÕjëÛÚ~5YûüA³ ¯Mbß;Ä®/ë[®¿vÀê'Ú­z»ïä:há.‡Ð_p²¶·CÜÁy} Ñü /œíƒòùZc7O…C»9Oaüv»j1~uç MFש&PÈ.¼³†ÞXù=¡®Ƽ+)·IçÝ5ô ¤¦Ý»«Ô>'<öÒ®öT‹yqOnç@Zˆ;sæÁ(n â‘ °v6wÈàRÁNgå/ò¯Wy+fš -vw8xV:ÕeÙCÍ9ZøÑRjevUN¥“ø=?±õF­RnåË_¬6¤Å⊠_–’vÎ%"o‚f…®_!šŠ7ÝÙÈ¥pÞî-¯™q‘;´èÊ·x®Y{6ÝíZ¼;=5%Âxc-ýÎ{üFöÀ°Ã«ÝÀæßõ¡ÐÕÆÑ×aµµÑ¬OÂJ ³:•6D¼Q5^o]iÞ/à•Ì:T)µ[z<3ùÝy¬ÒÔÊnš1ÀKQ[~9忬´?{ØôîLy8+34v*™ÕR•FwK‰O¥ËzÛL Úä®4g^ÉmTM-ªR•†VíL)ä­t|%;ç«4a›×.ú¸+ÍìÏlU6|œ}ÏÛk¼•Îe¬™=¾Js¶ùº3JUŠbß©j#úùÕ…µg¥ ‘Š·ÒR)ÖZà©tÅVrqbVÏÝ×ñ‰­S‹Éag¥Å–eŠ·ÒýIãÐ"U)äbôjÓ¶ÒÔá0w¥Q}c9ÖLpVš:eöðTêËébaܖǪ-÷·2LÐDí…e¬ÔØš‰ ~µ½_•†ìJ× Óƒx¥»~˜zµîí!ÛÎiÚ°.ˬÔÒhnÀJÍÛCÞ¢^ð¤A¥Ñ&«RÀ‘›+5?VmD—2±XKOh±J‹­À(s+œ3³¡QX©µs#œ³›½ù¡S Ò4XÉìM¿±Ñ㕦,Ìžfçâš¡aT©32—Ï3z:°ÜtW–§±±*UiÀ¦ïê_lM€j»s#V9˜3jœÃÜOã>ma.¿2Êù´]VÛFVŒ-ÄŸžkÃörsr€ë)˜ƒ´I­‰&áSŽm­ràñ¦íð©‘•Ùíºç@ëqRÏOÞ‰bÖÍó´ÕòÙÃK^®§`ÄúG†Ôщ…Ô÷_´‚¹‘Ñ&÷Óœ­˜7Ýmž§žÒx4ÜÖb#Æñ<·9ðΛ9ŸúÆ—ìz]d¹Ÿš:·GÛ 9“f®}Ì34W^N…©çŒ§ÃºùÄðB”çiܰ0ØØ‰s=…#–ÏšJ Ïì -÷_ÅÒ§Bz§žûéøôö©f)eäyºxjßÙ´:°ãx¾X3ïV}ÜO ÅIBvæxZ4,“«›kÄJ‡óÄ~Èñ×åEG¨ßäMs?­.ާ[ýU¾Û´·µ§Fú9ÿZ³0µ1¯SG¸ž6¡Ò”3:¥ÓÁ§–Î§ŽøÈÄT|±Žm¨+í7ÕEm’z®ë‡ë4 n3avðÚ0ý,a6Lƒ=)ïe©ÖHc¨Ï†\Ю6%§à=‡3jSicV­[Ö·á·I¨a]3WrÓ´·p¨¶ Z3EõQ5[Ç|Z  -.¶¡–4¬Öíqs˜lÀ€u'TÑ­?ÕôMZ™{_£ß¡ Mš1Ñê9´í6<àÔ"Õ1¨çìÒå1ªZ¸£¯ðWÚŸ^5óVŠô®Jq- j:%j—gTZX¨4£vóW -õš<ædôÕ—…Òÿ -Qif^é°ºH¯Ô53HÞ©è4­Ò¡¡T)®%!ùŸì«“5ÀPú¯sWê*ø+íOoÙ¨$«ÅHÿ<•z ô_á«´ÌU©JC °-ÀÕW\á2o¥P¦˜ã^ª””ÇØ}bͪÝäT=ú†OÄx{CÂ{ïO T¥”Ø?RKx¯Ñ.íjh»¶’v!:tÁ_›t4³ ø–€2ÜbdIÄg&¦Á™ðˆm„RÖ1IiÊÕt™¦éxšÚ·mh—xÊÓqÐÐ@-\×mÌ2­~¨ú¸u»šÔÀ²¹éMÑeKОå¤Ý?•†/9Ö'°í…Ã) í쌔Ä<…Ų̂—'‡‰Wf¢øC5Ù6êÖhÐ\ eië=HÃg–6€´qÏÌM‚AE¿ #‡DÕ¤ÅÕ$ëÎ@À„>°ñä0wB«6èù¶ø £iºVÍÑ¿ˆ=—gõ1zÑGy1ÉšAÖü9#ó³cbógÃÖ ¬i5,ƒ'Ö¿ Ax°¤Î²\ÍÈ,þÅ™ç\ì ñåÎ,Û¦öpQÂʢ։ʎ•U³—µY©#/8îVj%÷6ò`°*MÞqWiÄ‹µõLì­'µ’¨Ó+ {OÎ…Jâl¬¦ì©b3CáäÀLnÊ8Q™Z™h ¶íí&ø±L7›vŒ] -êÀ9Ö¶-‚J=oלƒÁ\^j×T'X×V„‡~ aâkˆ­Z.Íá¶ñNvDõJ?„zÅ½Ø ¦:“Mðw[ÉìÙ":”´0Ö9 CÆ:·U'-CLY>MáÌÊ!¼¶×Ù è–ø¸ôZ4@R‚ÿ!W²Q °„eY¸0Þ¢àì³pWqÔØ¸+÷çÅûÌ:j%—ÓäK©VœzN_,¹äi†Ø¡$aâfúö¬Ð1÷4Ý´­K¶äUÀaÔÀd˜¨âfdl<jX?W“pOj£ð&ÉÝðë„Ü©…6п!¹ú>oÿ"©1Þþ©42=Ù"ÕZiö B’g®1¸j‹Ím»Bý g -uB¶”fëäÓÉOØ6íýáõ©’©ùcǰ]`íá?“„;Ç®ž£Ø qöÚ-# L)€—›v±ÎSj•†ÉþäY£±u™Ó8…;¤’`áÌQL¯Ë ­±zŽÍïº^c¡JÃÍêxdY8:^y|ʲ4yŒÉêô:#Óôjq†w¨ã°*€M¸—ó ¬WÕrÉÌ:•Äïø -³J˸½fë}ON€¶{dVhÖ¸YûŒO¼¦")­5¬3qTNo$JY¡Ùì:²Ìr¤ó=¬>· -cžÊb¢Ä9á yÙ*%üM™ü™©wuÍnP[9}DÎøx‡rVâPbâ'áiÏÔÏ™;šcG›“µ£!›Ÿ3À†;Zs—}ZÝÃŽÖÜå?ôQÑ$íhÍ]Gï’R¨3ý½b޵£u‹ý9Y;¯í•ÓûŽ6§ÌÙ+*§Ä{tµU[s`ÄðUÄmÙbNXÐÆ«A3Ž;dÝÕ‹hŠ(ÀaË©K‚ãƒTŸ«Åy.EZæ‘<˜NÖ&Ë´ÀË:©€…IÜdUâÛl¡.Ëû Ì/›ÚÞ”FbÖ’Fi;Œh9æ.[CðJ¢œž] P)lIçä]´~äp‰ä* ? Aa2­~|¼Ù-õ&n¸Ð¥|ß¹Há>Ö;7?Ã¥qÉÜ&¢>òòÂ,,Lø”û«ƒ½s±Y&-~.¶Ð¥|ßYJ¡Þ;[`É÷ü¾pâåˆqCa^ÈØaÊýcŽ.¹!/„.á&Ä éµtø¾ÈuG"{¿Èâ…ôSQ–óå†Á» v­òª£´¡ÄQ)l±€Ê‚ˆD)ŒmÆž -“H ’.(Ê-fUÜk™#v  -ÄÙ« F´(çü§§Hã+5„L×bîtMê)m%K€KI³p°¥[¶'ó2¦JS€-uz®‰èû¶/}wà­=Žøâ®°n$ÕÛu8È?/²No`a-)‹XÚˆI±'ó 0Wr¥I¹ßŠÆ#b$,V^ç[äE@[VáFaM0 sƒ‹É‘q%0`NáõÑ£åtÓƒ^µiûÔ ŒŒË«Í>s‰A§Ò(C'A#†”ˆ¡ë¨”A‡½öC'A‡î‡Q †[T|t8é9†N8‚E *CÇU)AÇ-ØM pq§J¯1t<=Å#è¨ÞÞbè„#è0?ØÞcè:\.té=†Že¦ÆÑDDÐÑå1ñ:¦C2„Y%m‹ûÀóGE¥6IÐÒ;9ÔsÜUtâ¥hR_ΰ“Cü¡2-½`œ&åø’óŸñMj9=ÍäSg”M§§™Ab0˜Q‚E%q=M½ô’`Å#ç¤÷Ï"†ɃÎ:Ìl’H䣈L IŒ½ÕÒEМ´½¦`j°<‡»  ’æ -BÃ>Ÿ3Èjªç³9Ò£»`fuÑ5>Ñéu#ìÖ¥+ƒ¿ô`1¦ÏUç± §–$ì&ׄc·#p®+K EÁhšEQfaL, ³fŒL"Méä|‘÷¬rÿ¢°‹Ã-ZPXíMs™ -?³ÝYéq|B%ÎÒ¬³l¶¥—a&á1œ1 ‡ÆN3ÉF†@ÔÉծ?°ŸFXzâÀ–[Âℜ8>á« $ûÙmd¸$/VßX2Zñ‡¦…[‘Qž&q‹Ò¼xÐ(~xrê$ÍŸPÌ^FßÈ.9ŽO4&†³(Úˆ1 ¹AN»æk"‘)r -cr•GlEDk‘5büG!²;Yiö4bLï·ÑáèÔ -7Å"¹¤É²[YÑFÉ%?^Žs·à+€få+bÖŽ}ˆ »ƶJ²²×aÚPöxîˆpÄ ýC]A†a±µ–핚iž1ÁC府!$ÁneÙ'#ü:ˆ›8öŇƒÿˆQÂ`@FB”ƒ½ñI.YÞ+Oh¾£RåHG±Y±0åÈá¨X"bˆ/Ö‡6lÅæ³]UbHJ|r|»Dkº—Ç@“¤D´áا–N*\ùý`_t)­2ãÄ>Å!—©WJ^b‘q\MâŠG†ál²,2MrÊãbBv¢fÜ«@£D‚âšÄ¾»#bm²,2ÎA]D§“`‘kÌžëÙl1*l‘Áv‰jÃþh—™N}tMÛ{ט–w‡ô04Y¾hAÿaÂsÕ‘ÚU|žT‹ —Ä;0bžöÒ‚sT8:ùá9<Âr´ÝhŽb¬Ä¼i¤Ëõœ1‰‘9»°Ç€ˆ¢A³Âåz6êP]cyÎrpd)] ée9·qñ—zN’ë‚høåº -(W'Ù—‘ÿ¾‹œ=Qà¨:ÀãÄ#…ED°à:þKªè+Yš«¨y@Ë:G¿é„=²g—„ÇãáˆÛ˜qÜ»@÷ñp]ß?&+Ž)×»‡ª”x8)ª½ÇÃ!9¹#"Néx8þA•Œ‡ãô†"\ ‹‡ã»wTÙx8gÁ† T<{^è.}ÊÅÃñéb<Ç:Ð’ÒÅW¼XZxIö‰¤®‘-¥øDvxIt‡ý¹žÃë‘'ä|­wq+…Ç3XÎ /,‡¥Þø-KSe8á^7pƒ0uÀ0 ™iv­ÅEÌG‘†J…Âa\LŠG³“òBáî‚V0Ó_¤ ²—P¸.ôÊ.Bá¸î R>Žßª d(œ }L¢~ø§ÈVÀu²@àÓABòðœòXA± Õ`À™.•“p÷ 2,Œyy2L¥É¼dXòáG4zÂb•t„#ຣüè6ºŽ¸W Áͬ&IX,ë({À-@SXÖ8ÎåÌȈîÝ\Þô&—Òó3Qk+žO5VC%•&4›Üµ'âÖÑ…ä@ut&1Î̆jkFø–™ojéÅ•ô†CîObÌ™{iödü#]Üx„‹…NÁnó…IºùŠ$– |Án‹vöZÀNï?+ØÍfã©Ô30èÖùÒʼnDØÕü•f–æx+ÕŽT,[\±XX>>½@°Û¤ÛA«”wÖÔz‡¨T¯ìtq0Åå_„K/aן.[x+µ¥sÓ\•âùø4®ñä_°[I(ØmÐÃ_ifj`‰&[²£ 5;ce¾J§†w<7ÏU)agK¥æÒÌYÄ., ¾áÙìÚ†UÒ{΄áÓË÷¦m͈I(ѨµRë}.¸X‚(MKÒr0ԄϽ¨Ë-[‚ÃêÖ3ψ’b×þKí Õ¥Ü.-é—ÐUâ>WüJˆø“ò~1µW%2ÉM¢ç‘cä•k]âÌ$×®ãÒ³®¢!ᛪÙDîgúõ ¤2ãvž²ÂÉN"ÇÛ?¡¼o⾺Òú'šk@jjMBž©È'/5±ûò¹Ü]EÐ!K¯¢Ñt=Ùa$GÓqé,+œÑt\±t÷ÃtMÇeäÃK÷Ñt´Ý‰Œ¥ë5òQÚ1¶J£t4×°°c«{¦ëþ†9Ñtü>ŠJFÓqÓ°Ï^{¦#^¦ÇÒqŒôMÇegḮÇh:.[;a!Q.šNìž+e¢é¸béíBÑh:.f„ï– -FÓñúÃ(MÇ5ôŒ9ÊDÓqÍÚ“¦ã*JJNayÑtb1#ÊDÓɱn¢éxGLÑhºžFLr4¤«ž£é¸­¨Øj¥¢é¸ - ¼:•Цã:-áöï%šŽ+–ŽS{í)šŽ+|Œãd¤Çh:®X:NþÒS4×`tfËê5šŽ+–Žëä½·h:.å -íc|B)lTÏ -`D—lÀZ˜‰w‹Í-CB€”Õ,-©ëÀ'©»‘@¹|u¼Ò…¢ùêÄ¥ iã$šÙ–±Há(qƉH,¤-d (G=w4ЧIb[ë,I¨QR¹G“hÞ#$©Mb9Rˆî0ãT•Š^F$S#â8{Þe²7kn#[¯äLt'OÁçHsÇqÏ•4‘\Vš;‘fTø|Xjš;±H.itbü“ÁœKtEòOOt×sš;ÉÅžÒܱ,ŠÜ‰î:FGnš;Fì›D?`a«32g`õYþ=Wõœbq‘À”¤àWq%е€®çXžzN‚/†JB Hºñõ™Ãýù¤òý%=UÄ# ù8¤F¥Áé%ø•dØaúã\É"¶ð°GvÆMîs1:»¡øÎ{`¸šEÞLrzCÍ(ç 5£¤7ÔŒDo(ÇæÉ}IŽPâ‘úžBP)\×3g_b9²Y^§g*§R¥P{·`¤°¸g*L0°V,;;°^QÌ¬Ý - sié·ÂÂÂÁ+"tnP˜C’g8wñ婪J©ù^„(­éÙÔà7#KïÖ‡zNªè.™2_“/IðyDÀÂ”ŠØœ¯q2ÈÆ~sWR¢!ñÈÇ ¡Wq"Áº¥¸ÛÓjTŽäxNîÎ+Š»m ;O¢ÌD<,€ð2ts e/CG ƒöP42E" »ÍpÇŠ¯ìÈq×% YîzÌ[-1Ø4®L†;ä#ãNò‚¼¯X^¦*X»rÈŠnïêž+¬Ö,Þ;"@9 -ÖÂRìý º˜x9ü÷Âá®5˜œ,!ŒiAj|;¢±cÁÐÌÃÅ^ìZì¼oüË0Ä AL¥¥kqp1¡0&Ž¡\” ¶cg÷Å^œ±Ø¨\”d¦–ÄTjPº{z% ô” À“z%_“64Ï¿1K «l”ÄÀ6i‚aÂb¦C²–„E„—H \‚!åw!7Æ5¾¸Í{Ç ;ÂU%¦ì‚NЍENlh#&)X\ÂÕT (¶q²k¦ã.d¡ÃñÜ‚=¦{ÄïèV.ƵÀ{ÃGÔ³PŒ+…^›5]2sÕG„™UFÄ®A!z*Mz6â-$—Ò…ÙäRªe=³£‰¸e=‘ˆ[sÐs¦N0ÍsÄpë+Û\}o™çO¶ÌŸüÍ7˜¤/%F<œ1¸>Á„çÞ6h†Õ5úžÌ Øâýkö§7¬¼•ÚÒ³ñ)V¥ûD6z”»Ò5¡4wf?­RfhZ£06i¶ vhškq;äÉÃÖ¯ã Mk´×ìì <Ä+‰îOóTê ²ëuTê*, Eþí;6Xvì_mv–·Ò¡|u{ƒ¯Ò*«Rìv 2 oj‘¿ÒÔør†wxÉ Ù•¾ß1«šx¯Ñ7|$¾äzÛÇoºVò’Jté'±÷p6™÷pãÄN·÷ØV!;q”‹Û ¹M°¾0΃&‡jRýÇ„xór’}W§¸ËHÒ¡„&Ñ" %Ë†ã  Ûù“ʸV¡&q9VqØ`%X’&µjYSÇ›™e9)ϵJ Œ}ód÷Qiš*Yë©Æ<ô’Ü?¶Õ:)ÇeS¬I,]¬‡A—䥥’2NÞÈÄ‹€ŸV¢N=‡¹]Yj›UÁT‹ä’¶]­¦$_ŠÙ`•¹5±”bÑH«)Ny@×Vz·­¦¸·Ì9ëȺ›{­å[–9}GSJ\B c¥Æ‹‰j-°0~/-)ö1–ÓHÅQcg ,÷ç…û,u‡©8ÚJéÈÂæ`9Æà4—Ïí4AÞeWð2þË®X&;•”Soìf†AFüÖš<‚I}üÑmÌQF Ü-w}-eî9踬·+1áaMâ‰цª¼÷HÆéMêðSê.Ís¿çŒß— -ØmZ½ÎÈmhÞ¬Øb˜·°ø~O…Y…ÛÅ]+P˜hò_9#&šßGz»JŽ˜SÉsñÖ.Ì™#&7 -PªtˆçJë2 -@¥X  JJ¢aÇb1€¤Ô×U Ô@¶‡ª¼(@©1€Œ8qÙQ€Rcyü`ùf¨ËŒz´ë" -°sJ¸c¹c¬x‡£ËŒzlY^ Ô@oOG¯XÒ“œ¤|ò3²u“”#[Ö $åãµ*(š”O%iÓè5)Ê“MÊG$ždR>^+œ¢IùÄó#+‘”OVþÊ®“ò±¬ -°Qy× -Ÿì<')4¸3«Êb¦@^?á¬~r"¹»ªë¼~]£á¯[o[v^¿®ü”dçõ㋺cËÉ]†#*p7”ô¼~1M`Xá³"œÕ¾’{Éë'lR)”×Oj$WoyýÈ—9³ú1ùK÷yý„»Æ“¿Rv^?®†(‘„™×O¸Cë=¯ŸpV?â+%$ÂRIò9Ïë'Œ^26 ?ê.¯Ÿ0£#µ¤óú‘!WœÎãÝÜ@Å•×OXÕE÷Ž*×O8«Ÿ2ùøˆy—”×O¸*_oyýˆR„|®zÏë'8Ë‘*7¯ŸÀ -–)¯#·›¼~¯Ÿp@,‹#w×c(iYýøä1¹yýÄ-ŠJäõ“%Ãt×c&iYýÄ£k¥åõZ´LF=æõfôÓ7xTié`y—@“1¾ÐéñÁ2ì¢óÊ]+Ë´+x†)âxÏ [díc.Ó4Ó†5Ä€½nŸnòB3™… !P>º±›íA#ÂÔºe}[m¶jÇ,μx)ßl4͘ڰ՘²š5!ç˜;æö›Û#ÖZ»¬ÍV}~Cdyp©_=ÒÒ«céikaÕœYHjvfò*¶º]7{fò‡%ïîF~+º»6¾«Îøýã+ÙÃù{=·9³=µ³7—±ŽµçK½®TJõ§ -îSû“Æàfݸm543:m£áT÷ת5«Æ6¸Ô/å×ç~ã¼­ñpp?oÛÐ$H`Rm(fÆÔŽøÄž1¸îŠÚÒ¶HØ–ž]HÛ2µq[fb|»Ñ؉˜íí°¶©5W`ÇÕx¤eø0e ùƗᔨQØ›-5ï-©4æÖè€Í:QåÜðyAñ¥áf+¹”ŽåÓ¡XhJ‰åÔÆ§¹K[ݳŽ<³=7x؈xÆÕ ã9#«¯´ž¶×,ƒ†!Íâä /¸×LÎdFµk3#!—hÌc$ƒCÁ4­¤ÌÞüÐ)°,ŒéfzÈcêÆNÑ -8§k™h0ñ” ÃgM³Ç°­Bq··Æ©®Q܇˜1âÕ†jWj!~8µ¶ I£ßU±ÆSŽlü66Ýœ›e=kãF¿;Iû§7ÅÑ,ê©#^0¦°52á…3 :x¾¢3&MšvZ—7ꬆ;e«NÎAj}÷Ðo³.ì†Éf-š!„fø×€a†j»ÎÈ\¿ÖzÕ€©B6«Û¥Gÿ#­Œ*ì9€óô!ø!jÆþYlVMè›spxx-]Ò/çl›«Ñ­h0¯n€vçtÆÔüb6–[X(Ú6tºÞÌpÀÛ¯å›èÕ~hS -GMÔ#À¶òaâoÒÚƒb{5J<ÈÛ¨€WÔãøƒLuCO¯9}!__¥]&m¦€žÎ5Àoy+&¼Y368FìÞܰ{ÜFÑ^YÕ”‰îNaLÓ¾½R·›ÑÙë”™ÜrÁbÑÁü0Sì¥uOÂÿiCׯÛ׳èŸx±ëKËv¤¦Ø¬…´Ñ:6³ëOgMè©Cï l JQ-³¬›~ÐgsìÍhR&¿~5´ÍÒ—$Ø2± i˜Ú+¾óƒò¬¬òT=—h£•h·4‡sÁ†'<çy‹:„& %é—fÔøú-,;ÈÙX£–—CßÞØ%Æ{ÁDáÀ‘̆ $¸€­nGriÄŽ-ûäú„ÿ¶7çÀ¬pà{{yݑҗKø7Ç–áÆŠ(-Ea‰K£â(íÕým©=—½¦_Ü&Z³ä £Ò±Ü8E>r‘8¨}Y¢sZÈ?iAõ¡º†¶Í»k›A'¼( Ÿc›q»†Á·áѨµY ½&Ù.ONpn3¬,½Ø$‚”ð¸¬@: vËQ*#ñÒü!Ø4L¸tàŸ+MøÔJvw÷›vÛuh Cy7Á?½l‡)÷ϸPÉXnôC|öÁƒº¡ä²ä‡ù†ê¤wÛ¢7çËœ&°ÿ¬à ’ü€ì&í¶á%§§&Ênò· e9g¤ÿ–7Â[vrf ‹¦­59:\³±6!(íÅ÷úÒvóà¹Æõ¸‹&ÏžÉ÷[Ió²m>pÞÆPîe|s»Ú¤ÐÖ*·q©¥ Ðì0ãl«BÄ1ätjÖ÷ÍÎ!C|”0î£Âì†øFO¦IÄnJLÀˆ­›(Ûw”2âÚFwË1в°Í9ä4D°Q6ÄVb¨*¨LÑOîÝnÍ¡G:›@ÍåbHmËÁ7Í`ºëQ\xÇsÒºøÉ´ƒ#ûu?XHÓAV7ØšE¯Ý0™PUöŒ=ªã±õ<•üˆÞ:¶‰ü¸<ˆh¶Üý%ûú´!ªÒûìÆ]¯n)sxB…™Ž-ýs`ØÀÛ âL¼×n8‡†mQ®Ùàôçïn6|h;B0ãTÜ>½ÝÍÆºg?,Ü š¼É~#ŒºJR7¬lýV'CüÝ ìÉ`¦=h¦A7l)ÉÝÈl­ƒ‰hyã ªC†á,†Àjk"(C¨*(´ø¸-Ùô…» xerj?;äÀ¢„¥›™ÕÂûZ†$ * 'Ë,ëØl¿Ö¢‘0Xh¨0éBÖ`énE}R§¤×Z -5 Ÿ­¾%ÂÕ‹v9ëŒcÀ´Wã&M;¶’eLüä&T9À ¼µIú`iº­iƒ¬n N€5&¹­¶Y~7P'T‰Ý0ÊŸ j.0Ë•h7ö¬N †˜•\†,â÷) ÃÐV­ŒO¼ŒÝò‚óN î7.egÌé&€l2YÔ³Ù]_ê8­%þi©±<»0+UÔâÌûÚ˜5kÈ]KÓýÖŸˆõƒ?›nÁ—çW aèé˜vRŒ+dJ F0{:´ªd:ÁI ú­¿?ÉàV¨PÍ@_h@Iiö§Óª[µßm¥K}è×ÅÅÉYÄŽŽf$D®ÈòDòÔJ°ïà²(I“=³jÁL¤è7G|qÞ‚ýVl–œhöWšé”c l€îR‹Ò¢0u»Ë±5EÞ¢T„±~êê1hXé‡ -Ìk˜´d‡¶UCtÁP&nÛ -Ae~ì3yé"ËEÐPW†} ¼"‰˜—¶š²Â©]Íå!§‡˜ùÐЗàÞÜ8Ý"…’Ž£‹ës¤Ý+[´ôŸšC&/h)ƒêÌdlÍ;{26Éæ h¹réWèƒÐ^ž u¡š‘ÃrÃY!† `§ Abic•‹™åÛƒk…Á0H ‚1’8¬Ñ±¯K6› ª”¸NºqZl0Ã6ªÔéØÅ×£m—¸¬*ÚÒ^T׬)lñÂ25ºÊàô -Ï:À½ ÉûìÖ¸’J#X}"ºY‹ø Ï*p+Û`–Ð T˜ž",½vÃFÍ…JÓÕl˜ä­i€rU“E˜xŠ:”& kIãè†3:¥ÓáE”#Ì"ìÚÀJVÌ»ÉAá f£ÙŸÉ%ïY Ô{ð½Iê@æäèz_cúÞטUj|Ø{_cúÞטAV˜YkŒµDèE°»ÑÅP²×˜­ÇÙ°rÂ}$‹0uÙŠ‹YÙƒ)w6¬lÄSK -ñ)Ýèia#ÏjëµvÞn pì vÃÑkœR8rÖK±"a·“Q„C -Pi„Zá0õÚ3c·ìf$©+‚w·tXÅ»!ȇ´%ään î°3ÿÉä*'uŒbÛŠâ7èÆt\•BÝH5VC¥h.àIÇ×ÆÝ³×xrJà47¾ÃëQ-ºw:<]õñ™á”ú„y S%ò0S>"ö6&—R§]ØoLÛxÞ ýsLÔ¡ô¡vQ7¨Ù ‰å%Ú©ÓŃÆsˆqš#„©2'TÏTu0Œ·qÉ™EãŒûœ>ïx9"8–˜ŒŒ‡›plè'‰kµ ò„¤—ŒOÏ¡QÖ¶Ð†Ž˜1+~ÐYÑAšSÌ™nÜãÆˆI<&*ß“± -Šû¥QjjáíV¬“äÙ2~ÈÆìó)m6L:Éõ;JÙ¦ÝnªïG¨ªPÔ³!ãšß9ư1âдà¹ß0yOÇ2Ë &¢ÐDáG=€&Š a„Š)Ýcwè¶ÊVdƒMå­;ƈmtbÅ=äB¸Èm×jmLÎÀ¸ÝÝ4ž :_Ó±Î0]³4à ‰XÉôGVA¤§úƒjSi#«6®[²¸Uaq×Ë€!ü°Ê5caÔO ;'ÓÔMê¢6‰»0ƒS`˜A® Úù¯6´ë¿M&h>½lÀ‚³h‰úìuh¯ÙC'Ž„¡¬Ã[Hë(¶£¸ 4¾‘Äy%Z'¥Hl#}¹ÛG´A,¹XrfaÞ¸Å]3bÿYóA.æ™÷qA‰c†\ ºëÑ‚Ý ™0# vL ‚­’¸@LZÒrÅ*g§…óS6ر½°¸»ÖdVŸ§ÍÃøœÜ³ ªH»åâî<(±Õ„çí!0CI«1¢×´k jÌÐì ¦Fé›ËîÄ0œ_·s¨1›F6Jd¡…[a! #ã]ùCj­´,啲ze%Žšµ¸£ <)ÖËÁ þˆÏj¿!ƒ¿`ñŠð—!Ü -ªq´”ÀBÒú¦ü¾L:6•XNæFÔ3`PCYhí ‡*Ɉqf6Ñm,Ù‹³Y/øˆmd:{t°SÎv|xmQœ½sÝa‘Ÿ!öñÂÏÀà¿bG¿ÈgÐÏÅ‘ «G•b畨ZØá™:tm°0ÛMqY#ðöu¯ -:b˜hø ïnâוµtÆ™i$kÝ©lŒØF›-—m´UŽÂ¦á=mçÐøpƒpd~EÖ™º¨|&ªÒˆé¢D¸ž|& -Û¯õWމB ‰\]T>Åâøäé¢ò™(Ô^åê¢ò™(œ¹º¨|&Šß¡Jg£‘f07V÷%ƒ”Ì RV̯¬‹%aµâ±Xƒ‰»¸¸ë„¿9)_êŽâÌ%«¥q1ZØØÑù"¦OHvSB…!¤#¢(øk£°£1Ñ/Šù’pŽÅÅIY§èÈsXæ9º”StÓØb^mž‰L#Œ@.& %&ù(¡0Â8I”‰’PCªªDzªt ÄÚ½ª/qg¨Jpö;‚ëV•` /Zࣀ]qÀrÁd/"ÒRXö2ò0°hA^Ù 1+# -%«B׈32ç…«;¦ƒPq -›Ãhôa\øàœ‚”3fÐFå›Ã›Á4VDµáXÖ㌰ÌþðÌ‚ßbÁÜÑ»7ûã÷]HðÎÂVq…KO -¢B¥Û -°³×žLîÜ™ú #cÏnŒP†‘•Üi·Ûz€Š*ôøÊ“ƒ -qßEP‘êÆ¨ÒHpdìÙQ%Å‘±g7FxéÁ‘Æ‘ù{vcÄý”dHaݸ1’–+Ò‘ÝAÔ®§ÄÈ¥©`³¯¤®Â¥©àñû=é*ânŒ„§Š #cÏnŒpÄD{vcTZ3DÒ³áÝñä@Õ7–öµ+j$EÓïéåµ€‘´ÝžõR;¿< ®Y­°ý‹yã4$¼™° wkEk¶‰ÞwÑ•LØþ…ø¾0Ðø@“×þEIã¼°‚‡ÃDGXëH÷aAøgfc ]XN. v­Ö%Äœ±¿ˆAŒe#we b,sÿ­M=ÄXL†ô"PÖ &åTTKŽ]L6sHôæ–“`2è4Ayƒ‹É#¦°AŒe“*É4ˆ”<Æ4ˆ±ÌaìÛ´2ˆ±ÌahçWÞ Æ2‡Ñð¢%…º1§VÂz^£1ÝOéDD1\êë %»¾º·;P‹d”èƒZ¤µ@Ó˜ÿß§¾Ÿ(ŽZóéÚ’nš×–.)q/X%"‘t!nÛõz‰XDV8½Hȇ ª/%b=9Uϙҭª¶^³ÔˆEZ;~«ÔPÂÐG&Œ^±‹XûêKèü…ÿr!—‘%vñ -]’ðÂ'vY€v²›†ª~ð—…ãjo®“w ¦*ÞËW™Ð5%Ç­ÅðoóÎDe7!B:.·É1ï†Î„ÿëbÞáÅz]Ǽg¦Ð%Ѭ˜w‡IíX«û…­ÃŽÒ¾:,õ¬¼²8 õýrçÄ‹âAî,®ÁÖ÷ -rg€yY[´;j ëŒ6öäÎ¿ß øäùgâ8c‚—)*äÎ’àPÔ³òAî^j'äÎ -,À|®rg@;ÿ ¹‹r1E‚ÜYœ–ÞÞƒÜY /ôÐcÆÏºÑÍR¶‚ÜYj;~¿› wRGä=âòOÆ…:/„é:°€Œ¬W6ÈXÀöRS(ÈX÷±rg@o¨r—([*{S ½–“»)F¥áe£ -2Q–Û{»…‹‰BË•í.Ôê…‰ª4'äÎb¢Ømй³êC±<ʹ³˜(’`•rWÞBbœk3Q4/J¹w¸=¨4‚Žô]IÜñ;ð'o ª4ÝÆ ƒ¿6I üá”-»u|àu{À¼ä8>ÀËÙåþ¨HmsÅÌ>¢ -WMÝ/¹oˆJÐýðˆ!´fäät?•¦ƒmá‹ÁEí+`í8ŒX±†„=ˆ¯Êt©D»'k'ÛŸik+ŒOn·ÛoÁ=‡ƒþý4‘â–­j¹¤Ã¿ªp> ! F|ËDÿ èàŠÈšñæ]x›sa;±Ñ,ŠE[¶2²ˆv»Év@Zåsz°„¦B>0ÑÌÙ7Èúƒ­Ð&ÿÙh˜éÁ°™|?™8pœž},³jY'˜éêèº:Žn›Ç²¯Û°½=ëÉ;¡ðjvFæÔm›u2J%X,!v -~K#óº`ôÉ]¸,|(G*Ê‚ ^™°B$šÀ}=T­“svô7ØäX'—d*BıÔ*°@!?O%P\cˆK椵<<Ø:ÐÎ¥‡S®SÔ98uG+£Ì冋x¼´ñ !¡D®òTœ%rCä‰j«³É‘ßK ‹vbýÎÒ2ü9ô{¥"WaÙ…:ã‘Ê ––ÇAe¥w3áÜ·2gÅ~eцâ:À·e;žc²²êûG`®*e'ñmÃ… -À'vwÚŒÅ&˜‘»øa‘ÈP¹»l#¾­Úɉ¨Ðshîn8iVÕΖTqmì -u‹£©ÃýÆm Lˆv~î„€ -¦ä¼#KhT. –™3! ZœØØÊOXûÏa•×ãõ÷ùÜ^wŸuº½WmL4v¶vúLª Ê±Ûç6jéFµ:[ýB+Y[oïWZ}>kl&12âs'«ëµ*xNÑš—u)†8ùäÄãÉMf7;0*'7m…0Û>®wfC0ò4  ï«õãK~µi{g[­\ÖA7ŸŒZ·asa)>0©Œ3#£a YmÄÛ)ãX~) ,I  R‡É¥´;˺ –l/Çׯ3Þ\4bÿ\'i<ôÓbL赉ÍÌŠ:6±:ËÜL°ëÍ}µù`ª¢69Ò1µqI[Të×6}jÓüjJm*»-˜”@;¡’– ˜ÊÛ©Òœ\‚`fzÝ“Jl#Ó#£§ŒÁ4œÉàÅ*nÜ3/† ½D¹1/†—š‹%6’é17ý“Il$Ó“¦¢HL•Ç -7R4A0ýÚÊ“KŒk/¯bâïÉ$¦Ò£;¡ÁÔ6£Òœ\‚`J@)N(A0%à;̉$¦är‡9Á”<w˜“J̨v2¹\±}¬×̺b¹\HI+!—kÏ)i±Á'›’雉ÅaáôŽìk^å'é•’¶‡¬Óq ïl0‚ÿ»Í:]jh™GD<™Õ¶‘`µ‹¬ÓÝàËìÈÃ+é~Œ -dvTiX¹YE(“Ù‘žnåv<‘ÌŽðJAFnGãIdvÄPIËíx"™±$‹´ÜŽ'’ÙÌ 3·ã‰dv¤R±²)šÙOãJ›’“ÈìˆðBÏíH-l3;¢äd’³Íu›Ù‘0ßm~3²þÌŽR““õ–Ù °õ8b™ñT[‚IózÏì()]hÏ™U¡ýI©ÌŽ´5¦ëuñgv”¼ÆzO€GÏíx"™¥¬±Þ3;ÒÖ˜@òÏ^3; -§¤U*³£XF:„žVùAÂÞ‡Ð'‘­€ÿ -Nm÷±n°âV8ų¨ -*ö†”qemÙ -Е -{Cª4Ê{Câ¨<álÈ -×»•ÀlA_N,Ѐ-]tÅne¤¼;ä%’K_8«lGí“ 4 ˜-–íd (f‹œ›O(ЀlöAJZ,*W”Ùª4Ê$f¶/'•avg ;xFœÝv“¦–‘òüÄ‚È`€“ʰǸ*åÄ2ì!f‹{wœ\†=ÄlÑEŸ'™aÒÄO.ÃÎltÑ+»•uO¥é™ÝJ`¶ØõUR’×ö’ºìü'–0ˆb¶0…óI% ¢˜-æs2 ƒ¨ H'–0ˆb¶Øå˜'“0ˆbF•ÊÇs1[ü„·v+)`þD²Â+0o”¥Û²æe&´ýMÀüoæO6`^ºn«Ò(ä–‹Ù2Ó )hJnEŒ³e\*ÎnÁÊ*˜äë¶”Ž|’™âöOÖ”ŒêCüå$MÉhш¤)1[ò”çD3Ås]Ž©¨)1[Ü -× »ý?;ñ­¹{S2¼Kü7‰o“ø–éŸüošøV)S2b¶@†ìzÑžˆ)Geì6bÏ™»Nä ý(-J›’³å¸ˆMYS2b¶D:„3%#f‹ÙúNДŒ˜-Äþ‰š’ÿÿSÑÙa¯žz@ïA8d¤= ¥ '¨÷"àMsâÁˆ•^‹s0¸#MPáØ«ø†“ Qú«ôš3 í­æÌˆn#ä¿‚.õ€YjƒGÓ(J_ÿ›àÿßÿÿ&øÿß]ð,­»½”:Ø Ç÷«4ðËLµÕ®ÃÜ¥xukç _þbµ¡²÷ÙûläÿÜ}·»ÏëGÿ±÷¹áoùŠJ×\¯Tû*åõÝ­F­}°¡ï˨4%k¬ÑJvjåÆûð§Å±üÜH²/ЇýQ‰þGÁ>hŸ­þ ¼£‡× ”ì}Öx­¶ŸÌ¤úR_¨×­>Ô¸¾ÙZ_bfFü½ùæNe¯ÊxŒE ô.¦²õ-~|ÄTmð9¡²Ylàÿœ ×ü_°ÿ-–Á£³øEðQðåøéó}®¾±¾å¢­o?­rº0vøÜÇÿå¶9Ág^åñÚ;þ…½™gü]^µ©2€6Z¼n›6Æãõ{|NôÅæp8À¿Íîq *ò`¹ FøÍáÁJtÒ¾Á§yò½¼* F$ þíÿva-EßPK`;ÐÛôoØSêhãœjôÚf±»écþ³¡òôéô}‹ hºb`±•l :M‰(r|§*¾cÅbïпï€&ëbµƒ>—×eC¥Ã‰¥c³)y´s©à„ýÛÎÂɺÏå£:Ú@Ò;{Õm/™.7[`3ÑYëÏ•[UëçÊ ëfmo£ÚhZãF@[±C—'•œùBa'nû‚Ù=µÔãìˆÕ<»_7[§Ÿk§¾hiílêa§2*k²ú¹õêt&Þ·8®ZÆ'ÏÞG´¾ØçtØú.4Ûœ/À/ÿõõ9Ñ[ðmWZ`{DH–[å@ŸÃisÙœªÅ‘ÿçÃs™Ï¥?|ŠN©ŸJ~øTÐç:›øà\òýs©žÊ|ðT£Ÿ4‚øýÚ¹Ôµ³ñkç¢WÏEÀ'ü~6qílòÚ™4¤³©«g“WágêêiHïN¾÷dœ Ä{O¦Þ{2ûÞ#ï>™~çÉäÛ€žH¾õ8ƒÞ|,ñæc)H¦®<’$ ý’À¾_~8v顨…£Œ_x0A£øùb€ÞtøûCç! Óéû‚o|ùË…ˆBä£×¿À߸ð%ùÎÉ‹È}ÑÅ/y.~É}éËîË÷aä¹r¿Ò¾7!yyÞ|ÀýæCî·&Éõö#®ws¾÷¸ûêãž«y®=áyÿIïûOº¹Þ?íüàŒóó®ϺzÎ÷ÑÓÃ=üÙ3ÞŸý¾û瀾êô‹¯úþñkþÿõuÿÿú@ôéÿßèÿ§ÿéô  ?‚ôË?ö}ü HÿÉûOßpCúc O¾éùÕŸÿõÛ¡ùvøŸÿ4ø/ßýë_F 询¿þNäS@ß|ö½ÈïGnü róÑ›ßÝùAüÖâ7¿ñ×ðóæ7ÿ:yã'#ŸýÍØ§·ð//î^¿ôßn½ûøÝkÏܽöõ[ï<}ëòc·/ÝûüïÝyý·ï¼òÅ»/·Ž^:8~içø¥í£·Ž^¬½T¹ûbñî‹ËG/c´t÷å¥;ðsùè••ãWVï½J§Ò½× ¿¶vüúÚ¢ã7•ߨtï<$ú/蜰§÷Η­±é  cDGW!/´BPñE+Çç-wÒÑù¥£ 6/½±püÆ {fï½>{ï™{oLáôú¤ üž…ø}ÿ\Q†¿¼WÏ…àçÙØÕ³ ˆÙ3é«gÓ8r!„Á/‰«gÀ'€0Òï= éÝ'S¿ïã÷±Nü¦èø½ˆˆ…_’ÎCtG…ôêÄìƒá‹"Š‚Ï Þá ÷‡.ÞºðåàÅ/.~ÙáËøý8~/Òñ‹‚0FWî÷\yÙ#„ßÇÜ€høõ~pšß)üz~öû®Ÿà׃ðëý‡¯ù ~¿. ¿Þ~Áç/ÿÄ÷ë? ýúÏ£€~õg¡ýóȧûô;ñO¿ûì»E¯ãøÞüAì6¿±¿7~œ¼þ“Ñë;}ãùÒg¯µo¼ù¥[ï¾sí™ÛïýþÍ·ÎܼðÀ­ó¿wû5Þ—šG/í½´uôÒúÑ‹$­Ý}±tôâêñK¥ã—­¿²vôÊÚñ«î½ZfÓk޽^>‚$¿ì§43‰¿$]X9"` ƒ0Âo]X>ºÀ…_áá¿o`øFð;%¿©kŰRñ aKÇ//x”¼v6sõÌèÕÓ#eŠ“ï"zç4`Á©·ŸH½õDZ&~ã— „E(É"€Vœà?/AŠ¡ÒðG/¾ø@øÒ‘K÷‡/Þ7|ñ¾àÅûXæÅ/a–„~ôtà×ðûî£ÎüBpÚ…Àëúé9’ÿ~ö€_çÏ¿êúù× „ñµnðû1NnÀ|ÿù[O¿ùô/€þ ø/!x?û^ÐõïÅ}ö½èõïGxoü †ðgñß?Š_ÿQⳟänüýü­—·n^ø7Þzðæ{gn_}êÖ;çn^~ôÆÿýÖk¿}ûUÞöŽ^<·rôböÂv QåøÅòñKëÇ/oÜ{¥zïUD¯Ú`Ы½Vtü: ˆb‚±JÀïyHrñ{ÄÂïE~/Pø%X0'~Y„áwÐñù@„IüNwßkÜøÍÒð¥á7Ž œ¢ÂïÙØµsÉkç²×ÎŽ]=»úä(¤ÓÈ‘Ï$!ü¦a†(–ŽßGâÂ8H“|^€Ø#P¶!@Dè¾è(„0òý¡KÅ .ÌŸ/~Ùƒ|qbC˜Äïƒ~=¹oãñûΣŽNü~xÆ÷Áð `ëùè)@Þžòôtá×ý³¯ü:~þ5á_|Íó_óÊ’Ÿ?þ&EŸ|Óÿ«oýíèõ¿H~ö—©Oÿ2ùéw’Ÿ}7uý{$ů?‹…ßâ†ô£Øõ&>û뱛ϭÜ~ýàÎåß¹ñö#7Þ=sëÓ7ß|âæ…ûn¾ö_o¿ú…»/#Îû|õèùÊÑ ¹ËG/Á—ã׎_BÈ}i‚÷åê½W6ï½h Ñ&ƒ ® ¿¾èøõ B6æà°à½w~ yø=ºX<°eÒ1$ºM^ø¾³|tq‰A„Ïc´Hqá×gš–‰_À4Sºpæý§ÒÚ‰kçâמŠ!-€gЈ_ÄÊG~¯É_=“C4Bá÷Lê3øEN1©½ð“Ô~/? ÊÄ,øå@)DÉK'Ñk1:!VÃx.ñ#VZìÎŽ£$~/?¹ü@ø2…_a‚_ø’ä¼_ö\ú²ïüä¿¿o=ìyÐ#€Ü€ÞAò3 ¿œöýô¬ïÃ3~==íEàõAå÷«öŸÍþ‹¯»ýÃ×=ÿøu/†Ùÿ0ð1üà |ÉÿÉù‰è“oàô1 oBúäO€~ù'Á_ýiø×CøMöW©Ï¾“ºþÝÔgˆ®#Lð_&~„oþÒF¯ÿ0þÙO¦n>¿~ëõöË¿wû'n¿{öÎÛߺ|ßÍ7~÷Ö«_¼óRíî‹§î>¿y÷¹¤çW!½P:za ±]œî½\¹÷ -"ˆÐ*Q,˜à¿ò3Îj•ã¿¿4±™‡ÿR\ý(Æ)übRô<„ðë$ÍÊÇo‰¾lü~ñ›$ 8vƒ0Î…“¿g2Åà{™ÂFÞø=‹wá7ð›zdÁOf½ýD†@qšE„1bã÷áNü¦hð›$à'ù,í2á¡øÁèeœp_¾ø L–ÆÉñ>ßEˆ\ßåûü—ïó"ò0è~šþ‹ã×ûö#Þwñ¼ó( ÷»ºß{Üé¿×øÅ„g߇ܸõ#á°]Û/¾ðë@øuÿã@ü"ØâÀûñ xÿ£À?#ð ¢}òMˆÜ_~køŸ¿úÕŸÅ~ýç‰ë™úì¯~Ó׿  ø³ï&Aü~7Š Œðû}~1ÿáÈÏ3{ã…­[oüÖ+ÿãöÛOÞ~ûô+Ü<ÿ»·^û­Û/×o?·yûÙÊçVž_9‚à(.ß…Œ„0äÂk÷^^»÷ -"¨çVmðˆüŒáTªþ{ERð»LÒq'~Ibà—C¦ñßÅ{€^´@?~€>À!œô>„-Å‘ýj„.?“Ò5„0.HG¯Å Ñà—ôµ3@`Î CtÁäƒsùkgGáïˆ ÀO§ß…Dá—€0¤·=N§t‡Eš†_]êÀ/bÁ ºô0!T?œèx#éòC®B¾ò`ø -òƒáË„.a@~|/ݸtŸÐåûˆÀ/®<àC„ìÏ üzß}Ôûîcž÷‡tÑûûÞ'ñË–Ÿ~==ãÂ3P~¿fýÅ×qóàr^„_ ¿A@#úä›Á_~÷O#¿ú³ø¯ÿ<ùé_ ü~'sý»~1Çpü~/vãû~IB\8vãÇÉÏþvþúK»7ßøOw¯ÜwçÍ'n_~ôÖùÿïæk¿uó•úí¶oþÝÊ­¿[ºýìÒÑ +Ç/”Ž_¨Ü}~ -ÒÖŠðñ‹«Ç/#zeõøÕÒ½W×0;¦êvPùÞë@•Žßc­à=¾°Ê”Ÿ¡þ{ÄÔ1C4/‘ò3„ üBº÷›ðûÓ§q£À¦e0¶K/ÂïÓS†ø…R4”¥ŸŠ#¦œ¾v6‹(sí nÁq 7ôraȈß;›yï,Dñ;§3$„ßy2‹hÐÛ€žÈbPÜ©_~4ÅD«4z³kÅh’6 ï!DƒºRWJ^y(Ná—"€â„ðý+!~ð€e/F¿8xõ¾ñë½ú¤kOøÞÒÿþ“¾qã×ýÑ3¼.¨üRüï¿>„_aaüþë·¿P~Î\ÿN–¿7¾ÁË…ßØÍÇnþ$uýﯿrpëÂ9~ëÛ—¾yþ¾›¯þç/7n¾¸só¹Ê¿-Üú»Âg—ï>_„¬°ÝçʹJP†T|*1û4Rä>ü)ø‚ã7…<Ê ¨Bðþô+¹Ÿ>3úáÓ,#FRÆðûT©ÌàÑ(R{³ïŸÃ‘iø%dé³ ŸÎ2iäÝÓ£€0¿ƒPLpaȈ¯`Š0¤„p'‰@±i6§&•н ûH@ñÃÉ+G/?Y0Þü]Æ)€ÈåÁ¨Ùø}ï1ß{yx}WŸô]{‚÷ƒÓáø…òóY÷Gç‡>!AðÞ}¡x÷Åòžü¾ºrôjñè5@«Ç¯³‰8ù•ß{tý—™¹ñË/4X]"ð{iÐ=&u"#nü"ã´|ÒšÏSôÓ§2?}:  ÊIȈù"¾ Þ$Øî3£¿_Æ!eIu2\ÛØûOÅ%h¾#ªàC=føBgÊ€ç9‹Äo–I#$~!„OcŒÃoæM$H_y /Âoº“8-ŠîGIäÒŠzdÁ ü>»òpäòCaÈ…!….ü>¼ i€0@+ÀìC7 -b¾_yÐèÍ}o=ä…ðû(¯ÿ½Ç}¼Oðú¯AÎ `à÷¬ç§g¡åá׋ðëÂ3Ž_^7 -¿€á7À…_2^aú/Þ_~+Dð_>üðÆ;ñ‹›t ÑÍÂÃß›3zë¹âWšwÏÿν+ÿýökÿï—þÓš7ŸÛ¾õÜúíçVoäznâ÷9œŽž'€÷Þ»/.Ý} :oüÞ}Ãï*'~1ðáf+>ϰP1Ý6ÈG„ úBÒEHtü]X;‚j/À/a¼~/#ºT¼wyõÞå$„e61P¼|t‰‹..ãÔiƒDHË8ÃeÐ3$®Óˆ(ü’°%Á‹h”…_€ÜžÆ¨Ò)BüÎ^;Ù4Á3„,=òþ¹„0`ÐçF¯ž}ïìÄl'~Ï@zçÌèÛ§¡ ý&B#º!Œ¹e q!šn&x9 Á_{8…Ôä8†ßË¿$…/?!|ù¡á+…Þ|0tåÁ à¶obà}8øÖÃAÅ^ÿ[û½ýˆï]¿€ÿ¾…gœÿâò3 ¿¸üìþèi×GÏ8~ö; Ÿ0_ 6{yéøÅX0~!Aã3 áo"ÿi˜Â/ÒAûæÂñéw"ŸAÿ+Rÿßþ~âÎ÷qüÞüAòÆÓ7~œ¹ñ“±ÛÏ–^j¿þÛÇçÿë—ÿÃíÚ·Ÿ?¸õìÖíg×o?»vr^€ß•»-uøy^äÞyaéö …;ÂË@~¾‹‹Ð¥#ÂÕŠN8~).¼Fóªb1_ÂG ÿÀ– ‹!üÒ‰€0Äï¥ÒÑ¥"¢•ãË+8x/¯ð»†Ó¥5ð2!.¯°éÒ - ÅÂøMÈÂ/€*„-…\~¥Þ* `ûá3ð¥Am—À/À,&KöÃDk¿Wùñ ÀûÎi„ßÓ#oüFBø½‚¡O˜íÀ8íé•Dz€¨×º 67~x¯< À |bñûÈ0ø|Cñü¿owâ÷qéøu~ô „_LlöBúºï‘çÆÇüø!!übǾÞ_þ±ç“oxð’øÅìÏÃÈþ EèA&,ÄÓx“ŸþÂ/i¿‚öçøï'nB曹ýÃÌ­fnþ0sãGÙë?½þ“ÉÛÏVŽ^lÞ{å?Þ{í?Ü}±yû¹ýÛÏžºýì&Žßç‹w x—™´t÷…壄Wfï¼´|ù¥•£—W^°];‚V^z£|D#‚½®Dš ‰ÐS¿UH­3 üˆ¾ —$.‘ø]åÂo™Ào'A…Ðí 0ÎÎeû¢N‹äáw¤¼˜æT‰N”0Uú™ÔO'¥œ¦á7Gà7GÃo–À/Æ‚¹ñ‹Ç/Aÿ?{wÁWº.|ÿ ½Ïsöž™d’àîš!Š[Œ‘™={¶ÍLÜÝ#„!H$@phÅÝÚè¦ê½®û^kõjdlÛsªþÕµh˜9§Nß\÷rA’½Ö//À+Hr4ÈI¯~ä©“ Qÿoà›~F1!LÎX âaýl Kh^æý Þ‡æ¨øõ‹ëg°E¿ avP€_ÄK;0ø3æ/øýÃDîÈÅW°rþzºðL^À;SphðšÍ™òü~½Pºo©tñ»_;éÉ_Þù#Á«O-ןáÞ¨"Q¼UÜ%”Œß-ð‹3×^ùÆQQ㤨u–×:Ëê\7ëÜ6ß§Û.iZohÚbTÍg•ŠÀsY Kk¬nþÛŽi`Ú¶³ÛØiõÇ@u{°º#„\˜ºWZªl=ÆÒùm¨F+7”PÕo§/DÓªé ÖôíôjúXª' ðêú…¿ìã§%¼Ýÿ ¿êßÜï'¢F³í0Q¬õ;ü~™)¬CøÓ~…0‚ÂÄ,W’£0ÉI/A’³^ýòÔ¦óÉ.lÀ÷HÛÿ§0ç­¬ V¼,±xsì! ÖÒ&ýõ¿‚‡Ô¯©ƒql~%ñ¥ ÀöÐ`²É`2|$ý\¿_áeÏù_OÁä-mš¾³;}gvú¢# ¶¹ùß³Ñ& ðeäN)|G_.› „„„ ‘îojsêù%ƒ˜Í6zÔëÔ/=~eè×A':p1ítÎâËå]—Ñ,Wh$É·~¦~ÝØL¢'x~õÓ%4Æ[0#ÞHϯ(ÅU”êÆ%ÌK÷˜à¤ÿ5€¹–0õËLaðÛŸ`ÞOýZ áx3`K’Ä f’D i¢¬ŸE¸x>4d6”l:”âC$À{h„‰øM?8–AãùÍ݇~ñÊçý/úŽ`\?ký.›.”ZÀÃÎt·wÿr9â].gü’É{ˆõKð>ðæ_¼sÞö[eéø¼¯íÁïÖÙ'Y³¬ÖMV~aùÛÃòwGïŽÉßž–½ T¼T4œT4‡¯²éñ{r»™Ù&§zO©°ÓÛ­AꡚÀ{~§û¢šÖsQÝK‹V÷W÷Ó¯ŸvV'Aä{ÀxjA”FÀ)ßU±–ðªIº«èÀ½‡¯~¿·ßl~Ìn/ëW{€Ëèäeýº€ßÁt§A]¿ät0ƒ˜óë"a2æ7IÇ/È•¤ºJRݨbÆrª>^QªÁ¨5Š—$Nq%ÿA`Î^á$Itm#HÔB’aa¼¥0ÁB˜`.L0#™‹-ĉ’DKüJr‚©4Ñl0ÉTÏ/à¥~GÓLGÓLÆ ôCÐxÆ!¼ç(óàïêä®<1gýš¯W‚\sÚ¶¢~ Þ×[0|qþ’\ã"«q—ÕzÉ¡:E½§¢ÞWQL^w\Vï/œç÷„ªé„ºåÔvóI%=ÿû!p»%h»5x»-TÓ¾x;aò^Ü龬éÁÔ=—Ô½—Ô}ÐEu¾ _?tžULœÓοÒ0¿:gÐYœÅ‚Oùý,ÂÌt6 ü‰õ3×În~3Ø & ¯ßø üÚ³‹j=¿.ú~3]!ð;œŽ§Ó‡2]†³Ü ¡ Wò9–„]¤$Iš+ÉEŒ'’¸`Ø‘‡×k€W’êNбQ‰iî¢T÷ݲùq*þKÈwb/ !×p&qÙˆ’¬E²³%ZŠiI–’$+I²•J‚,¥IÐ@’ù ”¬C˜à5!xÍàs,2Ï ešÈ<4™uh*çÀTî~²xþ\±~Éúù ÿ—ç÷ë÷é ï—Åk¾úÔœõk¾þœà}¡¿²×¶²×²jÀë„;¿5Š;Üxã"ã&¯qSÔ¸*j]•µžªZeÝQEýQú=‘Uô)¼m¡%x»9PÙ jÜþ²Ýªn ×|ŒÔtœÅÉÛ½Ó}Ië·Óô]ÒôCÕýÑÆº t´^ÐIHÒþV¯vG°àS~µ„ ãüî±À 6Œ.­¹‹@ C¿”0ƒÔ~¿ì2ø3ý2¬>á7>¯Ã8m‰_×á,wwÉ7$—4W)ó4ÍäªëAqr…I°£ -Óñ¿nÚ(Ì4–çî¥ù31Á"²&'ÿ¹ €édÇrˆ8É’$YcÉÖÒd6ضH¶H¶H²ÄÌq -§0„‡SMFP.6¡_Óñ l"Ód2Ëd*Ûd*Çd -Ÿ–Cnø-8Àùe?š-4›#ÇŸuýb,ÞCË凨ÃVÔ¯)ßïÏï,ž_XnjýÚ˪aÙL;×8^eçjÅgØ€”5nªZïí:_ÕÛ£Jô KèÓäV€ª)Pݺݬl -R6‡¨>„m·F¨?žÑ´ŸÛé¼€“‡ï%ŠC¼Z¿šþh½(aâw÷„Ñó£¡ßóI¨7‚ù}a¾ßÝâë¥ë×XÚû˜ Ë»œR×/»oëh,­_½a]ïx„ -sálG2ݱ ·á <æ³~ÝÉ7ƒ0ˆ3\(ÞT7Æ/ÎA…q -=¸Ÿ®(¨zˆS=áS”â.Jqc"~Åiž¢½ò Æõþ ÄÙ¦ÿã’Øýn.r{#{Û”³åg„p’åP2„„‡RÌ(ááTSâ×| J§™g`™¦“Y¦SÙ¦ÄïòÌ«=ý"^}¿eõürG®ôü®3~-6ª,7‰_æ°ók;9rE†¯#ëׯߨF¹ Ø0…UµžÛu>ªwþÊ÷0|O+ðüË‚™ªjÁk)Ñoøvkâí¸°Ó x/aìð5ðK ëÇìõ{‘úUÃBZpŽñ½#½¨ç(Þ¬Ý ÿKüf:bžîÁHöc9öø‰Ñoô,³âÕþÖ ãûÍr!¹òrÉr§ gBn,P… w’Û ùfJw“Biî©$7.2iÀÖÈE}’4/ˆ(ö$?â'U)N÷â¥yíÙKœá­ûgB²¨&Ǩ‘° Ù‘ öÁµ—„‘›¤ÈýZŠƒŸñ…ù"ÙBäñ}ÖƒÉL±‚R±á4‹‘4ËÑ4˱t«±t h<ÚÈ0ŸÌ4ŸÎ2ŸÊ6›Ê1Ê=8™KX‡Ëæƒ4ô‹ÏÜ0™-2™Ã#Ï&¬ßƒìm (w©Üdù‘)öØDç°3ñ»úÔün¿•x‹ñûÂj‹ž?zmCü:ÈjåµòZ;y­-Vc'«!×_Õà®±¢ÎCYïÃWõþ¸²áàåù P6ÁðUùK†ïY‚7šÊeðö^a#~û¹.Opq—èØe毚úžãÇ›¿t/VÑ‘!W)ÐÂ4B(ÄXÁa±ôÖÏFüêdìä2w÷ΩÛæ¼-›ãn1~uN9òÎÿò¯Ž&XjÍr\Ú0DÌbnä“ÎÂ2 wô›~=$©†‘emªv¶ŠÁI’yó~ôÆÓ½EèÑm’Dä*þ$ó°8ã0ûgÈ\˜Š„…,aAŠ“ Ù ?Sœ„9ÊâD½Ršâ$ÅOGú¼>òàMÈv0Åf§X‘,‡R-‡Ò,‡Ó­FÒ­FIH8Ãj<Ór<Ób"Ób2Ëb*Û|*Çœø5ÁÓFä´/+—õ[d2[l2W ~ñ¶}h©ô½çˆ‡×Œø5åM^¯Å:ñ» =³Ø¨´›U–[Œ_ë­j›­7¶²r3úEÂ2ÒV­ýV­ÃV­ãV‹üía%¬œßW½?¥D¹$ô‹÷5žV4(@1ìü¶E¨ÛÏ2+gnÙ¬ÅK껼Ó…tÙhèZpI-¸h¬h5ÖM¨ï—í,sKEÚ0nìæ—6 £baÀ'âÆ1M߯3sK-lj´«Y¿9Ž:»½ôÖÂ]îneñÒ…1a›åÉo0Óƒk(Ëc(›ùf ÓñîêF-Vê”ÓÊ÷+¦e L.²Vt*¹Ò,IæîÏŒ³:¡_gì’³‡Ç¹Û%„ðûà>’=>V—Gx(Õj8ÍŠøµÅ(^ëñ,ë‰,ëÉ,«ÉlËÉl ô›kFüÔ÷[xIŇæK0Ä[‚÷ .“xx9¿üe³…Q¿[ÆýÚ¢Ù:9IVg·Ug»Yg¿YçˆOž¬w—¿óÅ;ôߟV¾§c—I~a-ÝxRÑtJѨl Q¿š® ;ÝykæÝüüª?Ó¯pO¿Øïë÷“ñkÕÿ)~Y¹8Ž_1/:Lé<ý<¿Ü7:~µ„Ó=EéÂ4waš?Q]¸âaê4R*9NžÂ$Á€°&9j §Ú¦Ú ¥Ú Ciøä“Ñ ¼ {,Óz,Óf< ›È¶™Ì¶™Ê±šÊ±œÊµœÎ³˜Î3›Ê3Ê7=_Æo™¼/ú-þ„ßU¼[Ðì7õk¿Uï°Uï´Uï*{ç­x﻽ª÷ª† ¾_fþÞ&XE«ZBÕ£4çþ×ïˆ_ްÇî~Ýé♬Ÿi@˜ßgùeWÅ^}¿<Â|ѰÁó{„÷+Íž¢ P Ÿ°­-þwpÇÒ!7JX¢žËHÅ“Ú̶§„‡Rm‡Òl‡¡tÛ‘ z ¶íy" -‹×v2Çv -ʵ‚¦óá|óé|S¼àªŽ]X3›‘`ðÒ_“¥RFî}ÈÝóeýrxø}f±§_²~F¼ŽlÈêeõN²zÙ[¾G”ïÁÊYõ>HÕ¬ëö|ñàæ@ž9 -Ó´ŸÑtž×tEïô\úo÷ûY„ÿíýê†53'—FüºéúõÔ6¶~6\ë!Ý#ü3²Áú=¢;ˆáßàµkéD1øÍpÂì k&iªË@Æ<»úMÈ_»!Æ/}ø =~m'¯4•k7•g;•g=g5“o9S`1S`>S`:Sh:[lÍçJ,æJàÓš/1¥xY¿¦+$¿æ†~×*,6*,>Ï/àu‚ˆ\'ù[Àë&‡áûΗ¾ïCT !ÊF-aUFÎü©Z`ç7\Óq†\'ùßäw7ÅAŸ£Xß//ÞpØóÿ5~µ é‘l¯álÏ!Y3ëø%y ¤{ø%„Ó11Âñ’fxK3K2ŒÌV£~¥YGø+dBõï·>Ñ?Øð§ü’pøà³7ðñ}˜=àÆ'|Ú‘‡–àÙ=z -o<ÛšÈ&xsì§rí§óí ™|›™|«™Kâ× /Ø(2Ÿ+¼–„0*¦~)áE2Y¼ ל¤ï—!\~AîTi¹ùÜj³Êj¿0v¯3$ƒê]ä€÷­—üíù[?廓oØvc¨ª)DÕÌ+H÷9h»/ÛØù_¿Ÿ"ÌeÄoö~ôÒž?âíýMü3~ÝX¹®¬_Ýýz¢>õý=<¥ë×ÇÀ¯Ïž~}Xà»øÍð$yH2=$Ú•Ó@ºÉu0Ý…„žÑçûÑg’ÐWÕçäcÄ/Ín2ñ¿ö3è—%œOG°ùl‘Å\±Õ|‰5!ŒŠçKÌJL—Jtæ/â}d¾òØ{b¾¦‹—ó»ÁøµÜÓ¯ñ x]äu®²:Y½«¼Þ]þÖ[öÖGŽGžO«Þ‡n7„o7†ñÛÄøÕ´Eìà5WÔÝY¿W°Þ+;½1п_Žpë—Þ­_µÖõ«M×/‡Î¨_jÖ™9½Ë»„ãwñ‹g~¥é®RÜøçù%ãU»Ï»‹_ˆ®¢$Íôbó„0.Ü;ÈÀ„¡ 7z§^²‚´à%.ød¡Læ)CôÿÂxiM¶úͱŸÌu˜Ê³‡Ðoý,„­É*Úr¦Ðr¶Èj®Øz¾Ôf¾ÄŠú]€JÍKM—¡2Àk-?2_}dAý®=ÁðW¿Ì/žÿ%wÖ¹ÊëÜd˜»¼ÞCVXVï+ëÏúàünk#«èæ`2#Y¿<¼è7æßÏo¤_£žþكؘ_×ï'¦°ß@zíw5àËvË!ióãØºq¿®üø¯ðëþ3üfxa~ÒôOûeö‚ÙôUíâ—f€7Û—‰þ6Û°#Øa^ތܜÃX¶÷0“׿IòÉvEÅx¡óœ"æIxQÍxŽÃD®ãTžãT¾ãtã âeýÚÎÚÌXÍZ#ÞÎï<ƒ[.5ãùµäùµ^}b½Âæ¼²\¯°Ü$x üâ%”2|H{Û>ç “ûë}ˆßãįÎú™õDü«šC·[Â5™ƒÏÔ¯Zß/K¸o/¼¿ƒ_Ž0?–° BgwøÓówwÂ"(Ðhº„©ß`¼üLá$Eã9îKØÕÀ¬^†pG˜-[7-í½ýÒïa1‡ !ºç+E¿.@˜· ¬ï—!œÎÞÍïîé¯ùHù„µryIsüôÈö`ãÆ vbðæ†²iÞ#ZÂ8…G³ÝGØÿ«òöhp§f<×q"×i*›.pš)pš-tâ£ßBëÙ"ðkƒ~™ý_‹ùRŒ%Œ~¡¥rœ¿Ë,©_Œú}jµúԒË~ŸYn’ƒWxñ$¹~’^BIüÚà3¯ˆ_E­‹‚à%ó׃ç÷è.~ƒ¶ƒ8¿ÛB·[#4íg‰ß‹°~ÞÅï5XKÿÓü’Î+Jmd-ýù~C4"(Ø  6=¿z£™ër›žËhŽß/¿1åN‚élô·œn#ã˜÷¾ogÎ/LøÿU¿ônßLø­öÌ/+—Ûn»FÂ`– ñ~¶ß#z`iƒÙGuýúqßc9Ø›_øKŸA(Çw0LJ6”s„k"x‡a xsX¿9c9ìTÙ…PŽóx.䟓yΓùÎSCx¦Ðq¦ÈâÅŠ¬g‹mfK¬I–³%s¥æó¥æ HØ ÷‚ËÌËÑ/ö /?¶Z~L'/ÅkÄïf¥ùÆs ¬ -2ß|i±…µ&÷/8Èß¿un -X6£\È[×/ìÿ†lãñg¾ß@íüÅÛŽ"ñʫΠŸò{MÓ³ÓOûúÕ#¼›ßpƒ£X{ø ÞÕ/¦ÿÇįëãHzèE„òÚõ·üq¬sLûçúÅ«Ùþ³üJ²™p6ùcÄë;˜ËùÕ†~™)ì=œãä0~Gsamè×…vžÐõKrœ.¿öÓ…6Óè×f†ï·ý"á2‹ ðZ°x-—\k‚—™¿ÆýVš¿æÌýûf/ÌÉ“Ÿ­ñþ_=¿0‚ëôý*ÞV¾æŸ?2æ7j»ý¼º“]û,¿²j'y³›ãŠá!,Ï-$ÌóÛDð†âó'›‚•ª†S~£Õ—Ô]1 WÝuUÝ x¯“nìôÞøõñóýêEÿ,”óë -Žèa“OøEžè7Û›k Ê"„Ù)üŸà÷ˆ‘ãÉxµN1_úÜ7C9~C9þƒ¹Ç ÜãÊ;Æ„_Bþ\ƒ¹Gs}‡øå`ÃHØg8÷ÈHîa’÷àÍž°Š&¡ßñ³Ž¹ßÈý úçµ·ýîz·Â/öëÿ«üæ1~‡™À¯Ïo#Þ<¯1Ìs<Ïs"ò˜(p'Á†Çd¡ÇT¡ÛT!v†Š\gŠ\§ PñL‘Ël± â"ûÙû9Bx¾Ìz¡Ì†d½PjµXl­—ù‘ãÏˬ_îü/«Ø¾ñÜ|“<ùŠø¥„ÍɃ°¬Ñï+ô»Yí´Yí¼õÆeó+ϯ¿âÝ åû@eCˆ²!TшéùÅmÖïö­ßpÞø3ÒÜä¥xIB¢X¢ëøÍâ§úýòf®Ë•Ë>yr¾üˆ<óê¿Î¯ßpÞQm¹GG0¿‘\_’Ïhî‘ѼÃ$oâ×k<Ïk¢ò$r='IS…;ÉmºÈš -]¡Ù"×¹b×ÙbçÙb§¹ǹR‡ùR»ù2»…2ÛÅ2Û%Ìf©Üfù‘Íòc[üÄ ² lmè—ÄÔ¯Å&>¹Ý’GØ‚¼BÅfo¿Šwô¶ý À«lÓ÷Û{Áú~Õÿ­~µSø3Ò{øEÂÿ¿Ãøœ:ò¨ºtgÞÛùMsѾð÷÷õË\j5u”Ûæû¥¬8¹<¿ÇóŽéØ ¯¡<ˆ°=¦-÷˜áQ†ð‘±¼Ã$ïñ|ï‰oJx²Àk²›‚Š<§™¼fŠ!™B·ÙB·¹"·¹bÈe®Äy®Äi¾Ôq¾Ìq¡ÌZ,³[‚Êm¡åG¶ËíH¶+L¨˜ì[ñŽB^kâ×b£üZ‘w†Z±„-?íï<:®z€·ý6„)Âa<¿$ üÿŒßðOùå+æùG°…3IÂÉ®(ó(*c~=~s¿ø´É ìsüðüJSY¿äùuz÷ߟ뗻NòèÍ`þ¿:x‡r9¿'°|½Žëúņõ;Ÿ# -çùŒæùŒá|è0øG¿Þ“àõ&_ïiZ±÷ æ5Sè>[è>Wì>W¹Î• áùRç…2§…2ÇEÌžøÅ–Q¼ö+ÐÈà ^ybCŽbY¯Ò¯ =…´Qi¹É¼ùˆ#üI¿ÞÄï ‚†o8‰ó rI@;DÕ¡j9«þxQÝñûû^ÐíŸëW!m”³ÁagŽ-ƒ7bGAîyqeýºé\ªa䌒¡_ïgÖÎp!~]Ð/‰¾í—ï—®«É³)0ê—¦cע_ýço=‹ÄÉ%ù`GÉE@ø(¿AvÁ¬ÛqcxYÂlCyFÎ;1’×!œç;šï;„óY‡' -OæFˆ÷0|N¦M™.>Œ„ =gŠ<æŠ=æJ 7$\ê:_ê²P†„9Âå$ôk¿‹_ž_â×bUZ±¯ä[‘·˜íêWVwï|ÏáðP¾DÂô~ðK A¿MÛè7ZÓqYÓ©õ«fýjz¡ë¿¿ôú_Ã+:>‡3ï¿ö!ÌÌ·\n¼Ë&é\¦N½tC¹£™.¿ ^ôË{Ñ#s+\—ãpº3àu¤ïìF¼iäÍ T4<[f •}ssÏ»«4ÕMÊáÕ>KŸ¿¡Â ^<ÍœN¢w ‘ûƒÈM‚YG%™þø%År|ð2H<믂å—wÜ€íÉÁnœ  å1Ùáü“ü´„óŽæÍóÍ÷Âù>XÏxÏ”ŸG& -L²MÑ€0ú¦~K<çK=aÏáR·ù2×…2 ì²X9/–9-•;-=r€–“ž8P¿Ë˜í -ô”†Áïj…-*Æ÷ÿÚ’÷ÿÚ’¬wñ‹„™Cеžòú#ìÎo²}¥lˆR5†«éù_‚·1„œQ -S5G‚_ÍÇ šŽKšÎƯáë̵=WÕä’öA²{úfFóÌrqT Û ¯úÓx‰_Q¤n:éÁÄByþ–†kéá gˆ{?Þ…ÍîÚó¿úx©_w&føñ;”A^ÛM §;r ¥9 ¥; ‘ ð;”FüÒGÊàSeœx~¤ÚALŸâÎ寸å?ÈŽ7…iôŒ°”Y63„%Y¾’LÎï1ô›}”à¥~ýuÓñ‹G® ýœ4RþI†°ÞS#Cx4ß4ÿ(›Ná¦qŒ@.dš„Š|¦°#Ä/(ö„Uô\©÷|©Œ`â×}¾Ìms],w%„QñÒ#ç¥ÇNË/öÔ~ù©× -TÙ® \;’íÚ3Ûç€×ž%ÌMa¿[ÕŽ[oœ¶jÐ/¾ü¨Þ‡ø P¾U¾‡á{FÙpFÕ`ñ¬FâU6…ïê·‹õÛ}Á‹Ñ»¯ð侇ßhžßŸ‰WµW{]6ÉK߯nz{µ?'|ÚCº#ñë¼§_wrý•¡_t­õ›Éùuaßí‹oûF¼vCø@B8]ú%„¿Žº~RÙ0yø*}~£‹DûÚWIŠÎ¢š<8Ž>H‡yB;ÏïaÖïažßcúÍ>Æ÷K®¤:¦eËeÌïÑ`¿\è·àôHÁ)ž_ÿÑÿ±¹Ào ãü’X¿E¾“$ <]ä3S|d•xÏ•ž+óž-õ˜-u'~Ý0·År÷År7¢Øuñ‘ËÒc—å'ãòSê—Wå ~íÙìÖ*íÖŸÛøµÞxÉúå^aVã,C¿nį¯Ïü*Ðo¤¾_ü„/ö!j»õõ»ƒ‡°~+¿Ñ:¬Œ¯–w¿IFîÑž·-pËã=ý2„‘ß4{°£÷@ƒðÐá „½F³·yú"|㈖ÉS‘‘-ós{òÌs­_q’³˜÷>Pª˜}½‘;†dŸeGâ/¡ñx[ý^~ÉÍôzÈc\zxõý"ÕSC…§iÃXó#|OK6†QîiÆoÁÉQìÄhÁñ±‚cc…Ç€ðX¡ÿXtt¼Ëo¢ˆ­Øo;:Uì7]ì7Sì #x¶ð¡„çÊ<¡ù2Ï…rÈcñé±ûâc7hé‰ÛòS×å§.ËO—Ÿ:.W8膄‰\’ýj¥Ãús‡õ*ûõvë/l×Q®- ðnâËC)^|y(y„އ¼þ°ò->3öóüF(?œQµžÓßÿý_¿{6øY~éûÅÂŒÜ ‘ w–­1¿äQNCé ÞÁt[ˆúæÅøe}Ìæâð²~µ~u^æËfÓw ò'KŸH©ë7ósü•p~sIéu’ÌÕ’˜Ž_/e‹Œ2Û”0k~äù=5Ê+<1Vt?Aqä?Ž#áöD±¶Ébÿ) \rtºÄo¦äÈl©Ï\™ï\™£¸Ükþ‘׿¹ø˜„=–žx,=u_†*Ü–+\—Ÿ¹,W8ór$¹Ï± -ð»Vå¸þÂqý¥ÃúK{’ÝÆKûÍWö›0vY¼rúŽ:wE½·â­òÝQÕû“äô=xE÷øU4E¿çÕ/þ“üŠÎcÿ~3œ>á—90容Xý\ð߆oâÆG)²ry~íŒùµãe?Àż[„ñ+aübb|÷®“ȸbW潟i\¼'ÊjýzÁ§8óˆ˜õ+É¢„ý¤ø_ð+&~%9Ç$ož~8‚óO ¿:x‹Þâ@ °Š¸Ñ™ŸoÌK/6ŠïbcKSì%ø.?G.£~IøÚP7ö2³˜î ÓÓÁ^ôÕ ‚4Oaº¯_QÂþdìâc¬ÄÙ¾àWœí#Ø`Ú‚Y>dž_/C¸(p¤„%L#³x¤(`* +Íó÷óKžnÔ¯®egî¼-sõ;LNã’mg6GöÀü›íHøB !ëãe§0 膯çK¦oè³£~9Â"mNÌ;“É+‡Hį«Î;¸éNç{±ùÀüS¼˜¿$‹õ›å+ÊbFðgø=iÔ/³„æ£ëw´ðô(ç·ˆó{Z'À[0^ -Ÿ§' ²€I,pª<`º<`æÑé™G'g˜}tš{t|þñ1há ä¿ðÄoá©ïâS¿Eø|rxñéᥠ-š÷r% {êF8ÓžÁtv_­òX{á¹ñÊ›éµm³ÚÚ‚Þ–A5>òZ?HQwTñö˜òýqr…d^ùÜH eÙr„ѯŠìüþ>~/þ¾~ſگø×øµ£~Éá&çOD„Å.ÜÝÖÃ;Œ‹gæU>$k’ }³ÏPª5/›!|i¾·k³‘jã½$7Å_¡›„Ñ—êÒ·Þ“É´˜ˆbòî0†°Mw -#^\Hóö!bÙWœu„~‘ðž~OHs±ÁüSC°0Ö®“‡‘-Io›¨G1:‚É.:5Æ‚( ÐVˆ•1ÛÉò ©GAÓ‚§Í<šÅ柞{|jþÉ©è)¶XX¬8¾XqléÙ±¥ -ÿ¥Š£‹¾KÐ3èÈrå‘å燡mGȧ7É‹¶ZåµöÂ{ýÕ‘ÍjŸÍj_’ÝÞzã»E>e´?Y¿¼ö¸¼þ¸âí åûÓxm3¾ð(˜‹7yC˜íæp9øŒ¯ÚÁoÌoí÷¢ZxQCcüò»À¼*T?>á³jc1~?Qägô+ü¦ÚÓ£Ð{FO×:¤;R³iŽdƒmþÁdòî;ÔÊ{&~2Š­Ùo,™ïIäôVRmÖR÷ÔÛH’lĉ­8É^œÄ÷ë ã—_®¹’ø³˜œWb®¨Ôžÿ…U´(ã¨(ÓW”y˜çwùKñž„ˆ_Ø·ÕÆ‚ $¨a;ˆÿ#ë7p¬˜C%ÐDi×dYÐdyðDyDä£ÜÇ!Ðì“9èi0)pþiàBEàô [®„–+O“N.WžX~v|é™ÿò³£Ë•ßÊs¬ÊgµÊ—íèê Èwõ…é´öâÈúKß×~[oüy“½9!«9Ÿ°½Uã/ÃŽÉjOÊëNËëO+Þ(™·•Úo ø%¯Ú¯ün~/±ýÂFý~á†_þ9Y#eÀ´E¹l`Öa8Õ^'æ”Ý0³HÖó«¥ÊÃk9Àþj ÙR—°Ž_ ñ+I´…ĉ†~)aAÌ,¤µ„y~SéZÚ‹9¼ÁÐdy4QÁÞè ø {Jª™«ž¯^x´TÉ´üiu§eu²ú@y}ümü]‚Þð‹+d¼ç—\ö¬]?o7…l7CaÛ"¶[¢Ômç5è7FÓqõ·ó{‰QŒl/“a˜Âbèo_0V‹÷ˆ#¼çûŠ?ïú ‰‘´~ÓŒ±Ms ß¤;Ò£ÊÌáåt¿C©vÃPÍ–øµáùµÜ£d 7ˆß$†°³–P¹É6â$kq¢5™¿8‚E‰ö¢$mB†0*ø iŽ0/Œ`úb_Øÿ¦û¿¤ _Q†øeùù{”“GÜç<¾xIÕ@ÞÉ\¦Á¼Sƒù§ù„ UÆ/â-Ƹ/GpÐ(T4V —0M”†h+ ™*Ç/ú !xCiàwVë7dþYȳÅÊ`h ñ†ÂÁ+σV8ÂÏO­”-DF{"GzªÀ[ðØ2Öˆ)#Èõ“aªFô«†Ðo8úmýÍý²„™±{Y#¢]¹;$$Œ£wé‚F|^íEøÓ~%F‹$Eð"*u.žä%1Ò`Šèc×½Ú`’Ž _°ÉLg$ÌKç}åeª-ïâµf«?>^)û¥4ÙRšd…Ü$.kš(ÑJ”@³%؈m„‰v¼ìi‚DvèíaÜ ¿/ã×[”qX„3|y1~éÎ/%,¡ç™£U'PnÞ)®A¦Óƒ° \ÈŸÂì,&~Éüå¦3ü8ZŒ‡Œ—ÐBÇKC'°°‰2(š,zD !~An|âÆ £âŠÐ¹gHW†,>]z¶Ä® -Z® -\ª -X® -XÁN¯T\}qríå©uÚ«ÓÐÚ«Sk¯ù\EÎ'׫OoÔnÖ‘‚¡­ºPY}˜üm$«—½ ßz‹Ÿ²wáò÷aò÷á -¼UðFÉ›ÎÈ›Ï*šÎ*1U#9ܶÝHü nßþ©Æ‹¯.î|ŒÙ鸺ó[øÕÂìä½¼#º²#†.ï°~Ù.„¿;F“FîH#˜$ô3lGj4ÔHƒÉ¶C@8…œ“ªd¤ëaö›a: µéüñP -ƒbØjñòåšï–”„~“,¤‰ð Š-%ÚÈ¢DË=ýj!³„»ÃÌB§°‡0ÕSˆŠ½„éÞÂô#h–È%xaýìCŽbùqóOs„yËf)_"—ó—‹ÁÌàŸù‹¢G‹CÆJB¹ÆKÂÆK±‰ÒðɲpJx²Š˜‚CáÐ4ô$‚>ó4«Ÿ­Ÿ«Œ˜‡žCá Ï#ª"àsñyøRUÄÊËHhùeÄòËð•—a+/CW±µW!k¯±õêPh zºª-dõMðê› µš õºàúÐú0ݰ›ouÚz){¥hŒR´m>‹ŸM8y1¾gTXä¶Öo°šÝfýÆü>~¯@¬_:‚¹¨_ãÁ*šõk4í^ðîÑHÎh¤P”A¸~þõ~¹)¬ý1ÙŽÿmºZN±L¶f2ØÏå­–Í¥I&zI’Lµ%bâSI‚›¹˜–h.L0Æ› ãÍIÂxKa¼•€–Y âmùõ'Ðì0TÌÌbØèÂÉ„p2¤¸ RÜ©‚TOAÚaŒàtÆ/Å8…Éþ/Kا03ˆKsN°xuýò¿ùAÃ0sCàsˆxG‹ì(¯±ÒH¦²3´‰ò³ãÎ@±©ÇQÓOh‘ØÓ¨é§t#rªˆœ}9÷¿òúÜò+Ø>³ú*jõuäi½:b­:rýMÔzMÔZÍ™µZR©6jµ6|µ6l­>|ýmøÆÛˆw‘ð¹^Ïö~Œâ·ù´žW6_ ÁÆ9¢8J‰c7’LÞ]¿ÁÛøæ#¾ß«ÔïŽÞýƒ¿À¯£x5¢˜&v -Óö$Œ~%¶wí¼Z²ç.ø­ä¬Fz–ø5$Ììÿþkü2{¸ú~u̦ҤC$ÞÄC¼¯8>ù~ÍDñ˜0ÞTð2<4'YZò²êǬùõÅÛ¨b{ˆ]Nóü&»ô'»ö§¸õ§x`©^ýº„S¿!Äoñ “7ŒÎÙ1¦È‘ÒÈѲ3£åØXù¹±GLãÐãsO°É§ç¦±³“Ø™é§g&IÓ´Š33Ϣ枟¯:»Pu†È"g^œ]z x/®×\Y«¹´R ŠáÇskÐè,S͹µÚóëuÖë/n¼»´ñþÒÚ»‹ëo£×ëϯ՟]w~ã=t>×ßžƒoH°qnýíy~ï.l5\T4_V4_!Ÿ—ÍÑ@XÕ|†à ߯Âè[tý†«[οW9¿Ô¬ïÏö£²!Û«l1ÚA¬Å—ŒuQ#€p´Z½m» ‘œß³sé¹]ÿZ¿ɶ4ê”Û „u8s¥ÁKVËÌšYŠ™³+d0{HÂD§­7sµ¡VS6fð -2ÂLýÍIh¹³ê×…L s~1Ž0®¢ ýzR¿4fw˜ç—Û fg#aIÎ IÎIIÎ)iÀŒø"óñâ6_n‘ŒxKÀoñ{v´üÜhùù±GÆ3?‰žx=Q=ñ,z’éSeôiúyôÌóèÙª ó/Î/¼¤¶ /Îa/Ï/½Š^y}yõÍ••7——«/®TG¯¾‰^£Õ\X«ÅVk£×êìåõ÷1ë W×®‘OèÊzã嵆Kk —×1øñêF㵦ë›Í7¶š¿Ùúð'ÔBûNÞò¢õ;ÕÇï•mß)ZnÈš¯Ê›.á8n¢ËfÊöçùÕü&~uÿB¿»ô/õ›dCcüÂ60ÒNÒþÈ‹·xN¶&çmµkfÄ›dÆ\/µ²N³ñÌšŠšwI€™ö?0!Á† ÷3„-ûZéoÕÏ[KÂ$'A’3ã7üºž0‚:„ÙYä°a1øÍæü¹§i@˜ r„aG!2~'ÊÐïõËàE¹£¢GG=¹HziâYÌDeÌdåe¦çØTteúEÌÌ‹˜Ù—1s¯®Ì½º<÷êâÜ«èùWæ_']X|½ðêâÂëËKÕ1Ëob–0T¼ZôV{y­[©»¼Zeíݵµ†ë߬71m4ßXo¾¾Öxmjºßl~øÓVË÷[-‘µþMÖúwyÛ?m?(>bÊ?*ÛTuü´ÝyKÕ?þQ7_S ás°~Öúm4ê÷ì/õ{ù³ü -ÿ ýJ“lhZ¿Lœ_­n¿IÖx®VÏoÝç¥Ëf`{tHÂL[3˜¶dàš‰šr ˜túI}qI_œi_œY_,!üÀ¼ïÉR?$Œ é¾x»>œÂX¢c?ßo2ã·/ÕG0v6èdø -3ý »úåÇFÅïpQ(ÙùgwxqøâÊùŽÝ'Ñ£O.=¹ lIWïÔóëSU×'«®MV]|3õâ4ýòúÌ«3¯¾™{ýÍ|õ·óÕ7櫯ͽÅ—æ,íÒbõ•…×W«íµ¥šëÐríµ¥Úk˵WWH«uWW믮ÐÞ]_}ÿÍZãŸÖ›¾[ofûð§õß®7C°ñÝÆ‡?o¶üe«õo[­ÿØjýIÖvSÞv[þº£€Úï(;îª:ïow?PwǪºà›È[¿S|€)M^El3Kh¿Ìñ«‹?ß/Gø¿Þo˜aÒDO®–°Þt& iúL²¢!ÞD‹$ó”k.9¶˜J€á~.f&æä>0Å!k€ÍÆdzp"xuýÆ^.‹Þ–üðC«Þ‡6½0úí‹wèKp„ „û“\û“Я€ÎßoA*úí'‘)Ìù¥KhHœ…x¡ß¢Ð<à6J6“_X9“}Þó¸`~Mg.Ê­ˆ™|vðN¿øfæå7ÓØ 6ïìkðû-ñ ]Ÿ«¾Š„__^xseñM SõÕEÄ{c©öÆrí7Ëulõ߬Ô³ZcõíèÝ7«ï¿]møÓZÓ÷ëÍYÿðW¬6þ lÉç÷-ÁZÿºÙú÷ÍÖ6[Új»µõñ¶¬ý.$o­wå÷•]5ýi;ÂT0IݧìøAÞú­ FpãyUã™mæà³áñçHu˹_ê—‰}œö‹ü’ î –ÓH.a5MJû—ø5‚—øµ¦ókÃóKJ²J²J"x­-iˆ7Ñ’’Ø=ÜC:xã¡C$SÀ+~rMhtÎòÙw ?ö F÷1ê‹5!™‚_®Þ8Èœd¡lÕûÀ¦ï¡â}„‰ aA²‡ýz -R½úii°–¦~ý„Äo¦?ë÷˜„âÍ&‡°rN’˜]`¼Œ_†0žB¿EÔ/%1Zɳ¿Ñ_À{ýV^›~~cý~ a0 r©_ÀKÂXõÙêë³Õ×f«¯.Ô\_¬½±XûÍb ©öÛ¥º?cõß/“–ÞbËïþ¼ÂÕðýJÃ_Wÿ¶ÚüÕ?¬}øq­úa­åïk-%ŸÿXkýZ‡Ú~\o½¹Ñv{£íîfû½­ŽûU,ëˆSt'kD¹;’Üi–F”¢ê¾#x«éм1ZÙpVÕÀ…&—`q~÷?D_5ú¥ÇŸ¯©»®sǯtŸ_§ç7†‹°C¼{!$ìaA’«€Œ`2…=úÈB"~}é~0ã¨0Ã_”y "~ëøÍ†NA9Ði,—-/`€;UHÎ"áÞÅ/¶¢~/Mpó·òútÕéªo` -ÓA<óòÆÌËk³¯®Ï’Å3n¼ü{ýíL56ûæOóuß/Ôÿu±þo¤¿CKoÀÞý°ôþG¬áh¹ñǕƟ°¦›«ÍЭÕ·W?ÜYm¹³Úz—·W[oÁçZëµ¶»kmwÖ>Þ^ÿxgýãýõö¸õöq[]·:ã6A1XîŒWôf¨%¥šÁ’üqºªçž¼í{YãEãEeÃ9>?‡¹þJÕ@^Ü¢¿Íg¶[ÎS¿jê·ó:f¢Š{®‘¿êÞ+j=¿Ì¡1žß+ÑÞù_=¿—uýÂ71L’«@XÃŒ`6éER4é‰ Ý-}¼‘úñk,)¹ÀÒà—Ä[Ф8F­ôâVÈ$ô;”h3„Ÿ–ƒ fƒ &´(“Æ›IÀ¯¹ɇ :(~xPôà Á{P—í×XìׂØý‚¸ýýL_÷Åò;Øwüè½°;Äˤû¾I×=šY÷=óîû4‹îûVݱÖ=q¶@¸÷}ï‡Þ¨,÷'8 ]I̾p_²{_2!œr¸?ö‚}ø„EÇ 1Þ`x’dA'$Y'!iÖÉðËÅ*–rG¤Éúy°ñK. Ç3Gº~Ç_‚áI†ð5TüœTu}æÅÕrØjîÕµ¹Wøãôókðýô«o¦«¿›©ýë\ý?ÞßZl¼»Ôt©1?›î/7Çbâ–[âVZâVÛ¬}|¸Ñž°Ñž¸Ñžmv$ëÔ™¼Î¶Ñ™Äm¯w%nt%lv'lö¦nôf¬÷¤¯u%oö&mvÅo´Çn¶ßßêJ’ òTƒ•š¡ÇšBµ MÕuOÑögEãe%Î_Î/žKÂg>7‘›‚ÕÍg·[.¨[/Ó‹7À¯¦óÁ{ƒDÏ_e^ -܃m÷^Þî½BºªÆ'BcaÎ/_+Ì^ŽÅ^­_¦‘ f¯ñºJ§0&….“.’¢w.@šóDè}ï§ý’_ùÇ¥‘RKH¿†Y Òˆ_;˜`3˜`5ˆc×D[<Í üJ⯙XÏïCËâ…ˆ(ظýÚb1IÇï}mïÞ{zîì¹wˆ_÷½ƒ]ÐÝC]wM»îÂ÷Ì»0‹îX’mOœ}oœCOœCw(v „ÉB ÷%»ö&¹÷&{ø=*L÷G¿äSx±Ò,è$—.aî¤ãw€ø, -"x‡¨_2é™#ôûü^¤„'ž\AÂOc&+®N=»6 „q93S3û›{yuîåµ™ç1ð=ãzõí,à}ûã|ÃíÅæØÅ–‡K- +-‰K-‰Ë­lmI+“VÚ“V;RÖ»R7º36º37º³6{ lÚVO´Ù«m«7W[_ÖV¦L%ÈDÅ[ÂÂMAö¦ m½'Æñf{ìFwŠLX¤y©®ÐH‹Àïv×=eëwJ¾çU¸~æû %w†(#ðqK´ºí²š¹Îß<¿,^–°Q¿šOø½¬ãWLF*ã—.˜Áì &)ÄŽÙ‘ư„/ñýîü\¿:7,øÝµHc—oEIãÍÙ,¤ LhY/Ü϶փñÕx7ãeB7àß#yˆÇ¦HŒYŒšecÍîĶ¿?vÏïþ¾ûL½Ð=¬‡øíF³Úºîè„îì¼cÒy×ñÞ5ƒ:ïšwÅZwÝ·éºgÓkßëÐkßuß®'Ç1³;œ„G´z“\z’\{’´ó·ý%ùaaš?g‡X¿üÂŒèl$<ÀÅ*(DÂCÅ¡4fþ–EãÏ£åçG˵„Ñ/‰%ŒMW^™y~eöÅåÙWH1Óϯ kX`¿þó\ý ˆ÷>à%Z“—[S—ÛRW ¤öÔÕŽ4h­+}½'“ðÌÝìÍÛìËßì+ØÂ -eP‘¬¿X&(&Ÿ%rA ý” ¡b…¸X)-U >QV*žÊ%E›¢ÌµžÄ•ޏõޏÞ4p­}¥aüª:ï*[ÿÃW¥¾˜Ì6†á[€›Âðî¤æóª–KÛmW¿tý܉x·»®oøÝî‰Ñõ«3‚q9ý~ÕÔ¯„øÅ!{•ç÷›é7HXÂ'¬ëWúOó¹›_1rÓO¢Em®ÙZ<ĤÌy™Ñ(^v÷ö€‘2¹±_Aèþ—¼àÇ}ý÷÷õÝÿ²/ö«¾Ø}Äì¾Þ{ÚzîB_CÝ÷t#aÒ]»Àö@û¯Ûol¿}¨ãŽ)‘kÚyývÞ·ê¼bûîûˆ·ëžmŽc»Þ‡ö½ñ½ ޽‰N=‰Î݉àF°w -øõíOóëO; - ØaÄÇ(a~Ü8f¾ÉÒ^ÚAG0Gxì“1R5Rvf„½xc´Ú>Þ‚âÇ2Ñ™øÉ–ø©|à™r¨j{äõöhµjä…r¸œú]ìx°Òõp½?]&)Q¿°ÿÛŸ¢ìøIùá†OeVÎMP~âcsÂT"TÎ*?\Tµ\¿ Þ_î—%¬ã×/õËíÿR¿°ZÆ5ó·¼þÝýr'qÈÐdâ3;³t(?4ŘJ±Cü$Jâ0X'ãN.ÙÏ­tg–Û«%íã]­Ü{ìþ€z¡û_¼_öÜÕ©ûÎWÝèw_×ý¬\Ä‹“wÿÇ[û©ßöÛ&í·uÜFÅè÷ŽEÇËŽ;Vw¬;ïÚ0ŠïCv°–ï~àÐóЩ'Þ¥;Á­'Ñ«7ùHŠ/‚M;Ú›v´/Õ¯/•O Òø¹P1{¤ ‹ #x¨ü†Ã.**EÂ#eçøWQŽ?ŽÆK(Ÿ\bv‡+.N>‹žª¼„I@VÑ7æèü­ÿaîíOó”pã½ÅƸ¥ÆKM—š.~ˆÇrkÂN^éÂé«™«Y¤ìծܵîüµž¢õÞâõ¾Òõþ² Á£M*¿¢§[âŠ-i¥|ؾR ¿RUʤÅk‚ôåî„ÅŽ‡+Ý ë‚L™üV©G«¥yÛýIŠö”®+¹áÁømF¿Û¶[𵃜_uû¯÷{M×ï.„y~Éá)ê÷›ÿ,¿Â8š>aTÌ­¨ÙýYpúàékÒ~šŠ#=øZüðkÑCæÀö¾^_iñÞû#W/tú‚ÖƒQ³üÀïW]·÷C·¿æÂá{kßÇ[ûÚo@¿·µýt>òmÓö;íw,±Û–,aÛN$ ËiØvèŽsìyèÜïÚïÑ“èÝ›ìÓŸTA.ƒ—ï·ŸõË®¨qQÍÄÊX& -Ÿ–æ–äÐ<@N—„ —†•F ÂÃet-ÍÑz|~ü „WA3ƒøéʼnР“ÏÎaTŒ?_™¿¯Áï_çaÿ÷ø½¹ðþÖÂû; ïï-5Ä.5Æ-7Á,~ãq[âÒǤåvð kéôµÎÌ5ŠWë·`­·h­¯„%\NÂZ¿²Á*ÅÐ Å@•Lòx]Kð>Xì|¸Ú›¼.ÌÚ’+F*UC¥*I¶²7^þñïŠWy·í‡ã‘«¦HeãWÕ¢3Á/Kø:ö ¿—wñ{MÝwUÝ£Þc Íø%xÑæÕÿl¿ü˜ðüÒ#QˆW¬•ËáÝ'†â0Qì>QÜ~QÜ>!‰Œ2F˜ŽÝ?b8sÿ§÷Þ°»è¹óGì.×ú~oCà÷«Î[û;øáðÝ×v“ú=øñÖÁ¶ŸhýÞ6k¿m}¼­:îa[ìì ;tßwìŽsê~àÒýÀ­;Þ«'ápo’oÊQÖ/!œâ˥¼ýbºküy~q á.* * *AÂ0ˆ azEåYæ.$ Ì âËäv†ó“ç§žÑÀïå™×g_ýi¶ú{ÁóuÿXxû#(^Åïn/¾»»Ôp¹1v¹)nùÃØ/^j'ó7þð!ÌNa$Œuç¯ö)\²Ñ_º!@Å[XEãúyKúL6P «h¹øé¦ xµ'}©óÁb{ìrWüzê†(gKZ¬®P)DŠî8YÛ_ÍW”Ìð¥OÎ!oKi"û¿Baý¬äü¶Å¨Ú¯’°ŠÖyúÝîºÌÔ©z.©z.“b(aT¬ç·ÿVÜÈO9«EÜaç«ìâù?Ío즸Cüx㘎f\ƒ_qÜ×^8sc÷‰c÷^áý¯´¦béœ%„ñ¨ÔW¼¾ KåÿÁîþOïÝÿKë¹ó{nÿ»ó‡nìÝw¾àãíºýe×-øýªãæ>ZûÍýí·ö¼‰~?ÞúñÞ<Øöãà÷úýxÛ»eÑvÓâãmÄÖÔï]»®»ö]÷»b»ã\»xtÇîIô¿}ÉGûR°žT¿Þ_˜ÈLZÈz+j?öè³æüâ:›¹ÆR’„%¸ŠÄaÜ DÅá´áÒˆ‘²H–ð™1FñùñGÈîð…‰'ç'ŸžC¨øΪºJ®ßønîÍ_ækÿ¶„aƒâúŸëo-½»³ÔpoOÇ.5Ç-·0ŠaGxåc2ÑjO[mO_íÈXíÈ\í Šaw8ìnôAE›}Å[ý%2a9îKžÈ¤Oä’Ç[‚’õÞœåø¯Á½¥öØÕî„ Aú¦(W&-R =VJ -”‚Tyç=YëŸM—™×¦Ç^Á'žðÅw…ªšC”Âù½ú ýöòý^#iýªµxq.«EW4böœï¯ò{ÎXÿ ¿‚{_3Ý?(ˆ=À%Œ=ÄfÒ!Qž´ÇÒ°}-º ïïÜãOþŠŒ"x¿ì¿Ç…xé´eÌrÝÆºoÿ«ëö»nÁšÅ:Ù[.À»¿øm»ùuÛͰxF¿7}¼iÒvËŒé¦yëO VÑÖwl;1;¨ëžC×}ç®X÷î^Ýñ>=‰~½I~}IGpo -äדìÛ“ìÃ…œÙô³kiz¦˜óËçq„¸a Ï(…ÑYŒ„™›‚£8Âã”0|âÁg0ã÷Ù%rF –Кóý|Í_ja -ƒâ¿/Öÿ°X÷ãâÛ[Kï‘ðRã=¼–£/á,Ž_iMXmKZiK^kKYý˜¶ú1}µ=cµ=s­#k­j­÷änôæmàjrjIP$•ÈÅ¥˜°x³7g­#e©-n¥õÎjûýõžÄMaæø•)Êâ\E_²¬ãެå;Eã%åû(UC„ª!LE_ÄЦÀBðüQó?ѯ€Ã{ÅhÄWY¿†xõü^5î¯ÞãÊ«ß×oÿ½}4B˜ßA2ˆµ~aF‹@+‹Û¤û^ø/À>ôK‘2‡¤è¶oßÝ/úî’ãTtì¢ÙÿËæðþ¡ëÖ»néøåóüîo¿ùõGdËúý‰ú…%4ì›@­7!³ÖŸ ó¶›–í·¬;nÛB@¸ üÞuè¼çÜëÞçÝïÛ“x´ðjýíIöãûÕ³Ì-ª÷ö ‰rNŠrµ„ÉBZKx¨8d¨„Ù#ÂäÔpùy@>;ñ˜ñ;~/¢ßª«s¯¾™¯þóBÍ÷ µY¨EÅ‹@¸î‡E˜Âoo-¾»³Øpg©ñ.(^lº·ˆŠ,ÁN1(&—y¬¶Åmikíékík™k]™ë]ÙÝ9=9›=¹[}yòþ…É„²þìÍNøG`Y~{µõöFGìFoÒ–0S&ΓI -e’b™0KÞ“(k¿½õá;9õûþóý⧺㪊x1ž_$Ãâý|¿‹÷:´#ºÎð¼ßì |‹Iÿdà—%ŒÇ¸týÒK(?÷ÊçßÁïÝ}LÜ fƱîD†mâTt_;pù îíÜÝ'¸ûUÿÝ/ûï~Ñöm¿Ð‰~yñöÝA¼½`öÖÿ×s‹ç÷Ö n6ô{ó‹®›_B?}ÁëËŽŸöAí?ñüþ´¯õÇ}m?}x:Øúãê·• ñ¶þKhË7­?޲ŷmÈ¿.]±ž]w'øõ$ú÷&ùøÕŽàî$ºßøúåv„ñ’iŽ0¦õ«·#<€Šƒ† -a8X«¸„%Lîî+;;VvnŒü´Ñvk³#v“ñ›+ço‰ ·ú3dÝñ²ÿŸ»»þŠ#Ýÿÿß|?÷ÌİÁ]ww‰áиÇÝ=!‚;4înq%Š{ÍZß½÷SUÝ23çÜ;WÎZïU«Ã$3óË+û©ª§ªÛÏ7Ç,6„à7ÖùÑ÷¡ß%Ö:¿­²~ÃV:ÖY‚_!˜Å=áÀVèÏü®I2Ax£VGd·Zm8Et/X ,ë—>ø?ë·ÿ˜kàøv ¼®ÁµU†R:ÎE×ý=@~Ê•#­ò|rø ðn#¼è·'ã÷ÞŒMœâÃ[Ño†\OÆ6Vw†\wº< Ù¦± Î4¥Î´íé\íéÛÛÒÀ¯"ç7mWkêζ4ð« x[ÒTZÒT[ÒÔZÒÔ[Ó5ÚÒ5¡ö ÍÎÚ@¸ó¨^× ¾g¬{ÏÙ÷^pè»à~û.b„×¶û‚ ðBðó{‘»´E׫¥÷•¯Úʾî4Lƒxø–ËS6‚ÙY°P¦û <#vqßãåO¶;‹b„ßdQ0‹?äŽáѼýŸüTü—ÐaŸK#¾”G}­€…tìW¦¸2 WÑZº6}\œ1VÆmZHVÔ''šNO6Ÿ™BÂç@1¬¨§Ú/Nw\žéº2Ó}u¶û4×s}¾ïÆB?6?Ÿ¯ÌwžškM›mNšmNo;¼Ðyr¡ïÂÂе…á[ Ãwæ‡ïÎ÷_]è>³ÐžÁû ¤ïÿõù^ç½Tç…Õ{ÑÛÝ™ßÀï-˜ßí?û û±Žpwø?çw]ƒ«CQèw˜ß­Á¶ZýÒ¯ì*:ta|áÎoßQEV¿0ˆeƒ©*ë÷øv>%Ù`åŒrB ¯<¯u [ÙúpÚnêIû K'Å›{3˜_ ñ¦±äeRèNS켩J©Û¡ö4ËRjM…¶·¦î¼­©@xW ¦Üœº›Âê-i@˜à †µ´f'¬Ÿañ|Úª÷œ]ïyÇž Ž}¬¢meñvÉ$p&Âx]KJX¸"Ív]r„ÑïF„Y®Ïïâ‹£)÷—øŽJ/ÚÝ!õ+¼×îmvÁ£¹4…s‰pþ¡…Áø"Ž2˜ÂÑ_ðq`R\ÁÍⱪ¤ñš”ñÚ´qqúx]:fË鉆ã“''›NN5Ÿžj`Ÿ™j;7Ó~a¦ãâL×åÙnl¾ûÊ\ÏÕùÞ«s½Wæ`òvŸk;<Û7Û;×’~;O-ö]\º:?|ƒ^迲Ð}z¾=u¾I´XëçÀ%±ÿRï’à·Îk±Þ“F°à7˜üF0Â+<^¿|¿ö+ÜH’ñ+»"¹:½:L€P~©ü3Þ ü†ñO1p„ÿ§ý*ðáõ psYˆµtª+f®BÿyJ®ÿèÚŽlë?¼¥o}›{Ó7u§ýFýÞ“¾©'}sOúÖžômPwú¶®4HŽâ'o*¤!ÞÞoêö60›l•Z0ÞoÊ.ðþä £â4õ¶4õötŽ#°xî=k;pɹï‚sÏç¾‹Ž½`KývýçÖÒ¬û.XÉ–vEJxèºÃà ÇÁNC2„ÙZú9úuañ¯÷|uÏûõ}ßWü^?¤%ô£ö¾|qGvÀ‡öRÊ è#bXHü\„Cñ¹†Òˆ¯e‘ôR(æ[EìXUüXuâxMÒxm -=HŠ3&êO6™l86Õx|ªéødÓ ¬ù@žn=3ÓŽO'Íu^žHšïº8×}~®ëôLÇÑéæ„i|»N4ø]h?ºÔuf©ïâüÀ•ùÁk ƒ7†n.õ]Zì:µÐ–ºÐ$Zªù.úÎùõ‘¿kýÂü _nÂßH*je0zuH„ ‹Èo %sæ+l¡”öK¿8‚ŸØ(FøïõÛ{TÕ·AL±7šq…¬8È¥0 ÛQy)ÞŸê;¼­/c Ùª7¨nêNýKƒ`oîNÛJmëJÝÚ™º­3’“I¿)Šäw~[SÀìvÄ›BIý*ÿÂ/ÖšŠµ¥i´£_‹¾sWÜz/ºö\pé¹èÔsÑ¡÷‚tñÜuÞZÚîCÏyÄÛ{Þ -B¿a Õ—mû¯ØðSüa'ž0 ßüºrßãp—üfz¾Êô~uÏ¿yà÷æ¡ß[{ñ]¾ú)Ƶt~ràS. -ùŠKþ–†ceßÊ£Æ*Dc•±ãÕñµ@8yBœ2!N§MÖ§O5dL5&¡£“¹ùøTËÉé¶S³í§gÛÏÌuœë8Ãwr¶ýètkÊdƒhª>b¶1j¾%_žÓM~û/ÏÃØ¸º8xý{ß…¥®øv,Áo]À’ØwIÌüz"^ôë7‚×ø"¿áßhH2xcV‡©‘Þ/õ¯øÅìüOX:‚ÿ¿G¤]“°´æW׊ìôv7+ÄS•—vX¾ï°WÆ6ŒÿŒ‹d²àt ùÝÄ…¿Ü -Þ­)Û:’×%ב"Oq~ÛÿÔoÊ/ý¶€_œÂZmGŒºNZõœwî¿âÑ{ɽç¢[ÏEXEÓ¶üvž·êüRü¥$økIVúµ,ü[9(ŽÂ5 µ‰ xRÌJžªKjH£Ò§3& òÏ´Ÿm:FžiM™nŠ›¬‹˜®›mŒœoMXl?²Ôuú{ßùÅþ‹ÐRÿ¥ïW–{Ï}ï:¶Ø–´ÔÍü.‰Ñï¢Ø{VÎuž‹HØ ¿×¬ißhÁÿå~iòÞ‘d0fu(vu8vu$võ©l1ÜZú¿À/OøÙþ¿Ù¯¼´£ë ËZ¦Y¬À]³kVÈŒ­â•ïËïå’£øÏér=iÐ6¤šr·ðm¥¶uáØ•²mOÞÚ­÷Ûž²jKù¿Í)»š°ÝÍ)*@˜O­9U½9ÒÚmG÷t²±Ûwųç’W÷Eݜº/8t_´ë¾hÛuÌÖBýžÃzÎYr„/X ç‚߾+v0‚)Žð­¢……4ú½ã½`^ÆU4¾µƒk–ÏZÂ2~ñŠVàǼ OOö}Îß÷¥ðÀ×"P|ð[ñ¡o¥!ßÊB¿•‡•ã[°&ªEÕ15±µ±“µq˜8aª.‘JšªOžjH™jL†šRgZÒg[Òé˜F%϶$Í4ÇÁÊyR:]2Û1ß¿ØqFíRÏ©ÅÞÓÔÙïýç—ºO,u¤-µ&,5E.ÖZª \,ÖùáW#Õ{/Ö{±h íþ;ýâçÁHÉ N^À‹~‡ò ƒ˜ o€÷¯ßžÃò=‡å 5¥ÉÎb…~L¾Ÿ[-o“vXÌ -õQ½éò=i&×ʪ[ºR¶®m^®u~ÛÉo[2ç·SjNQlNÂ;ZRv¶ÀÉ/øMVnNæü6q~ÕøÀ¯fsšNëQ“ÎSp2ëÚwÙ³û’W×EÏî‹nÝœ»/8v_´—ú=ÏwÎ -‚áÛ GòÛÃ+Æá VÂN­¾ËÜ*š-¤pÿu"LçÂxEë–3.¡ñ}³î¬w< úâ.î+WxÂüw¬¬# kiÿ@87ðS^àçü ÏA_ -÷}-Üÿ —•…à[(+#&ð-v 8ŠÞ_'Âj¡hJ;U;Y7U7Õ?Ý?Ó”8Û”HDŽ٦x|ùdsìLcôT]øDí¡©ºƒ3¡ó-± í©‹‡»Ž,t]ì9¾ØC–;ÀðÅ×A7…/Ö\¬¼þ‹u¾‹õ> õÞÔ¿Ë­e×ϲ~¿#aá.°Ô/î‚î•-œ%õËo¡$¼Qè–ͬá¸ýŽß‘h¼µÄúßî—»ÞKŠå×ÄüÊÔǯû³³Z¶0†£%/“PíNÝ0Î/Pý ¯ÔoûÉQòíÉŠíÉJˆ7y{kòöª9Y± JRjNÞÑ’¼³%yáÝ 5AÌoŠšPSŠFsªVKº.øm?+d—ÞË^‚ß® .è÷úå×Ï —Ë~Yg!Ëž³ÆanwÇZÂý×ìYx:ì8Ämv{~ËÏãÅm ìþN„17"̾2‰½{Ö÷öÅïHÊòÿ-ä‡ß±‚_³Bߨ’çÿùIÀ—üÀ¯…ûÆŠ|+=4^Jï¯ §WÈFLTGNÔ`“X&}%¾Žr¦>f¶!–‚"8Û…fêçÄ!Õû'k÷ÍÔÏ7‹æÛ’æÛS …Δ…®4€¼Øu P/´ÄÃây±!t©~?ó»Pï»ð×üÊžÿ~ç Ëú]Æ[Àëã^µÆo¨¬_ÂK‹ç?ò+‰’ s¡åÿÍ~3äÙáµ~á—²gµ²'¶kVÈ8y{ÓÿÈoW -û­3iëOñx“¶®‰áM‚ÛX‚ߤíÍIÛ›’±æ¤ o €¹IÊPc(ViJV“†~µ[Òõ[š’_çÞË=—áWúáoEûÇJŽá[ÜCǰñŠÐñʰñ*l¢*|¢Z÷.èÚˆ©Úˆiqä´8ŠŽPø´8lZ:S<]sp²*hº:hºîÐ\S4œÏ·%ηÅϵÅÌw$,t¦.tÆŸ4ÇÌ7F,6/Öï[ªX¨÷Ÿoðoàü.þÒoäŸûíÚØ¯¤7œ ï‡áP‰Ô¯huðÆaÿ.~… ¬µ„zKëÅØÚ˜M[f–>p§´L.â%¿ - µ+åç丒å@«PGâV®¤mí‰ÛÚ $®vŒð&*´'*¶AIJmIÛ[)Îo¢ùUjJÚÑœ´–ÍÍÉàW¥)iw#xU›RÔeÒhB¿-GL:NYw£_÷žKîÝxýÊ•ùí•ñÛ}ë:kÝqÆ -êâ²ì:cÑu2ï>kÎ÷ æf±UŸ,azš‰Ó­«¸µ_~oºQá—à÷¶ëË;Ø+ôëþ:Ó¿¾ÏàGÂ*Úï=áe~?æø}ÌñýøØçS.ö9×÷K~À× ±"ü•q˜ÂØÁñ²CåÁãÁcÁã•!•¡UP4Y2YƒMÕ„NÕ†N׆A35¡35!35Á35‡fªNWï8Ão;jŠÀ/Yh…rÄ|[ô|[NdÀ۹Њ'¿œ_?ÁßïMôü Ýÿ]n [ÂxxÍþåŸüÒvèð5÷'Tð» -~ûÂ0|8‚[<ãeçÊo$ŸG"©p endstream endobj 1823 0 obj <>stream - ¾Ž’½QVæ-”€÷ï¿þ,Ü]ÅÝHXAýbŠ| -½2+d0+Dx™_N.áU@­Ékê\“\G’40Ûž¸•ŽÛÚä°D…¶¤µ1¼‰J­‰œß–5~!Ä;hæÂäUa5²Ào²:ŸFc²fSŠvSš~s†qÛq‹Î3ö=hÖq÷y§®s]çì{ÎÙöœ³î>kÝuÆškÕyÚRˆÉí:íí>mÞs†¦0®¨-{¡sì¢÷¤C?=“8pÙ~àŠýàò{üÞp}Î÷â¦Û‹[nœ_êv§̾»Ðûí~ íû>Ë÷C66šíû1Ûï#s¼?=¦r½?çú|yâ÷µ ð®¢÷sá7"í/;0^vp¬üàXÅÁñŠC“•ÐAhª -:0U}`D°höÐLÕÁYìÀLÕþi¾U3Õ~³5A õ‡ÂæÃCæ›Í5Ï5†ÜùÆð…úø§‹u–ê‚–êýëý„Åó"w Ø›^å÷½)ð{óþï-¸…r¹-úÑÊvaa¤xý%¬®°•îpJú\°ìü]E¿ìÑ«Q«ƒì²s`˜®(ƒW±Bã5ƒ]›’[›<Ï–['w¥(t% Éw&quÈÔž('Ô–°O®5A+‘_-s[ÄÛš Ô–¸£–ʉۛÁ,ÕˆÞääª6&ª4&²ù ©6&«7&A”fc²V#6h>lÒzÌVÑí§m±S60‘;NZuœ´ì8eÞqÒ¼ýäÞö“ðÁb]§8¼è÷”9Fŧ-zÎXB½g¬úÎáÓˆ}ÜNK»KöÐàeȾê8rÍùÙu—gןC7\^Üt}Éù忾ãúú.Ì_wšÂoîy¾½ïõî~Ó÷ûG>ï³|>dùŒfc1ïÙžŸröÕ*0‚ÁoÌê LÞÄÕa(žð¢YÉÓÉ&øåð²»î+ ¥ß4zpuäÀêÓý«Ìéð¾õ@A(Ɉß/û ~WŸþ\gм á5~»Ó»e Ãçõ—‘·A2דéoæ7Eê·SŠWêÀ” 8“¥õ°ÎY6pQ®<°m‰WhIPlITl­kkITjI€¶·$Þ^ò»ƒÚÙ”¨Ü”¸» ñRI* øÕâMÒlHÖ‚êStR š2ö´ÛÛzk;&dÖzÌ´õ¨ eÚz̬¿‡j?nÖqܬó„Y×IôÛÃð’ß^©_z ü^Äg"ðeŽððU§§×œ¡gלž]wÂ/n¸¼¼éúê–ÌßÛ.4‚Ý€ðë{̯'ùÅÞ?ò~Ÿåý!Ë{4Ëûc–ÏǬ5~¿äzÉóý -#8?à[?Vè?V0^8^8Q4^4Q4Y4U¶o -ŽåSåSþ(”¾x¦2š­ œ«œ-œ­ðŸ­ð›©ð™©ðž­òžÃ¼æ«½ç«}j„|jÁ©?^³Â{¾èWì÷½Î÷»Ø{Iìµ$ö\ ~}éEXËÍûÈïÁå6$Œ/¢lÿA óC²„ÿØ/­ŸC6ö;ÂùE¼O9Âküò æõß·‚~y¼#ûy¿?á–Å+ë÷Wý§üâŽ&ÜÔ$ÏY¦XjÚ~Ì´ã¸iç š¿Gø´F¿çm0|¦˜BÂvl -_q‚ù;r ;>䄹n¹`aœÂoîy¼½ïñö'ôzèõþöá‘×è#oô›åõüæx}~ìýÖÏp -œç#Ë÷ûVà7Vè7^è?ŽßëÀš( œ*cùO—ùbå>3å¾3HÕo–UùΖûÌ‚\Ìk®ò„櫼ª½¥Õx/Ôz-âV+¿E±ßî¼ú.öúrY´„þ^ïƒÏõ7|o -ZnÙ¿ÜÊ΂ñE²¸š{œý2ÂÂæGpø/üB¡’¾`üjQôW®ãy¿qÂð]á ÿÚo÷âY ¿Î[2r@2²',[üªÀ¿ì×ÿ_öËßQ¥à„4y['IÜ8ºhÌo´àîø›.dbצÖÔ‘(ב Ð‘ ˆlY J /N[d‹5#^…¦xŦ%¨Án— ØmoŠçåò5`»(å†„Ý o=—j}‚Z}’z}’†P%Æ@±v}ª¥Gé×§è×§4¤ò5¦7 !ç=-‡MÚŽšáN˜Â'÷vQLqAî=kÕ{Î#¼bn]q„<«è«O)0œ_Þr~Ýv~ÉMa·7÷ÜÞÞwûòx=ô|O"a¯Qð e{Êñù =öý’ë„I±ï·|Ÿ±Ÿ±Bßñ"ßñb?¬Äo¢Ä²4`ªÔªÔoºÔwºÔgºÔ{¦Ì›À2¶$·Ìk¦Ìk¶Üs¶ãð’_ï× ýÂf‰¹–hø -~i~éE²è÷{ó¾ïl#aáDxÍu/^ÚbgÁD8ìg¿D8DÆoÔ¿ê7Œÿʆ`ÉÐ!ÉðAÉðÉð~~ÂþµþF¿üU†WŽÛéDû,;¨N©_0»¥3£Ý[¤÷m“Öõ+¿Š$‚Š­0daÚ[oœ -MàjNàÏp ¥Fl{#àÝÀï®úx)^2ËU‡©ý¯F-¦Y—¢Í•¬[—¬!á²QCš1æÃéÜ «î#&íHئ0Å-§áŒ—Ót"Œ÷ˆÏY1Åù¼0ˆ°Ãð‡‘+ö,ÄüBúù 8)vzqÃéÅM§·œˆ°óË».¯2]ÞÜw{sßýÍ}ÂDØ—þŠ iŸoO¼¿å{xúŒQÅ>%¾“%~ÐT‰å=]âE„Á,ËðÎ2¼å³s˜û\¥û|¥VŦ0E~j½Y‹úõþ…_ïïìuvx -,ø‡È\È -ð’_®?ô{HÒˆÞý¯ú‘ñ;,ãwä•_.~³"¿ýIf=>@$3¼›)ðÏ7sÉo"WG"ç·ürlñTk<Ë![ª1N±1N©',‹äD¶NÞÎGëäø]lµÜf©z.åúøÝu˜ŠXšª8AMœ¨^—¨Ö$M1U+”ŒÕ$iÖ$j×&éˆpŠ>eP—jXŸŠ~Ò÷`dôÛrxOO˜Õqܤã„içI3n-}†Ý ¶ì9kÕ#3‹áA éËvú…)Lki¼œ…žßp|ÎfSØùÕ]ç×™®0…Ñï}÷wDýR£Dø#[KãöþüØÒy>_ó¼¿æy}ËÇpG¸Øš*öš*öœ*ñœ.õœ)… н(Ï™2ÄËùE¼ä×}¾Êƒò$¿ž 5žä—k‘ù®õëù½Þ‹¿€Oñ·ìÂß[yÅp.Üýè• ~²Ò -ýèÂdoè7l•[?ÃùoÂêpÝ<¢ËVÿ÷ýJï±r{œ¶Ê¶î ‚Δ­¼\ilw&sr;’ð.ÝÏ• ð’ßx…¶xX3£ß–x¬™ ür!^ WÈ\‰;¸å±›³Ê2lwÕaÊuqÊblwmœŠ´xÕÚxµšõÚ q"àÕ‚ÄT-”Œ¡\ª -ýêÖ¦è‹S Å©ˆý¦×¥í©OÇ€0›Â°¿­@ø(dÌj?¶‡cæ·û ÅŸ#Â4‚ûØ‹¶€ðE»¡KvDØž#Œ iGº¨‘ðM§ç¼ß—w°+·¾ç½»ïñþ¾Çjô¡çGè‘'­¢½>A9t!šúšçùõ‰ç·|o^ß -=¡±"Ïñ"¯ñb¯‰b¯É"OhªØcªÂ2yL—¹Ï–»Ï‚\.·ù5~=/úõX¨õ\×b­ç$ö`-²ê<~ò»o ï'–Û.·³‚‰í!¡•Î`®®`¦XÒ"K˜_?Ze~b$q’¡ÉP¼d(N‚~Eÿ^~åÖîzÚò“ehKGÒ¦v™à—@¸#‰JÎè·=q‹p'—+k‹—'¼ì„WQŠ7N‰Ø*6Jñ*5ÄmoˆÛÁ:™Æ;×Ææ¬´:J¼¯j4ð«Q› )N¶:l‘,Æôª€¶äÔ„ŽÀÖ˜ð2¿ðC“Æt“¦ ¼ºÅûm=b µá ÝS˜;>mÞuÆœ3¿aRlSxà¢íàEÛ¡K¶²„ŸqW´dü"aXE;½¼ã„«h"üVJØýý=·÷Ý>úÈýc–^‹ÎöüœãÉûõ”úÍ÷øZàñ­Ðƒó‹yNßIÞ/öðr~ËÝf+Üæ0×¹J0¯¸Úc¾rg-@µ¬ÅZwÊ Cî‹uîký.5a-ûˆðþïmÐåvÖÁBà÷Ãûg~ƒÉoù%¼ÿ^~ÙN§5mmKÜ‚áŸjKÜÄ÷õöÄÐñ7âÌ~Ï–¶„­2÷s±Öøm­qò­(W¡9bÓä*!ÛX…†XE®8¥z -ðÖÇ ZwÖAqB»`ÎÊ&ŽÇjcY̯j­,Þ8õ¾:u´0†SÚzZ×#Ï=Bu(Ô´áð^,ÃŒ)¹<^Sü§R¿ÍÆ-Ða£–Æ­G ÚŽaG` -³Ut'Þ6Çm§ÍùYŒké^viÒ6m/­'üôöìº-¡Ÿ¡bÇç·‰°³@ø (Ît{wÏõÝ=—÷÷œßßwùðÀeô¡ëè#×Ñl·ÙîŸrÜ?çx|Ʌܾä¹}}¹Ëw§)ì>F„Ç -=Ç =Æ Ý'‹<&‹àè>UÂE„áèÍ”¹Í€ßr×YÀËZGüV»ÏW»ICÅ ÌrÛB+ÆËúmF¿Œðw|iïw?ç·ã€ÔoçÁ•®C ïŸù Y•Ù¿r±XɰèßÃ/²ZWÂÖÖ„-,¦XZâæµ~Aî´&ü?8"aœÈ›é÷l^ç—þÍò-qܽ!~ÌElê1EŒó»½!~¿*މǸb®]”°TV®¥j XhwM,ëVÊ'¼ñ5 ZâD»€×°!Õ¸! Îda˜IpjV—ÆŸ›cœ_“Šäb²óü6g5g6gèµÖk=¢Oav"Üq/MsŠÏdn³…4›Âa~!}Û?½fÿ ºáÀb~áw\^Þ!Âw]ßdº¾½çòîžãû{ïï;|xàøá¡ã‡GN£Yγ]>e»|ÎvýüØõs.äò%Ï•»awŽ0Tà>^à>„!·ÉbŒW솕ºN ~Ëy¿k#Þ¹j7ÙækÜøqÌá_ã×SÆ/n âjÛÇÕ¾¹ƒu€õ£óÀrç!>©b ¼ÚÊ.dÑý#ÀB_'ú³ßµç¿¿ºÿû_æ÷ñþ'îÿ¶Äoâ omßBmnMà=®Iê·5üþp$Ë›¤¿‡óËïÊàn)´p—ª8¹`¶ü"^øeœ/L^8½¥%1PE¿<[/ \b«\Í…~‘m¬Z5+^"¿Úµ‰º°`®ƒ±‹~‘d#âÝ‹lSM!qª ¿lÀLá÷áoΠdü6¥5§6§4¥ë6gè6ÖƒZëÃî Üq£AŒx2n–Æ=–Dë¿€!á‹a¼-õkÏûå·ðŠÖËÛίïº_gÞ¯ý‡öB²G³œ>f9Êvý”ãòé±ó§\g"ìòõ‰ë·|YÂÌ_òËá%¿B®ä×õ~©*œ¼ÄÖU¶y^h޵®2~½é:þ¼_ø•©}ßr‡lû°0ŽA1cn"£bnþ†®„ò~£eý²Í“èiìû¯þÔ/nÒøc¿2ñHÿ†ýWMq[›âä "¼µ%nk ú•!ÌBÈ4މgkâ¦Ö„ß[˜ßÿGGÎ/üNú#[dg:üË›ãäšãä›âä¹+ÌÌ/£ÕÅ(ÖŲ”êx¿õHxWmìÙÉ[+$ÅËù£Ju¬*ÉU¯ŽÃª¨jò[“ S“¨[“¨W“¨_¤_›¤ðs‚^e¼.«*N~Y•Èý£šDƒÚ$Ȱ&ÙPœlX›bT—Âø7¦5¥6¥é7¥é®õ«G#ظýøžö ÔAki[KÓi+ô‹„mèDØŽ÷k7rÕîé5»gÐ ûçHáDø•ԯ˻LFØþýÛìð#‡ÑGŽ9Êrƒ)ü“_¾7òë6^è6Q芹LC®Ê-qÁJ]À/.s™)sž-çš«p™«t§æª¬Ë†ÍW;/Ô`óµÎ2~=ð”>ßñ[Tˆp‹ áVšÂÞ5ó–ÐB^š¿!4CÉ/Í_\?GJðÍ9¢•ÁXF˜n!Å­>ÅPñ¿è÷WÛ6þI¼ÿ ¿±Û(9òµµ9v æ‚Ï›[â6ADx ÚÄ練„ß[þÅÿG Bþ~¾¹%~3ý©-ø·0Üñ_ŽKÀ¨!V¾?Û­³\èW ÅBJu±Ûë˜ßÄÝÌo­Ì²W˼_Z-sÁä­ŠTª˜ß8 ,^ðV"aͪxm¡Š8íÊX­òXͲH£\¤Q­.¿¬ˆÑ,…ß¿Sâuëm@ ¢ëR ëS RõSu ¦4¦ "œ¡Ë/¤ ÚŽ¶7n;±§wœ0“.§9–½gq›eÿy› èwð’ÝÐeÛá+ØÈUÛ§×lŸ]Â\D{qÓáå-Ç—·œ^ßqys×åm&ùÍtz~ïÛ"á‡Hxô¡ãè#çY.³?æ8|ì„„óœá¯ù.з"\à:r \& -!gž0S ~§J§Ë€°ó æÍ–S@Øy®Ò«¢ªeZï«uY».Ö¹}oð`_ὑßÀŸür«hÁïJ ýJº!6|©Þ`8ÿ•ñ‹/ÏYáG0=¿xã! þçýþ"$°~yŒùþQÿºß-ŒpS¬\c¶4ÇnEÈØ–æ¸M,$ 0'Êâ c¿³6dz?VêWŠ7F®>F®.Fžå)ŠE -bί³C»«>aw}‚Š8±‹±SÝÝ|°NV¡ËâýƨVÁðE¿ÀðVÆjBå`¢M«V¥Z©‚E¨†+Ñý~^¥V ®5)­ŠŠ®ŠÓ©Ž×­MÔ£«aÚ )ZPcšvSº%Cø¨~ë1£ÖãÆ­Ç÷´7iƒå4fŠÙu-Ú¦eÝwΦÿ¼-¶¼d3tÙ¾b=rÕ⳸AÌ~u;¿Ét~›éð.ÓžüÚa0‚8|@¿¸„&¿Ž;~zìø9×éKžó×'.Ì/|ø–ï2Fƒßgòë< „¥Šðt©ïL™#Ä.wšã;ÏU­iå²Pîbùu^»,Ö¹~¯w_fó·éW~^?ÓâYf/w #˜AÅÁäð†ò~#y¿±ÿN~b¶°p̶FÑ8rÅnnŠÝÔû;D„ fü¦&i¿7ÅÿÆ÷;÷øß!ø³üʼIoCŒ|=àÉ#XLQ¨ŠQª‰ÙÕÆì¿uñ*8­ŽÝU‡UÇ)WÅ`°T®A¼xmä’YÄ[)R®ÄÏj•1j|å"ÕR‘Z©H½D¤Q­^ÌŠR+ŽT-ŠP-W -)ø% þiI”:úÅ41‘*ÉN€u¸Ž˜¶‚Ô'k6¤`©dF¸åˆ~ËÖ£F-Ç8Âí'LYDWÔݧÍq§´ a8¸h5x‰¶a„™bJ€lŠðë;ŽoîÚ¿¹kó6Óæ]¦FÅÙÃ*Úþc–Ãh¶ýhŽýLJÏ9Ž_8Â,æ×Ïwž(p -& yÂEÎSÅØ4v¢/ ðbÎX…Ó\¥Óûe„k€ðwÁžË>øÓ_ô+KXv¯ñ˯Ÿ™ßp ÷æX‘d(†Îÿ]üŠ6sa€,Ú „±˜-ëü²šâ×õ;Èe~75B±›Ù²\ˆðÊÕ‹ä/ú­ÅY5\Û«cv@0pñòrnšªWÁÛ8¬*xî¢àÃn.W­\)R!¼°Ö(•00T+ÁÔK¢5H. üªEàñç/üæ2™J£5KQ±f™HÃò»*^‡.ˆiŠqC—F}²&¿il -ù°AËaÃæµ„ÛNŠqs;¥ÏXá~$ ikð˶›Ŷ켘&²-~qÓþÕm»×wlÞܵ|s×êm¦-Na˜Å÷¸ËѰ~d;še7š}̶ÿ„;~ÉÂN_Ÿ@Îßž8=áýæ;1Âè—Uä4Uä4]ì4]Âá.uüÎq~æ+¿Ò€-k¡Úq±†kŽè×é{ërƒï¯B/·.ÿs~ü´ü†nìwøßÇo½hs½hS½è÷†R½©A´©‘Ê›ã6Ó’xKSüf,޵‰os#Æ>ÞM²œÕC‰äê£åê¢åȯ<ø­äF+ ^ÑÁ/¬“Åä·&^µFpÜnÀ UÄì¬í*^—r¹HÑÊ"Õ -Î/žØâØ%¼(W~5Š¢Ô¹"ÕK"²F +D›>si -a­Rò‹#8F°6mÑ”™ÂZt:¬KW´ôš3 €p36­R¦¬v¼G #Ø‚{Þ§°uÿ«þ –DØz×Òœ_:#¦ëZH±Í³¶/nÚ¼¼eýê¶åë;æoîZ¼¹kýö®”ð}ºœõÐúÃ#›Ñ,›Ñl[Áïç\ ÌõÎw¼R¿|è×qºØq¦„å0Sj?Sê0[æÀvä ;ÍW:ÌU9̃\V5×BµÃ"TãÀûuäüÖƒ_ïåF_ôÛä¿Ü¼fþ.µr~…–Û÷Éœo0‚Ù‰0œáÕ>¿ƒ¿ð;òÚ/â%¿(·!úwê7Š}Ë€/P7ÇË5ÅoA¤±²mYÛfü« f‹ ^¶D—ñ-W-_ƒ)p‰«£•ªeæ/¬–kãw×Àð%¼Ìo%ø]ƒW¹,zWYÔ®R¾²èÝå"˜¹À–ðÒ‚F-ÍÜ¢hÂ(ÂHõüµ‚µÂ$\ˆ¸ÏÅèwMküŠ´)²òXºL­S› Mº´ê’µêñ\Òˆ°~SºASù%¼_)a¶îæF0{dتL_¶¯ƒºÂßWB¿6Ï®[=¿iýâ¦ÕË[–¯n™¿¹³÷ ¾cõöŽ-~KçÂïîÛ¾¿oóþ•,áOÙöŸp®ã§\{èKžÃW$ìÈûuœ(àš,t$¿Ž“ESÅÓ˜ýt d;S -ÙaŒž¯p˜«pœ«´ŸÂÕx”f¿Pm¿Õ8,Ô:,BbÇïuÎËõî°„¦éøòW±¸…ôR+kÃ{Ië ó#ø #¼Ò,ã7r•½?–ð -~Q.wýùÿªßºèߩߘâú¨ßê£þÁŸ¯„þN+jò'åœr³•âGíšBõ"jíð•]6׊¶ÓüÝ^%ÚQ…Sx'œó²¹ -Ùr“ÖÌü*ƒ¢à¸»4 -R†cY´J)úex±bnà"Þ‚Hüõüp5¨ ðªPð¡0R£ˆ¯8J“U­U­]"Â@n©H—÷K·™âuk€0œs„µë“uRô°T½Æ4ŒsŠác{0~-Ýq”üŸ=5lÑ{֢^`=ˆ7…mp -s»³ìP1^—¶zzÝòù Ë—7¯ø}}{ï›Ûæon[¼¹cýöŽÍÛ»p.lûîžÍ»{ÖÌï(ó›#Û}zl}¿¹à×ý>qÏgÙO8@“P!~‹Èo çW†0Ëa®Ì~®ÜðÎUÙ#^ôk/áåü2Âßa×»­õë÷'~Ûø)ܾ¹}Íé_ú¿ô -¬aÎ/†lãVþÌï*ç÷ï÷ñm´aãoô+Žú]õ›8êHâüþGöºÈßê"~‡ê£`i½µA´•¦ëðÊÁlmÉ7ÄÈÓy.™•©N„rë¢å!áÊ™Ý!-åVRU¢Up’+bç¹$WŠw·l ·Œ™Â‹ÆÅQ»éH fb[LëäBŒÃû$R{‚„^ Va¤¦PâÕÂ/c«[£ÑÝòX½ª8=ò« ~kq -×%éÔ'ëA Éú )ú ©a¦¸9ðÒÆAfW´:Oòoð —xôžÙÛwμÿ¼ÅÀy«óÖLñÛ#MŠG®Ø€ßg×-žß°xyÓâÕMò{kïëÛ F°å[8Æsaë·™VïîY½¿oõáõ(þe_P „í>?¶û’k~1û±'ø%œâ‰BûÉ"{n—ÈÎ_Œ÷kÇüÎWÖ_ø]Âõ3çZ‚\ïÂûõYnö…ˆ0w!k#¿Hx¹]hÿÜZ‰„WøU´„ÿ±ßá¿à—½yc(xü­¾A4òßí·6ò÷ÚÈßj#ÿŠë H$\ rÿ„Wþ{]ä& \-øÝ²¯|½H¡>Z £bºI$¶Ûè7sÅÑ -ÒËÎ1;jcvÈú…™ lÉïÎÊèQ;+؉-›³¸6V&°*?W‚w‚ÔŠ HÕÂJ5?\µ ~ NUÙÀE¹aêyaj,ø ?ÉÔàWs­_­¢(íâh¨ñê•Æè—Å”Çà‡=ð[¯_¯W¯[K„ñ^R’.óKq„±4ƒ†týÆt}Ćl9ÍN‡™ßŽf]'öâwŸÜÛsroï)³¾3{ûÏš÷Ÿ³ì?g5pÎzð¼õÐì¢íç×òÙ5‹ç×-^0Âlßb~ÍßÞ…, w™–Ðû{Vî[3ÂÚ|zdû §°Í§ÛO9@Øþ+”‹åIýJ ó~á8ÅÖÏŶ3%Øl‰-—ü–ÙÍ—ÛÍWÚ/T9,ü“~—Ñ/‹FðÚ«XËk’úýÁû]é@¿‹þšß_¯ŸÃ7ð;t@2$ë7pM¿Üíü·úÝL„Kûú~ŽØT¹¥>j[C´½Â2xk}ÌVœªð­Šñç0Xê¢Q±H§-n¬ÌF+a"%˜¼µèwg«†i½ƒð‚Yd[)CåQ4^1 TÕdwY”á%eµR:½…QKCæ)hU!³\O 5š¹€—ùeÀ/àÕ„ -"´ -#µù´ -£´‹¢tŠ¢±b‘n óK¡eÁq8‚kâõj ]ÜY½Ö/Fÿ7¤aÂBšn9bÜztO=lØyÜ´‹>!ø5í?kÖÖb [Âqð¼„a\¶~zÕâÙµ½Ï¯™¿¼nñêŒ`K˜Â¯oY¼f i |Çüù}Ÿiõáž5øe#˜#ló)ûœcûå±øý–‹¡ß<;h<ßnür„í& í&‹ì¦Ð¯e3]l3Sbƒ„K¹æ˜bð[„×áåÎ7öËvay³–›|ñ^RS€Ìí¤ åV™Ú€­Ðþ†·ã€¤:È%ë·P"aúÚAá+b¸-”2xWG¢¸Nò‹çÕ¡5x‡öI†‚$CT€dxmîmƼj_ß?÷»áÚˆÍDGnâc7‰#¶ˆ#·‚_8uųרmlªÊÄ­Š™_ Z'b·wå(yÜU…·w•¨P-š¼» V-ÚU xw¡Üh©\«"ðÊ\–=½Å“VZ!«ó`e -%¿4pÁl.¦å…i< ×|®•iDêDêÒQ»ðFéEcÅÑzà—³º%l9 «hÝê8½Z ~õê’ôë’ôdCÈ)øB¿†ä×ýÙÓÆ½»Ã¬‹ê>nÖs¬÷¤Iï©=}§MΚœµè?cÖÆœðZ ƒß‹6#—-Ÿ^1zÅìùÕ½/¯™£ß–”ÅkTŒgÁoo[¾½cùî®ÕûLëÐ=ëQ"üzh~³À¯õç›/m¿=¶û–‹á\òûãçÛMØMRE,ò+&Ås¥vaôË÷k¿pþ»Tç¸Tïú½.aáöZÆ|8Â2ײð¾R+;"ámÐ>h¥mÿJûHB~W¡®ƒXw ߟƒ†ãwvñß:Äù/ÿÎXú¶”Œ½ó -ðŽ„®Ó™ï ¬Ü É` d0@2èÏ5Ä7ìǵfo$ñö^ö’@?sþ£7Êúó#x}5[ ÚÈ­,1¶…o«8BZmý†h9Þ¦[³å±üÚÄ1LîÄ£ ÕÆ(#[ü°»F´»Z´»J¤\ g»ÊÑTÔîŠ(•r gµj,š¶ÂÕ`-¡âhMþª2®{a% s6/L•R¡TóBÕ„5s77L37L+/\z®¡“©`º…QXQ´«ë Æð3¬«ñZt™H» ã…,q"àÕ'鉓t…è)c]ö~<ò xoóaã–#øîöú¬ŽcfÇÀ¯)Ôíé>aÔwÊdàŒÔ–O™ ž³ ¿ÖíG.YŒ\Þûô²é³+f/®š¿ºfñ꺥Ðë–onY½½eýö¶õ»;ÖïïZ€2­FïYÞ·úøÀêúµþœeý)Ëês¶õ×›oHØåRãy\aò‹ÙNÚLQè×–óxѯ-Va'ô³_ï¢Øq±Îi©Þy©ž6RRËžt;ɇnó—³Z–¥±)¸Ò´B~%m%à·ðîçüvZí9„[°8¨xu(’GчpLúzIþ “\!T0ŽÝÁý’Á б øC«~«¾dФèt£ì°ç¯óÚh"ÿ4…Ÿûÿ\Møj+DB·q–ì6jkm8VCÿTÌ]€’GÉÕòÑý L/^aÆ-‘;Ä1»˜\qÌnØV‹”kbTjcTªEX•ˆöMáî vU -ðªB¥lkC¼"­¢h­ÂhÍÂ(Í‚HXãJ–Äü"Y57RÉ £°f–âÍ ¼:|ºO"ô~"¬G±Ï:E}ÐfW·J£µˆ°æO„Yx:L~ñ=Zøº€Áéè·)Ãxߣ&HØ´ó˜‰ÔïqÃÞ“Æý0‚ÏÀ86Æ_ž0ê?µgàŒéàY³¡ó¦ÃMF.™<» ~iË~}ÃêÍ ë77mÞÞ²}wÛæý›wm`âf~­>?²úœEe[}á ~ÇrmÇòlÇólÑ/f;‘o; xÉïT¡54íáÙ›9nþ’ßrªÂv­_»…{aå¼Ö¯+vçý¦‡’ø+ÒË-þ‚ß-A?`þ‚ß6ˆ#ŒŠÛ÷­vR]ûW»¡«=W˜â>a/4F/µ;$8(Ó•Áý²IöI‚$”Ì´ð_ð[ð]!¼¦ßuT¯÷„aÿ)ã3&Cçö Ÿ7¹hüô’Éó+¦/®˜½¼º÷§Øâ5#|Óúí-›w0‚o[¿¿#Œ`ËÑû–X~zhùé‘åç,®/YV_³­¿âÛ1„ ÙŒaÊfâ‰Íd¾õd×~ mfŠ(Ž06 Ç2›Ù2›¹r Kè¹*–í|5–U\·ž0ø¥µ4;öùÞù.a.ÿÍ@8üþh  #„Û%Xg€¤+Zí -ZíæëÙÇÕ ­ö®ö¬öH0IŸŸ¤ßwM},hµ_š¤ß‡~è-é÷^ð^ðb­ z­ ýЧÇ/úgü>õ!¿ë« -ßR¶¹2ƒôK°¼•Md¯h ~É/·ƒÝÕ…ä^Ǚזá$ÖÌ»)¸»+£•Á,È­Œ†Ïlì*3¼tW¥4’ÛÜX©Niàn»,ŒW†ñS$ÎÜüHÍ'‘Oà¡™Žå"OµÇ¡`ñæ‚T«áL='D ÕÌ Õ~¦+-\Èh9L'O˜Îð!LëI˜¦Lù˜zA˜zq.ÖbÏ8TÆjUÅqUÇkW'àËê-Ó Ö%ņÍ@8ø•½> 1é8²§:jÔyÔ÷k1¿Ýà÷¸AÿI£3{Ï7¾`øô¢ÑÓK{ž]6yqÅô%bìÕuó× VÑ7amõî¶Õû;VïïZ}È´üp²½oÁ~„}zdñù‘#Lƒ˜ÊµÃòXž”p¾Õdø† -­g€0‹¬g‹­çJ¬g¡RÈeÖ³@¸²eÁÂóÕ2„ÅŒ0SìÊ/¤=—0áŠ]OŠ}4aÄëÏð£Í¥Ío¥Ík÷•tp­vÊÔåGù®vCÞ«Ýž«=ž’I»¤Çm¥×U6I¯´Òë.ú<$}žÒz=V >wI¿‡¤ß“kÀceÐceè/%ú×ünPEèæŠM\¡›P1ÇVýÊÕ V¼’\¥P#Äo£âü"^ÞoÌÆ~9¹xª‹×©x¼ì.=Y©ÆÉä®MÑ.°Õ*ˆÔ.ˆÔbבm„² ã¢ñ -CV-'X5ýªæ‚ÏùÍÖ€rB´rBurÂô --çÀt…¶ô8D3'Xýqˆz._^ˆÆ“Püª†#áRÄô°ƒHƒž=ÄÝ›•øÄ¢|Ö¨NÐ`¯ÞªOÑkÂéH˜)n;¼§ý°qÇȰóˆÁ:¿=Ç úNöáü¿ÆC猆Î7>o0rÑèÙeãçH˜ºjòòš¾aþú¦Å›[oo[¼¿cùþ®ô!2e„Z_ø`þ‰ùͱA¿HØú[®õ8Œ`¡øþhóùÑæ-´Òæ¹Òæ.ÁÜ Õv÷Õ®N÷Õ.WÊ’t;IºVºíerô8JzœWz\$dy 3Åä×}¥Ï«ßú1àþcе2¹óýwûåf1×ó[!W)_ÃW±F¶hE™|µHCÂküâÕ*œ¼Þ²HeŒî•F"Šmk¤¸ËSlí -«YºbŒ=‰Ðbx‡ia0Ua¶«#Uô«š}H~ÂáÍÖÌÑÊÑÉÕ“¦ǬݬíG‡4Tx@ ztP=ûz„Š5 Ü FFpa¸Fq$nœ.cO*áÆ"Îo% b|ܘ# ~éÍ´a"lÔ -„3ŒÛ2ŒÚ¡Ã‡õ;êw7è=aŒ¯N÷4âüÂü=m4xÖhè¬ÁÐ9ý¡óú# ž^2|vÙèùå=/ +{^^5yuÝôõ½ØÍ½oní}wÇü=tc~?>°†/ø…à3Î_ÁÖÌïfYÂq"ÏjG°4U`5MÍBÖ³ET±Õl Uj5[f5[ŽÍUa®ù*h¡Úv¡²ÃjíÅö]ˆvú^ïÂ_Žöà¯HÓ*/gq~ñI‡f$ü£Õ÷ëÇûõúÑêIy¬´º­´º¬´:K0'I›ó*«rZípZít¤V» {I·­Lv’nø (vÅ’^6ŽqãPvûÑëú£Ïeê‡\¡ËAleÈ•’Uìþ7ù-ÝRÂæñþ,ª«Â¶VEÈUEÈWG*Ô¬õ[¥„E+PòU˜&RÂGD;«£wUG+WG¯Á[.ø„»K" z|ëZ„Ù©Bþò3KicáàW+7ñæ@ày¢ßlÀ‹~UotP  -x)PÍÑ#³T¨þ£½‡‡tÔx°_í^Jf rfòƒýª@8ë ø…© ?hr„C5a]Áö[â¬Rî1CTŒké8-Þ/GVÑè—Áº ©úMl -§µRmémúí‡õÚëvÑë:ªßCW®¿lž1<£?xVs~/>¿dôâ²Ñ‹+Æ/¯¿ºnòú†)vÓôÍ-³w·ÍÞÝÙûº»÷}æÞ÷Ì?Þ·ÀSà‡p4çý²%4ö![Ë dî½g>zßüã/ -lùý ¶üöØbì±M^æ×Ž“O¬(K"l>U`N„-g --gÖú)µ˜)È0¶Â)\-õËZG˜-¤—ØÆU´×rGøG³ß5~ùsap›-žaÙìcWÒæ$e‹ÙKÚìðØaO~í%‚%Åö8‹»06¯Ëj¿›„ ãäåü:á‘ð.8-8RNG¯Zg”jÜÖ)Ü¢œ®AIñæáÌÕæüFèx³CaI 65³R  -K_U®ªl1üð¬Šam¬õ𠥋lé>8¤ ¿|p@óÞ>õ»*wüwÝöÛqËw;ïÒ>¤ÿr¼äªC®µéö1íÝŠÒ,ŠÖ,ŽÖ,i•ÄhC¥1Úe±ÚåèWg­_Ú$Ä+Æ)Œ›µRôSô›S [Ò ƒ–4½Öµ~;èuã–úí; „õûOéœÖù;|F0ö º¨ÿü²Þ‹+@ØàÕ5£W×_ߨ„ßÞ2y„Ñ/(6}×ô}¦Ù‡{Éè}ÓÑ{‰0ÁØ×,óoÙæc9æc-÷ŽC¹æ4‚©|óÉü½Sf~gŠ,9¿Å3%³¥³eTùO~‘0UCki)aÇ¥:§ïuŒ°ÛR½;n$ÂM@Ø Î‚Ñ/ÞNä²ÛIü-\H¯´yKÚ¼$íî’v7I»‹¤ÝYÒî´ÒÆr\isÀc»ãJ‡£¤ÓIÒå ­À±ÛE¶ÕW:ùÅVû¿ b\6³õ³ ›¿ËaˆÉuùïð¼¹<˜÷ú+¿ÛX¡ra -á…?—ƒÊפP¦X®T¾½<|µ³<|W¹Œßª(B™^‚¡Zˆ~Õ h»2áÅ-ŽX˜f^žbû¦àÕ{©—©›¡ó8\ýÞÍGÁš` V¼P«*×~U0x¿Úƒýêök<< ùà€öƒ:÷ÀÀÕ{pP÷>t@ñªÞöS¾í»ý–ÒM% –a?€Ùóþ[º¹á:¹xiðù‘ZQZ…ÑZE"¼]£Ã*‹Õ)Ó©ˆ×­Š×aѵhÝÚ$öÒxÚÝ‘ÄvÐÂM© Xý¦¡_¼ÀÖôÔë;©ÓJ{ð¬îÐy½á z#çõž^Ð}vQ÷ù%Ý—õ^^Ñg„__7|scÏÛ›Ì/Ê}wÇäúÅ>dîùpß„üš}zhöù‘Ù—¬½Ð׬½ß²÷~Ë1C¹¹{ÇÃ3æ{ƒxïd¾Ù¶wºÀý’ß" Ä[l>Sb>[j>[F•[Ì­ñkÍ~mÈ/¶XËF0ú]ªsåýÒ¹p“'D~½4ûþhñûÁùex÷q„Ûø Ñí~’vI‡—¤ÃCÒá.ép“t¸ -­°c'&ér“tc+Ýî̃r—ô¸¯öx°^º~å.é— ³Ó^ ÅΗ)­ÐßìðnýÃùËãe…ý²rª,LžOZç·,bW9¿l.ÅsÞÝ$W™ðò~ÃÔóÃdðâ– vcˆîá‚e¾‘úùQúDXïq„nN˜6ùÕz¬õè&ÍY5`ËB¼ûTaa|ýjB÷÷kß߯so?°Õ£tá'wÕîøï¾å»ó–·ÒMoEè–ï\E*߃¿‚µ²ÃtGèåFÀ_ºôÿ “¥]¥]­]$Ò.i3¼¥±è·"^ªLЫNÐeá+³’ ðpw¿Á2I·!Y§1E¯)U·9U—ùexaÙÜw˜2üö×ï=¡Û{B»ï¤ÖÀÁsÚÃçudý>¿¬ûòŠÞË«@XÿÕ5ƒ77ŒÞÞÜóî¶É{ð{‡ùÝC#xÏ{ί)øýøÐôÓCSòkö5Ëì[66–c&ãwïDžF~§òM)¿…̯94[²w¶tï\Ù^òk>WÎüa©_kòkÃûµ[Û‡,vZªs&¿nœßFÞo“à×oÍý_¼¸Ò°ÒîI:üñþQ§¤Ó‹òt¹¯vy®KÒíÅZÁ¼eò’à­%oI/Þ-’p·Šd#Ån?Ü$|ÂõçŸû ~×ï¨D°ëÚØï¨œÅ¯¢ -toƒÊÿ¬²P™x¿eaŠeaJeaÛËÀoÄ.þœW¥4Nx¥¯Ÿ*ƒT)µ|òû$T=/T ƒe*Þ„¥{C¸p…•s¤î“(Ä›® ËÚ¬P­,¼*xµÁòø€Æƒ@UbxU2ñ¨~ŸÖ½}Z€÷þ~Ý{ûõx¿zèfjÞñW¹å»ë–÷ö›^Š7¼Ðïeøƒ`¦‡jgÃ+R/'B÷1®ÛáÿüêDëp~o¬.T«[‡(A• S¬W›¨/N2¤—ÖÒkä“ À¯8Q§>YWðÛ’‹gôÛ‘¡ÓE„×Í_ô{\§÷„øí?­=pFkð¬Îð9æ÷ù}q…`æ×ðíM£w·Œ‰ðžwwŒßCwßg¿¿güáþžÑ&€—÷k¶ßÓ±“±Ç¦D›|“×tÛ;“o1S`9[h5+õ»w¦Øl¦Äl¶Ôl ï-ß;WaA~±ù*+ÖB5ø]¬Â6‹ÂµhZEÓí$º£$³/‹L‰Ë\¿Z±ËãÝÈ/¶Úå-$éòYíö¡Á>’nÆVÒã#Ûj¯/îÓèó”¹Ï+Cx€åN¹­üï¿æwÂÏ6ò{h ¼µŒó»õq~ËBäÿ¨P¬”o Þ°eáxò[NxÑ/âÅðÝqˆW%?L5ñªå‡ª^©_¼ÈL~sB5ñô3ý"Þ=XÓ²± óñá!8±Õz€Ëc µ°`†îÛ •LL53Hý^æ½ ŒÃ—üêÃñ>»·ývßòÙuÓkû Oð ëçwvg¿–åaºYúÙ‘úaò«[‰t‹côJb±ÒX½²8ýrôk~Ù®JЯM4¿Œ0î”ʼnºì‡ò‹„ѯ®ŸÓµáî£XÏ1à…ÓaíÞ½'5úOköŸÑ<«5tN{ä<#¬Ã/¡õȯþëël3Â# ~3>Ü7}°çãC lòé¡É—G@ûšeú-ÛäÈ}lö ðr~Í& <³É<Ó©'&è÷‰Ùt¾ù Ž`È|¦Ú;Sd*ãƒA<S¸Â|®ÒbÂT5#Œ-ò#˜]ÈZ¬sZ¬sÙ`ke“7ž·ðS>à¶ \3 0Ü¿~½…VÁ,%éò•à.?Ê—üúü€c¯Dðöúñ[­ÊÅ`µL©âÅä@–*¬ïjÜ ÔÌ ÒÎܧ ÝÛ§— ÁðÕ¾ã¯~Ûw÷-ï7=•nxð~wgP»¬ùüfE á}X´Ãß!ùQz…Ñz…"½¢ýâý’X¬4NŸü€ßŠô~kð=ðuÉFœ ×Äëˆ`ò4¤êÓ{¤ñUÒÍ©:­i:­©šmiV*Öî<¬ÝuD§û(¤‹Šk÷×ì=¡Þw - ÓÖ"¿:äWç`œÂWõ^]ׇÌ¿½eüö¶Ñ»ÛFïソkô>ÓðÃ=£ÑûÆ|¸çÓÃ=Ÿa_² “¯Y{€07|¥~M±<ðKá½8… ³™B³™"3ô •˜Î–ReœbšÂæóaj aÁ¶Kµö4…iK7e¹³0; na„}—áC«ÛyEW®pÿú•†;¯(I—Äûõ“tû -~…/ú¥-”¸UÒ‡ÿœçÌãû ~&üWý–òäòÛÊ* ÞöXE¡R¡P!¥Ò°í¥a; ²0ò®\§½ª4|ín’‹áS~¼\«–‹©?V§Ý<^­lXdžjçà.)Ä{ðjß?¨yï€Æ½ê™ûÔ3ƒÔ(«Šlvßög©ÜöW» AiÝ „^»º”ø½ë¯vÛGù¦çŽ›è÷&çWåîõ{ð -×{ai˜a@~q³4ùÕ/éÅǔĔĔƔŔÇV@ †¸Šf„ãô€°8 ü×$èýÊoKªvkŠFkŠ:ÛR5ÛAq†øå CZ=ÇÕ{N¨áþS0‚ÏhŽÀšƒ_\B_æýr#X l½»møþŽáû»†2F‘°ÑÇFŸ}†É2þ’mü5Ëø[öž1VŽÉ8”k2í¦žìáü曢ÜS¬äšÌ™Ì›ð„Íf(Žp¹ù¼ ˜›Â–8ÉïbÝR-¿„®c'®´©Ãé°Û÷Fe8æûüe¿¾ÿ ¿>äwã~ xÿàÿ*0ëIýÍ~J©nXÙ¡meÁkÌRJ¬R¡P¬ãðRœßÒÁ¯*áÝMxÉoˆ*°ÅÇýhñ ~ã¾GÜûD[24¼àÕ}¬r ¯VæÍÌýšà÷.ï÷.úU½lwßòÛ}ÓOõ–ŸÚ-Ûþš·´nhßйÃB¿:wáùì&¿ŠüüÝu'P5ó€ÖýP݇á"²¢Œr¢ŒGæFêçEêçGŠ oQŒáÿOÝ]Å•¦ ßÿƒžéŽcåî…GIIЉcAÒîq\ ʨ*œ$ıvwK§c…à°Ö{]×½wÕ. ÓÝs¦Ïó>k}W-¦ÏÌüt>sÝ÷½­¯TßW¦ï/7 ”ËC‡Œ§1bØ—jñaÃrú K®¢/VêÙ#רû²Bý^­’Bת@±ìÆËòÅ~ßàü~ºØ¯êù~ Ëù5p~„Fð{Ï…Ýw™x¿fôëa~-º,i M«hËÓnªÇ=é1“_ÓÓ>ÓXŸy,0…q[Ça-ÍüžæüN°Î%Lâzýä¹ äwó4ç—ÛOlƒ¦.o›¾œ2=Š„g‰ðßñËîÎ`~çëgZ0Óâ9ƒcˆ®=pÄ?v”ˆþIÚÜ!Í~‘J¨íœûâŸò; ðK#þ™ßµ‚ÖAÐoØÀî°þÅ…÷ïŽØÙ¿7ª¯¨/;¹b~^±ñ²Ð/>(TD7-H]t÷Þ:…7=ªXx—c¡ -&/]%Èm…r€—ËÆðJ`ì^QCº¤1CÚ˜!kÊT4e*›2UM™jˆ)†Ü®ÓD ;ÂR˜ß°Æô¨›¬-_Õ¾[Û±Ïà8`t4¹Ð¯±k¿Áw@ï?hè)6ÞÞRðk ¿ÆþCÆCÆÁCH¦0ø‚å4ù=C'Z°–†%ô¥jÄ`ϯÀ/í™_åÕjÙÕJé• -ÉÕ -$|ãeóËV~ô†üã7¥A¿G_áX~ù-°f©ßŸ—õ‹„ ¿Û1˜¿wѯñžËxÏi¼ï4þáb™˜_FøQ—õ‘7†/Lá'~ã“nãS¨Çð¤Ûð¤þ0>í5’_ÓX¿yl€k|Ð~Ÿ Å_Á±gã¨øÉsPâÔ¹õî‚ÁïŽð¥$ò‹„§F’§/oŸM™¦ˆ„Ñ/Æ&ÎÄLœEÅäJ˜:ÏünB¿xGôÖ©Eq„wÌ\Ùž–Šr¯¥qàÐ0ˆÓ˜ßÛE~ƒëçÿ·ý®B V=ÇïJh õ@þÚ^ëÒŠ–ÇÛÇãíÛÙ»G8°‚5³·&¯ -<«Û…»]¶íÅœt'†ƒž#p(èò®ÒÁÝ=¥¶ç©x›³å`­) VÈ|ˆWB~Åõiâ:ð›.mH—7¦+Ò• ªÆL «)K~›2ä »ÄµÛ×Õ¡ß°†Ôø6Ùä­ùjòk¿ÌÎý&÷~S×~“÷€ÑwÐè/FÂÝ¥¨!—¡>` # —Ji;Œ~u¼_ýùjÓE¨Êpž>)Î_?Ò^yIƒó7Ô/a©YDXùÑë‹çï—Ga%?‚9Â?Ôj~DºŸ˜bý/ú_šô¿6ëo¶`¿µè~kÓÝjÓýÞ®¿Ý„a -ëï:ô÷ '61‰𣮚†G>ícŸæ‰ÒaÝ“Ö?í3Œa@˜0Žšˆp4G˜ÇM ÇOãAôÔ…ÓÙí”ItG%71nþ‚_¶ þ‡ý~ºhý¼ØïüÿU¿}y+áU4‚—õ x×ð~ذÅ…÷C»×WÞ ÁðÝÙ»[ÔͬŠhÍ\(‚º0þYûB)Ãë.»/ÿPžÌ‘¯ èîÇ<5Þ@•«jËÁesK¶ü6eÉ3¥´HfÁ´åªO“Ô¥ŠëÓe 0yoC¦º1KË…SX s¹~§¨&y]mòººaõ©‘ðlÊV´hÚ÷:ö™:÷›;XûÍ®ýfÏ~sדï É›ºKŒX©±‡‚qÜ_x©R"Œ¯¯dW”ôg1¿fXEŸ§KH‚[°À¯j©ß÷éŠð¯j>|MC~¿ û_ù§ï(Ùþ÷KÁНŽ)¾9®„L~a#¬¦ÌÆAL~u¿6éo"aúme~u·í@X§ƒ÷ëбh -Óv™ºÍÀ¯'švÁúÇ^õcŸê‰_M„5OºµO{tX¯n¬W?Æ6ŒõÆ ãHØülÈBEOœ¶N§p,.¤‡ñ Fð4Þ˱™ŸÂI3#[gF¶a—·ÏŒ¦PàwçìÕ]³È6õŸó»ðÆ+^ÆïüÿE¿¹+­êσV `/ -Z1˜·z0o ù]C~Ãú—‹üFÀVwQÌoOQDOQ$xE>”+F¹˜§@ìÁguéq]|^O9óåx'U®CÈ -Jx;ó4ì¦)ð•~›lŠFð›!¥!˶bJR—&­K•ÔÃÊ™áÍP7d‚\]“Mߥ«ÏÔÀ?©O“×îJ^‡„w„×§EÕg€_ekÎ¾ÇØ±×ܱÏB~-à×~-ÞƒßA‹¿Ø u—˜»KÍH¸Âíp©‘2 ”èKðõ³§Ë gaç«ÌÌï…J{Ùìeò‹·p,ãWýþ«ˆ÷«"¿ -Îï»Ê/ÞS~‰[`l‰_õµêë4?Õi®ÓýR¯û¥û ën6£ß[B¿vò‹#XðËF0l„@nÓ#…›w¡ß'à—Š»5O{€°v êÕ÷éYcP?ú}6hz„-CVÎïiô;‰ÅO 'N-ï—' ~/§@³8‚±Ù«;áP¿éx ŸÜÏàˤþžß_ÖÂbÂðOÒþßó»Š -ø]- hÕ@Þj/ùE­K*dÃW(7’ÕWÑ‹x!QO¡Ø_xÅ„WÜUÀx=¡xÝ -ò+ïÌ•Qòþ¾eš¼Ì¯º5+[²•M6ec–¼1CrëY8sEþ!©ÝKhY]º¢‡¯Ø6Úôœ_m}†º.U^“":±mÞ ëízâÙª–|]ûn£ü"á}fç>‹{¿ÅsÀÚuÐê=h%–n¨Ä„{J #H£ß¾bCЯñÌ!Èp®Òt¡ -B¿ѯürGXÕÊ+UrÞ¯ôÆa%ø½A½ÿ -#¬æG°ïÂzGñÅ» -ô‹„åßW|sBùíI ¬ -ú­Õü\§ýüÂo½ö×í¯Ú›MT³æV‹öV«öV›–CÚ;Ú»š»H Ýshî;µ8µ\º‡ný#6ão—ö±åŽQ4…‰p·üŽC@˜S¬ï×êŸ á"6(ô‹GXó72Þ”ÉûÍ\àüfRxÅ/|’±LŸÞ¥Ãƒø³ ŒÎŸ™ßE„—ñûÅ?â·7gUoÎÊÞœÂô8Ôb[cæz –¿¶¿`]_A˜ p.òÛDZ¨Þ¢È^Ä+¼Ý"_ÈËËíʇ$ž|†—óë*P@˜¶¹rVÞ•¡„ ¯=ÝúˆØóµmyš–lUs¶Šü*2ä ¦mmª¸v—¨fWˆkvIjSeuiòºt%hm´éšsMà·>K[—¡©MSÕì’Ü.:¾5üĶðS;¢pdgÈmª–<][‘ѾÇܱ×uî³:÷[]û­îýVÏ讃ÑރѾƒV±µ»$º»~-=Åæ^$lì-ÆúK ƒ%†Óe0yMÐÙ -#ú­d~õñ0øe„Á¯ -üŽVJG+$W+e×+o¼ôûþ«ZÚó~ß"¿ï(¾|üÊÁï×ÇäßW|{BùÝIHõý)øý ü"aÍ/P½æ×ÍÍFÍÍ&Ío˜úV‹æ÷VÀËÒܶknwªïtªïvªî9XêûNÍNͧæ¡KûÈc¤ôº4¼* Ìü>õ³ÔO»Õc‹ kÇûµãÚg@¦0ø¿1“C±“§cÁï$ø=ƒ~§Ñ0¦„g/ƒâm3£É³W’çÈïÜ5öð/Û ³SèŒù™(Ë -Æ)¦H1#¼¬ßÀ[°øhKcx_¹Çð.`$÷¯ù Å‹~ç¿¥¾ ©7{‘_ÄK½€q„Ño¶¦/møÍë… -0`+¬—muià††Ëf¡˜ðнà7_Äã%¿yw¾6¼ì|®|%ùÅè‰%¬–Û1¼õ±-üê: -ôíù:ôk¿ªÆ,€)'¼’š¢S;£aIMª¬6þ Š:Áè×Ü`Ó×ejkÓÕ5©ÊS;d'’EÇ’"Žm‹8¹CT Ò3 6us®®µÐØ¾Ç #¿Žý1.,Ú} Ús Æ{0 Gw—Ät—¯f1î)6ö4€bô[ÊüšÏV`ÿUÎïKè÷òaíhµj´Z1Z)­^­’_;¬ºñàÕ@ï¿¢¿´&¿o ßÏ™ßwå_½'ÿêˆì룲oË¿;¡ÀN*¾?¥ü±FõS­úgê—:õ¯õê›P£ä²n5«oÕÜ&¼¿·«nÛU·;Tw:U¿÷y¿8Õ\šG]zJ‡~»TÂÌV1ÂãaíxŸæY¿æÙ¤{6`x6`š°LÆ¢_$Œ~§8¿‰Ót-iúüúé g.nš¹´‰#|‰#L~·ÎŒn›Ý6wuûÜÕ8‚ñ7uîZ•>w-cþzƾ‘… ü~˜ÅOáô…—›¿Ÿ,ò›”Ëú|×snÍ -Þr¹Àûeñ„ÿ–ßÔùo— ýa~!½J@øEîP‹ó»†ü®£x¿…aKñöp[ÝÀn—%b~¯/_ì%¶ž<‘'OLIÜyRw^^ô xs9œßöÔ–£¦[µùúŽƒ½@ß’­n¶©›ljò«¨M“Á´…z2%êÄ.ðxr§¤fЊštUm¦¦Þ¦ƒj3µ5éêS©Š)ÒãÛDGÐoäÉ’š4Em†ª>Kݘ£m)0¶ï6Û÷XÚq -[ûo,ä>ë9Ûu0ûŠcºKâºKbq -ÃZú ¹û ‰ó‹GX†¡2£À¯ù·„¿†K‡ #/8¿‡É/Ž`ÙÎ/àÕB‹ü~ò†â³·B¿_£_é·ÇäßW@ߟPü€~•?ÕªoÀoÃb¿·Z”ÐïmªßÛ•úíúUÝwª¯SõÀ¥†e3æÑ<ô¨–øUŒScݪgÝÊñ5Ö«ïS?ëW¡ß~ÝÄ€aýš'­“C1SäwŠüNŸM˜‚†¦Î%’ß 37’_^ñÈ–Ù‘¤YÀ /'ÍŽn»J#vÁü f„篥ÏÃ*ú:)¾.\KÓvϲ#/£ßE‘ß…OÒþ ¿_þÛõó_óÛc[Ýc[Õc[ÉCæÆ1+0”~{óÖöæ¯cõ`@˜ -‡zX¡x» #º £ ÀÊYà—Ãë!¼è7OæÌ“C ðÊ;²åöly{¶¢Î©`«Ûš­j¥[ÛóÀ¯Ñ^`lÍÑ¢ß,UC†¶·äWr -ÀÂfv×Ébò+«IUàR9]Ukæ,-T“¡=•®>¹KyêR@O½Ê1XEïù•?ëÆÆ{\}Êg8‚µýú‰~Š“ƒ¦É!Ëä•ÇáÆ)?u.a:Ÿ8}¯Ÿ¹ˆ§/mä ³ñ–ÙѤ¹+Œðö™«)³×vð¯À‰ê÷ú5‘_cÀïHµ -üŽTÉG*°üªÐ/Öе$å¯É?z]~?{ “ßw™_É7GÉï å÷'?@§?Õ(ȯò—:Hñk½ü×ùÍF–’óÛ2™ß» -è^§üž+î;¸Q.â}èQ<ì’=ê’=öÊ/üúäã_ö¬[ú¬G:Ñ ÉÆ1òÛ§C¿}àWƒxP;1¨GƒÂ0…é,z8nê\üÔù*¾¸»Dãx„íˆ7Ï\F³W¶Í^Mž¹š<{u;ÞΚ»ÎJ†è]>Ñ¿ƒ¨pç<>NÈž(L_ÜÇiè÷ãT|ø“\œ\z.˜ ^€ K-û€ùÝñù]Åü"áì•=9«zràw üR°¨Î_”ÛÍ*X×]Ö]^@~ £¸Š"ý»£üEËú•°=o¯;Oî‚ÉK~;sd —ðJÛmÒ¶,ik–¼5KÁû¼ªæLukŽ®=ÖÏàWßœ­iàü*9¿;¥ÌlH»d§Rå°Õ…ù{*C}"CÃ"¿*ò+~7)’üJ‚~á¿¿ÐÔºðF·ï‰&¿qŽ ΃ ®ƒñîƒñžâø®’xo Ž % «hSw±ù õ;Ìû½tØ4ò’yä%øCOϪFª”äWâ÷¥¿ç÷û“àWô[£ø¥Vx©_Ö/lÕ¿Jò«ø•߇œò?\r!Þ‡]Rðû¤K†xѯlòKŸuKžõˆ'z%Ðx¯Fð³^òÛ~A±¶Ãƒª‰A56ã>c™: Y'ÏF#ásqÐÔyP?}qâü£âM3—7ÏŒn™Ý -„g®¢bzs]òìµm³×’Iî¶¹ø.îÛç?H™ÿµcîÃ]œâØsÁÔǬTî5ÑŸ°×q¤,|ºƒ -¼ˆ#e„RóË—òÏùõg­òg­d~»³Y+ºy¿=¼ßÞÜÕ½¹k ž¼u=ùX7« /V¸¨(®X<‹!_Ä—/úu‡ _߆VÎ4y/>4Ôœ¥€hø’ßlm[®¾-ÏОolÉÑ5d©ë2”µéŠšTù©E~wIA.%G•©ÊSi*0ËðOWOûý&¸‹Éo1` \"ð[LY%–ÞS™9à÷ŒÀïùjó…ÃæKè× Sãç¿«T—*#àWqµZ}äb0‚5kþ~wBÁ? Ë8¿Dø·¦àúùV¤ø½]ñ»]qÛ®¸cWÜ…:äÌï½€_·ódùcÀ/‡~%ã~ñ³î( <Þ Ix¿ZJC{aåÄ bb~aGlœ2Nœ6LœÑOž1Nžµ ás±ä—?uJ˜º˜8uqýô¥ 3¤xzdÓ4G8‰5{e+v•º¶uözÒìõ-³øÂ«$ò¶9|Îvˆžã“â0|Á»/½ã‹½Ôý“íÁ—R~òv¬èÀ‹~SþQ¿~_6†„)šÅ8”ÁoàÍ] ~»ó°ü0?ExCú-ˆòqá±3ÃëÏ¿ÒÅ~s¥Î\©# -úÅ•3áåü -jÊTµØ4-ÙÚ–mK®¾)[Ûð+¿'û•³–õ{,Uu|§âØvé‘­¢w¶D¼—yl»øä®?÷ëF¿ $çA±]Å1Þâß"¿¥–E~Ï¢_˹*Ë…ÃØÅ—,4‚Í#°®Ö1¿—É/WßÃÚëÕšë‡q û_º‘RIwA?ßï1ÜÿÒ´üû“òNɬ‘ÿT#ÿ¹Vðû+çWµÈï­6ùïíòÛvù -üÞí”݃²ûNø}€~å˜G -~Ÿx¤Oѯ üŽù¤ ï¸?êY·˜ü²ù+ŸèUÑ~•ÏúÏäÏeDX…„‡t§!5ž8cš€)< „™âØ©ó1¨˜'€_·ä!&~ì?é?õbc¾È1_ø˜?‚üJÆ»%c=xb’ Ižõ‹Æû%ãHx¦ðlò´bò´’ëp!}ÚSxò¬×ÒÃÑSç ÁÓ`/œ0„S1ƒŒ'Z¸Š¦)Û*Ÿ ~Wøx¿8‘sVûsYè—“›C_†77"¿‘~ÊWÀö¼‹üŠýyb®Ø—+îÊ{rDî1~s‚~@üfÉÚ³dm™ÒÅ~³`ò*3•ˆ7CQ›.«IC¶¸ff…œ\ñr—õ ;ßtõÑTå‘ò#)Ò#Ìïfß u½Mטgh)2·í±²áÛ~ã¡~=P „Y]¸ Žñ•DûK¬x/ùí+³–[‡EŸ®ˆ>S}¶²áóÕ_Ë¿°rÖ^áúùÃW™_…À¯ïßxOÆ]?ú~åA¿-²ß[e·Ûd€÷v»ôN»”üJîBâ{ñ}'ö‡Kür‹ï#·è±GôÈ#zêÅÆ|c¾0¡ßñî€_éDÝþ¨qŒüÀZ:1$’O)'‡Ô´ÖOœ6N¢_ÓÔYóÔ°•÷3}>næBüÌÅH@¶Ãf„Ñï(ú'¹sWwÌ_M™¿¶“¢ï"áÛ¡wÒ f©¥Ð’øÈï‚Ð/?‚¹> øMöYrÈþÇüve¬êÊ„Vvá^éµ­òÚàw… ¯ôüæ¬öå¬ÁÀ/“›³õt˜‹ðåEBäÁ.õë¥ËFÞ<Ä»ØoNÐ/àuؤ6©=KÚž)mË”´fIZ2%Í™2ðKÞ+^¼U#]^“f%ØÒÓfš¼'vÊ1¿§ÒØúý#¿ï_Øü&‹ß£ý/úÝN~35õÙ̯…üÆØ÷-òK•$z¸x¿±à—'lé!¿å1ä7æLeôœ¿œßsÕŒ°Ð¯úâ!ð+9´üù¿ÿU|ò&ÝÂñ–âËw”_½§øúˆâë£òoŽaè÷8ø•}R¶Ä¯,Ô¯üV³œ÷+½Ý&¼·Û%wìÀ{§CtêÝsˆî9E÷¢?œQ¸D\"Àê7JèwÁüÃ…´d¼&¯d¢ðÂü•Ž÷ËÆdÏÈïÄ|bH91¨žÒNé'‡ “HØ8„‡-áóÑÓçcf.Ä.!¼~&„ð&XEÏ&Í‚ßdj;úeÁ¾ž²Ý€ØGÍR°q~·SÉ Í/Xþx;µˆ0k[0nÍâ/B -½‘r‡ðvsø]Ür~=+=„Ë"¿Yœ_$œ½Ò—­ò¡_Öš ^ô‹“—ðr~!îæüŠÙ5#¨ ÊùrYKýJœÙ‡ ë´I:²ÄöLq&iË‚ù+nÎÒÛod Þ'™xe$Wü|¼!~O¤ÊO¦¡_¾*Ä›¦:š¦<²Kó÷½dÉ»[Eoo‰xgkÄ‘1ü›Áoùm*²´înÛcßÛq0ÁYœè*Yï*^ï.^ï)Ùà.Yïø-Mð–ÆûJq{‘°Õ_bú­ˆ>]sº -~­g*q xÏUs§Ð¿—*5Êåʤ—É®T©®^rýèUåä—náP~þ–êËwÔ_½«úú=%þæ¨"Ô¯ô‡S2¡ß_ê!é¯ ²›P£ì·&Ù­fàåýJ°vÉm»øŽ]t‡ðÞuDA÷ gä}gäÎȇ®ÈGž¨ÇÔÓ®¨§Þ×ÏŽ±³è>P,¢_ð+ǰœdÁü%¿:"¬Ÿ=ªÏÅáÍC¶„WäÎŽra"W6ùÍ‘8rÈo6à%¿áP¿øl  ðÖ†ú=¾C,HÂË•t|—ìdª‚;¹JמÈÔÏÐ!á _1ù<ëç4Em¶¾)ßܼÛÚ²7ºu_lÛþ8ðkg~‹×;é»K¡D*ÁS„ã‘0byK¬^|¨ÐÒ[fí/¬ˆªÂèw¨Â|7¿VòkD¿x–ñòaý¥JåÅC² å!~¯?×/n¿€-ð;ì oþæ˜ôÛã’oOH¾;)þþøÿX#ù “þ\+]ê÷7ðÛ,ý­Y|«E| ýÞHÌEÜ鈸ۉÝs`÷á8ú ˆðë{è {ì {Ôö¤+ì©7ü),¡ñ‹²º# /&¸ÌüÊ~9¸Â*\KŸVÑq´fò¬nr맆 SçŒÓçMÓ,Ó¬Á.FO_Œ™¾ÅB3#q3# ³—¡¹Ñõ¬ù+ 9jþêÆùkÐ&Œ>GHmXïo¡oŒò}È5¿[>b%-|¼•/‰+„°pÿ#~é+!GÆ -Gx%)~‘¯Àð* ðÚV{lkºxùº¸ÈoN„/'¿þ<‘Ÿ7Œ›¼àubè׉~ñúï"¿ù‹/áбÇëÒdxŸ•ÐïNq°çù…%ô.ð«>‘®9‘¡;™e8‘©?–®=šªz/Eñ^²ìÝ­’w’¢ÞMŠ:²]r"MY—cj*ŒnÙÓº—á‡ì:&: ô›øg~£°¿ÔÚSÝ(fà¹~M/6Ѓ„ºK• -ð{ñ¯ú•}ö–ô‹w¤_¾#ùò]ñWG$_sLüíñ¨oOˆ¾;)úþ”è‡ð+þ “,õ{ü6^Éo-¢[P«ˆÃ‹~#„~ï:Âï9Ây¿ë ð+ð‹óüâÂaãþðñžÈ@Ï8Åèw BÂØ³ZB‚í°œ;”>« -6¬ž:§™:o˜:oœºÀÎæé‹ì’uæR4×Ú….Ç›»]MÄ®%Î]_ÍC76,`ÞÇO‹ÎS컄ü× ƒ-|´…J -öIRpþ²ð?ëw#LŠWº2W¹2áwäÌ‚A¼Âm[ yl«<ˆw©ßuPåÁ)á͉d^™e<–¡;"ðûv’è­"ò«ªÏ³4Å´ì‰kÝ×¶?¡ý@"Ôqp=Ô‰ów=¬¢äוA‰P#L’|¥1¾Òhi4ç÷PÌ úÁõ3ì«,Ãxxe>˜üVë/Uã-п#‡äÓ¯d9¿â¿é—áÀ¯=üNGøÝÎðçù}ä^÷гîQöÄ»ñ¯oݘoݸ?l¼;|¼'âi7YàW2õKaÿK[`Ùì‚9¹²@“§å“gÁÎ*§†UDXKé§.è§/§/š°Kfhæ’…²±ÎŽDc—©ÑÖÜ•ØÙ«ØÜµ8Öüõøù ï'blÀð£À—ï# ¼™WL¡ß-óŸÐŒð?é·“ÇËüre®pd¾È^‰ ý®£Â»ø<9,ðëËò劼¼ø´ ±uçD¹r1gn”#WäÌ;s%LÊž\èÀOŸÈÚéMìøM1›¬9KÒ˜)iÈÔgHëÒ±Útt*-è74 JZE÷&SWc3Ôf›js-§l&ðû^ªúÝŠw·ËÞÝ&}g«øÈvé±Tå©,}C¾µywlË^æ7ýL´ƒßbð»Á ‘_Îß  ¯G¿e0‚c!òã/‹î)‹î+Âl =H~Ïð~Ùâ™üj/U©˜_¾#¼ßÃjŒÓëìøógný,ûâm~WÊAúú¨„K¾;ëg)í%l ~‰ð¯Œ0ú•’_ño-‘· ß;8|~ÃïAŽu÷ë81ßµ¡®µäZûÔ·vÌ¿fÌÏ~JŠ¡g½´œîëõƒ_Éø@È…`JÒiÙä9×YÅä°rêœ;¯Á.h§‘°a -#dÞ¯yšÿåË:s™µÎŽFcW¢g¯B1³×bæ®äØùqó7â±÷>HXø0Qøuoú—‰Á„?Þ,ä²x¿‚kIÿu¿Ž´é+œÅNø—/Bl -»2yÂØª€ß.ÎoxÀ¯‹€È/îÂp/7s,Ì\åÈ9óÅÎ| }«WFÉJþ“ -ª¶\%÷n:›¼1KZŸ)©Ï”ÖeHk1Ym†üTºüdšìfíbÉøß@ò;!ÅÉTàmÌ1Ìú<ëb¿)òw’¥ooߥ¬E¼–Æ‚è€ßÖýñm˜_"¼¡“Ÿ¿®Ò .Û@~q{Ëâ~cºËbzÉ/,¡*¬°~õx~ù½T!§û'™_õu>|–?ª¢ø€»þ«üŒú<¸æþ†vÁß`×d?büþýJ~©—aéÍFð+!¿· ÖˆßÛ±Ûíá·íØŽ°;aw;Ãîu®¿Â]k!6’ßG —Åù…¸U´À/Õ5Öb1¦{±¤üµ$H,H: |V1~‡ÕŒðôyÍ4ó‹¦/gЯyùF,³—±ýb3W è Œ~±ù±TÜüûñä7A`6qþÃGø£¡~7/|²ý~ºÈïöÿØïü¿™¿i+a–Ðo°,Ädy¥;G°Ç¶Ö“µÆ“µÖc sÛ¹„Iq$SEyr1^1ÌÜÎ\‘#Oì*”ºŠdî"¹»HÁ½›}·ÚµGëÜ£sìÖuiÛ 4mùêÖÃâw-ù…Ö<îZóÈ»æ‰wõ"¿O»¹˜bh¬7òi_@qÔø€h<@xP<1(â:#Ÿ‚É‹xU€wú…xõ3 ”q†ðÎ^4Ï^2ÏÕ‘ÀÌ嚽̙ŮXiìòÁä½;=Ž ß…÷Y Ký†F~q Íð2¹¼Èïü¿t#Çò¯Ãzž_F˜Wü¢0g:úÅ£- »cgæjwæwÖ7þŠÃ —â×-ðÀë‚›'fx…RÏ^e×~µï Î_lb¯pô[ð‚K±µë Å}ÀìØgìØ­o/Զ櫚s6y}–¬> ~õYÊz› -×aÄ4‹)’+„ÌΜOÁÊ9CWg34æZ–õû^ŠüÝíÒ·“~­…1Í{‚~Û/E#vÁ<^ô[ð›ðëÃÈo9úíåýVXOWYÏV[ù½X¥½X©äý*ØóGâ÷-ÃûùÛ¸Šþ’Aã]X°„–ÐZÊ]þ+~‘0â%¿aœßö°;ö°»Ký"a<Âò„q# ¯ZÖï“¥~aaò;~ƒSþÐMY ¯bêŒrê¬jê¬zjX3}NËš9¯#¶&Ž-ë’C¿V+hn4šËæ¹+1sWùpÙ;_¶ùÅØþ—/dýÚR¿‡úÅ”’ŸwG´àFŽ¡„—ø]´•,"üâ¢h"cî2Ó*WÆê@9s-äÊZ»Äo$F׉‚“—ð¢_ø-¹÷(½ ·ÔØ{(º¿2¾¿2¡¿2ê£z*|åqž’×A‹cŸ©½HÛ’§jÊQ4Øä 6øU6d«À¯ ýÖdÊ‘p†‚#Lxñ:oª‚ݰq2My*]U“ŽÃ·>Û¸hþgçW;äGSd°ó}/Y›ß›¾±ÀÚTôÛÆ_nþÒfÃ×]¶ò”mì*ßÈN±˜__Yœ¿<ê.E¼8c9¿•ѧ«¢Áï¹ÃÖó‡~ äϯFðùAô‹ëg \­º~XêW.ð«âüâl¹#¬oŽ‹ñ ¶À'i ¼Œ_I¨ß¨ßš£ØZ8ï´‡ÝåýþÑÉü†ñ—ÖÑ%¤ð‡î0Ä8‚ÿŽß(_ö8Cp!‡W§¯jêŒzêŒfê¬nzØ0}Î0sžB¼æ™ –Ù‹‚.Yç.Y oô¢æGcæ-WìÜUVáM Ö/pçÏðüùý ØÏ?¿Â#¬P¿ üâA4»k‰ßÏ—»ë+A‹ / ¥=u%‹'R`kÌmß5˜_",ôÉG—wñ´Š©òÄŽ<‰ƒ¾däÙ«öÔw—[{+b¯?ýÊæ¡W¶ ½’ Âï«[_Mê;¼©»r½÷P¼§4¦sŸ±­PÛœ§j„)œ£lÌVA@¸Î†xk2e5²SòÅ~ñ>I”KÁðÕÖeéê³ °ÿͳð~'ÒµGw©`ø‚ߣ)Rvò\c:à—_-ò[ôë!¼Ìo—`ÿËù-¼±½å±}‡âúÅ Týý²ç —ªuø9•*ÕåJ%à%¿Ê«ÕÊkÔu|– -þ}EþákòÙþ—ü~‹géìú=1ú=õíqÀ‹~8)ÁÍï)ÉÏ¿µ L~±›àW|³‰ùü¶ÀúÅ]ðöð»öð{á÷;Â0G8ùÅ[8€ðwDÀï#wÐïS?6ÆŸ_=a„{"žöF ÜÞ¨§xŠÅmǸS,Y€0wø|ZIxuSgôSg ÓÃÆésÆ™óÆY6y/Xf.DÏ^Äf.Z!òÍŸ6Ç›E¹,‹áU¤yvñè:]9º±iá}wéßúÝô\¿ÓâOžã—?ÑÞ½ÌÛ)C_'»h -üÚq -¯` ü®d‘âUàב±Ú‘±–~ÁÑF8Âm‹ô^xEöákÒ_—}ú†ü³7å¸óÅd_¾-ùòéWïJ¾ÂG€°ø»ã¢ïÁï ñ'ÅäWÂðþÊðÖKn6P’ßÅ¿5‰n5c¿·ˆ~o¼Ýq» øeýÑ ~#x¿ÜXŒ0¬¢Ù)ÖcòûÄ¿ü6¿Oiìâá3âCShv!‰ž%Äë¿“ìBÒiÅäÕ$L^Â;uÖ8=l𯻰L„†¯uæBÌÌE(š5‹xc‚q×|É/¦8ÂB¿ø˜ßÍt ÇfNñLñ¦ç´™³Y¼)xðò˜{F)…óŽãÏ]Qs‹jÞ¯ öÔ•,Á©+q~iw ÑebÖê@‹¦° ÷Âáž,æ7Êð›Ë5; -¤®=JÀ‹c·2~à¥õC¯mzc+Ê}gûÀ;ÛûßIî{'¹÷ím½omëy3©çõ-=¯lê~iƒ¯*Ñ]ã@ÂÆ¶½ú–"ms¾¦)«ruÙòÚ,‹'¬8~3”uYê†l]C¶ž®e~‰pM_›m¿uY†š4ÍÉJÄ›‚w}Ðm“ºmÒÒ¼;ïÜà/ ñ:‹70¼ìØ -ðv!Þ ¾òõ¾òD_Y‚óÃùÅesü`eüPeÜPEìéʘ³Ìo•å"ïw¤Ú4Rm¸\­­ÒŒV©G+UW*UÌïuð[¥¸Q­|?êM~_•|üšôÓ×eŸ½!ûüMôû%ú•B_½#ýú=$Œ~ñ~Oˆ:)þù”ø—ɯœ_ñMˆüþÖ@~Å·šÄ¿7‹o·@Q·p[$ù¸k¸×Áûxà [ ñ.èºüF>ô„ã.¸kÝ#ߺÇþuO¸Â„‡W„WÌð>¼«Àt Þ…5¤¤ •€w‚nÞ€eóÔÙ€_3ù5óÃ7à7&pç†À¯àž $Ì]üøe·p¬Ÿ¿¶oãüõMÞ‘Åâø€êòmâ×Ҽ߄~áí‹ ‡Ìâ¥ïØÙÉ2ˆCjÛµ‚eOÅ:w½( ü®^Ô’UtÐo—óË]'B¿b6yýe–þêÄ¡W6ycëÙ·¶Ÿ~{û ÊÝŽrßIîy{›ïÍ-Ø›}¯nò½¼ÁûÒz_ubWe¼»<ÖYjµ0µîÑÁ&¿Jð[Ÿ-¯Ë–ÕÙdµ66…¹0ì‹ëmšF£9†ú,]m¦¦Žá ¦œe¨MӜڡ8¾]r<Ù]kÓÔ益BüÚ†øu”lt•b¸ó…e3Ã{hƒÿÐzy¢_à·›÷KxÑ/à=SE~«Ðïù*ÎïåæËÕÆÑjý•jÝ•*5âÅ„~à÷ƒW2¿¯J>}]Êù}“ùÅÈ/þö¨ýg~E?A'E?׈~©ÿZ'þµ^~cx$·¡¿è7zàˆzèŒz(xü†ñ~ÃXà÷‰`ó˜¼4| o_/»‹r’' ×άtSÃ̯Ÿ¿f¶ó%¿Ñ„7fúRô4wçUà¶+`ÇÇæüÆ‘_Ä;w•ØRsÐÕ ,äŒ7bü -µò“÷?÷x@iéŽXðŒa€ð²~w¾ÈjÂvç ‚„Ó— Órz5-¤×-" ¹²#qþæE9ó%®"¹ð–š{áÿ{_Þtæõ­gßL>Ãü¾½½ŸÍÜ7’|¯mò¼²ÁóꆮW7v½¼¡ë¥õ]‡»ª=U ]HØQln#¿H8_ݘ„åõà7[Zk“2¿ìDº¨Á¯¿`¶Á¦DKh#ïW{j‡òl{ѯädšŒüâ3G-{è¶çÿÔ¯¿4®»,¯¡ßØùVÂʆ/.žÿ›~ß¿2hY¿ß‹úá¸úñDÔO'¢~>~¹~­ÿ-¿ò†ÿg~ƒ÷B³õsˆ_ FÅt~eœ>oœÆÛ&éÎÉót/ôE>n -ÇPx/ô,KkéèP¿ñ„—ùÝÄšƒ®näÑÜZšú€˜ÅÓïâç…±ùå_Ö‘²Ìþ÷~¹^fŒàeâWÔl -á0O&úuQÎìHgN¤3_ìÞ-ïÚ¯ö—™é´*ñô«[μ± ‚ÞÄm/ìvaµìe#€uUÇ»ªÜX¼»Š‚á[穈óŠu–Xa# „[‹´-ê¦Î°9¤ë›Ï5„úÝÒ‡¡ù¹ûßm¡üü.º´„ãxî‹í‚CéÒoZp -‡øÍŒpeF8³"¶GN¤«HÚµ_å+Ñ÷TD÷N|eÃé×¶œ~=ièõ­¯& ¼–Ôÿê–^Úç✭ˆsŠææ¼»4ÚqÀdß§o+Ò¶¨›óTM¹ŠÆyC¶ ×ÛdÜ¥aº:ôk ñÛxƒ~u麚ªS)²S;¤øâÊtø_MCýîcÏ 7¿Ìo`øÒ™ó&ï!h£÷Pˆ_ó~{Áï¡è€ß¡Jëßò{ð†ø•ãþ÷•?÷ûÍ1øýö(ø…Œ¡ß“à7*à—VÎRj¿wÚ Îï}{àü*‚÷ »`Ž0=È~£y#ùÂC~ì‰?âI7ö”=ˆØü2¿¡xCüžQMž]êW‹„Ïñù…óˆ—{~á‚eŠ{ G0>Žâ ã Æ…tÂÜ({.‰­“aÔn"¶[æ¯c ì¹B|¢0‰?ÅÎßçà6q~Ù-”â7™ün<æ%Ï‘¼€„·Ï™rýoý¶íx¡}Ç öÿ‚„~;w­´ŒåàZzøõü:ÀovDgn”{¯¼ë ÆWní{)¡ÿ• ƒ¯n|mËÀ«[ú€mu¢·"®«<ò”ŸˢA(ä*µºJ(ø£,òŠé -øÝ«o+Ԁߖ<º¯#[Þ`“6Ø$twç·!¿{ÒD~qÁlÓðÒ¦ñþe¿qaTœH·mlà†oM^ÂK~×û%úËüå oœàÊo wå¨Â:TaÅ÷oüýõóõj~Nôeù/K>|Eü§~ñëù=ÆŠøáx$ù…]0üFþ;¿­â;mQwÚ#)|Šá.†‚‘pG(aÎ/~Ø«èˆÇ¾¨Çþ¨'þÈ'Ý"èi·x¼áë•,^??oþ.ç7Âç ÷Ò9¦Øæ§2øÁ¯|¬Gþêåñö1¼ªgƒZþ”ú‰3þ-²ô"Ù³Ö©aîE²Áð²À6añ‹ìF6Þ‹E3w3µ…EoǾQçïúÝò\¿þë~—<ê÷…¶@;`Gü'x™_û®ÕPGꪎÔ5Œ0àud†9³#Ý’®} -o‰ÖÈÜSÝ[Û[×Wß~+b}e÷~@ªuìÖ8wëœE:g¡6£@Ó j: -5öBM{‘ƾGÛ±O×¶GÛRËf9> ~m†(PC†¤!C -Š3e˜MÙ”­iÊÕ·ä[ Í|–Ö¢è–B"œgjÊ14“߆4eCš_«•©lÌÓ6[÷Y:Šã:K¥ëYä7þ`Ã×/¼ZÏn˜d÷\ùÊü¥A¿xÏ$î|qøð~y¿g«ÌÃôæ:òk¡á{ù°žüªÉ¯‚ü*~å7ËßYöÁËbôûù}üBÒ/Þ’r÷o¼+¿ßüþpŒù¥õ3þâ·Qò{³ì÷&ø•Ün¡~ï¶‹îÛ! ~ ¯èäàð>p‰y¿RÖc¯ô1â•c~ù8E~O9ÂL±ìiF~•„W?1d˜8mį0` ×ÊÍ×,Pÿ:èõøE•‘M,¢º‰½Înö2.˜xç.³WS&ÑÛí’Bý&¢#¬PÂÿ¿ñXK ü¾Ð*ˆù !¼kÙVÚSW³:ÒÖ@éè·3Ô¯¯Ü„¡îCÖžCѽ±þ2‹ç€ÞQ¤´çÉì¹òŽ+óë*K ‰{Õ½íŠ^ØîåßK7lß’˜žÒè^|ç.žûÊÍýå´x.7_À{¦Â„ß/ãüš.U/UFªõ—«uB¿ÞÃàU Þ—8¿¼õá«Q¿.úä ñ§oŠ?KòÅÛ|~ýJ¾~Wüõ»¢oD}G‡Ï°lF¿'aøFþ\ÉŸoÖGÝlÂQ¿5€_1á.ž[i ?: ñýNñ®‡N|‘û#¾bü -~H”ùÅ?XÂè÷i·œÃÛ£ë 6Ž_4Ó2¿“C¦ÉÓø9ÂÉÞaü¢(7|ϱ/Š&Rë§/l¼Ó!ŸùÞD³x#óK[]|—ìÜèV슰$ú?¡ß9n^P¹•ŸÅèwîÆ"¿-pÀ/]Ez¾ßO®p_MÂë¿<á­!¡âm|Â|_3Å;š’ÿÅjÞþ\K‡øÝñbðJS ]« ö]Ì/à]Û‘¾ŽáE¿9œ__±–Øêº¨ Ï~µ{ÒQ(ïÈ•´Ù¢Z3#[³Dv›´3GîÈU;ó´Î|#_×™¯ËöU{¶‚>^&ã“·âçD%ÌoK¦¨9# -ƒ?èYM™°¨–7eÉ›lŠ–Ukž®­À`ßm¶ƒÙ}\öýÑû£í{-­…Fø7´Ø4Í™¸x†3Yªæ<æ×â(¿ñ®²„JÜÿ¶X/úeÛÞRÂËùE¼äׄxËMCåÆÓ‡Œg*ŒÃìûÝôðà2~«ÿ’ßЯèÓ7EŸ¿-ùýŠÉ/à ßc ¯Àoä/u‘¿Ös-ã·íy~‘ð¿õ+äU<Ïï¸_õ´›Í_l¬Wh¼_ól@÷lPÿ ‡¯üÒðe“7šðÆO²áËæï"¿ø•Í|›(ü¨ -½ š÷{eë’pÍ`ÁüÅ%ý5¿lyîü%ÂóoÅ>Ù†r?ÝF% Â%ôüg[ç?Ob-`¡xY‹SÉÿb‘Üøåô -TkÊ‹!í€V¶íXÁµü®nC¿kì of¸ƒ]9²E8sEž"©o¿Ê~‹µÞj÷^¹k·ÌY(íÌ“täŠíÙ¢¶¬Èö¬(»MâÈ‘;óTî|§Ð¹ ®½#g«ÚlŠVþ+„­ø9üï C0Ä[iEÝÂ}æ[Ñš o½@ß±ÛÔ±×Ò fðŒé<Ó–‹ŒmùºÖl5ømL—cŠ&ïw?ø%¿,æ7ÞUï¦<¥ñ¿ô´lôkí+³ -ñ–™ß³Æs•&ò‹o¾¼—ªõ#Õ:Îïa•À¯‚á}žß~?ø¥Å3ž\@¿´ó ú­ ú½ÙÀÍ_:¹Axçì|ŸëWú‡Cò'~½ -øƒEx•ÐS¿j¼[ ¿O{¸ÆzÕ\}êñ~-ù5<2M ^+v6fb8z‚¾¼ßó “äwêÂú© Øð%°›ø¥+ö]$îëHIÜð½(éù~·Ì±·ËrËæçàP¼ÔüGä÷cÎïÜ’ˆðÖùÏ’ø¶òËiÞ?÷ûÂÒZ¶¿¸„0ø]ŵsuÛÎ5P{êZ{L^‰÷\ÞœHw¾¸k·¼û€Æ@Š={äÎIgž¨#;Òn Ö™-väÊ\y*OÎ[dôí6ûö˜½»Mž"#vr„•í6E[–¼÷ÛÊü‚Ù, °…Ú²¥ø²;LÑ–kle{®º£@×Ydtì1;`%| ÌvcűޒØÎ0‚Míú¶Mk–²)]Ö”NßWÊVµäkÛö;ÀúüÆ1¿Î²ç2~ã—ñ[Æùí+E¿€·¿Ì8Pf$¼†ÓÐ!ÃÙ -ùJãEúx÷ÅÃzsŽŽüjG«É¯âJ•üZµü¿à÷hÄ¡~áýÞäÏ”ç/¿x¾Ãm{e‹üÞïd~±‡N ï7¿»À¯"¼*è©_ý¿šñ>Íx? ß ß ýÆbø-oô;yð&B„—ó;!Ø-‚6ã§E)ú4á>ÄË>p&œ¼ÕïûK ί>\Œ÷¯ùMæF0á¥-º‹ëÏý®X^,€Wàמ -Ã&o¤ÓÉîyvåFy -$¾=ŠžZÿ>•wÜ]+äH{Vx[ƺ¶Œ°ö¬ˆÄ+ræJ]yJÂkðï1wïµú÷Yp×n£»Àà‚µt®¦#Ge·)Û³í™ìsfœ_†ضçÈX°/nG¹*¨VàEzÇ£c¯¹V¬Îd˕Β˜Îý–Ž"c;ìv³”ͲætüÄøm-еï5u -ü‚\wùßñ[Æùí/3^òk,7 •ëÁïò{üV^;©C¿‡µ—«Gïaå•jù•*ÙµjÙ?ã7Jè—ÅüÂâùøE¼`VöG å>è”@ÈÖ!{ˆ¿èzä’Ç/áN˜<ÇüÞÐn~7M_¤5ó°}Ž_ú¨hhìKÁ›!_BÞð˦û*ƒSxKH2³Âx¿o›û„ZÞo°¿áwÛ¿¨ÿÃþ—àDK0……#8E0‚‰0®ŸÓÃ:2":ñžg¾]ùRoÌ“/¶ø…ß‘n&ü{ ðŽÌÈŽ¬ÈN[øuåÊ» -5ˆwŸ¥{¯Å¿Çêßkõâü5ÁFØ•Ïù ¶a› ز¯²#OÑ™§èÈSa$WÎ…:æ·sø5£ßÒ8`ÛUµÑwx³¯r#\ì7öÎÊ–u{‘¡þ#9òL®§<âþ.£ï,”Å{1öžXzÔ—žV ¿ÖÞ2Kâ ñ‹'W´ù®$¿U€×ô[­½\ý·ý²ó«ÏðZüg~#~:ôKloR‹çoó»øäù~']<ÂËFè÷‘SúÐ¥xèR>†Ü*ò«zyáà âeý>ãü'`ñâ7–ó;¼¬ßMS6M_àðN_NÂ_¶~ ®Ÿ§ÙGEG·,׿@³W–úݲÈ/þÿÈ»ë隷}ñÿÿÍ=§Åcc±ñ‰gf¢HÛS(-ÅqÜ­H±R .™‰+^(Ü%„àRh k}_¯×Þï÷¼GBéiϹŸ»¾k=WV ½çþôèkïý¶©#' )#£^ÆÏ¬8;ÅŽ°>>= û[ýîþlÜîÏÆ@@øßòK„gø–~í_#un~Á,ø…` -WÏV`àúÐ4¦e³¿µ t¶TS=n~# ØüÖ-ÄÉ[=ßX5__9OW9«˜£-Ÿ­`;\67ä–Ï ­˜¯e׋…«Æ† - U.4U¦†U ßˆò ô `mʼn ‹“—LiX” =ýî›­Ý?ßPšKëÊœð[ãá—áüÒK&é=Ïä7†üF7DÙó#ù°óh¡Å³W¿½‹ Àûïû=ýÑ~¯o‘ߨ*g„E¿ww+ù),¤¿°ÿ¥-p„p øe“ñV²c+ð -xŸÕèX/juÏëtäWû×üF¿é0¿†Ð¯åu§õ ÈíŠÇºFóûö Ä¯Ëþ—}ؽwƯG“‡O${œHOq_N3Âÿy¿ž„?Úï$ô;“`Y>×ÌSÕ·±«¬œEÏ2|À«KR¿saý\“‚ûßÚ&,«¹óôŒ­øåÍU—Cxׇº"ESµ@·l¥²Œ•0s…U¦¡ßŠŒH ZWß°(©iÉ”¦eSá§­8¡*'¦"-¢l¾qÿlíÞYjP¼Ž¬áÿ$+º*7ýÂ>¨ÆÃÿ9üäJÞëÄÛT(âräãðmü¶zŸ¿a}‚߃Þï©¿èw—R¼„$ñ‹7oÐýN¿lóËϬ°@¶r¦á«%¼úµóûÜÆB³´xÖ‹gÝ+Ø7é^òcg¯‹ß(òk^w"Þ×qoo~»íA¼R¿oxøåW‘Å'»ô§üþ䩨»ßÂÿQ¿»¦Û5m Äý~6Åï^Šm]šá³—Ðþe0agq¿üóF¯Å7þN¿€÷[eÅlúìž_©kRt5óuÕóôÕó 5ó ðK˜3Js5óÔlÍ\™¢«Z¨¯N5V§±LUXäJ8²*;ÚV߸(Ù¾dŠcÙ4øY_œXËü–ÎÑ^¾¥sõe ÃÀ/žwåÆVç™qŸ[ˆ~m…è—Éå -°xÙØÅç|ílåœÏVΑÎá[À7¿‚ß°Þ’0òk<°ÈtP8|öæ7TÄK~CN, D¿Ë½û=¿>Л_9ù•ÝØ&ýŠx%~ÙÍWÁЃýÁÎù‹×ŒBžV†>[J'W¸í¼Ï«ï³ÃóZóûܦ“ú•ž_½jÔcMnÇVF~åýF¾n‹zÝû¦ÝòÆ.áuõ›èæ ÷‘_§ÜÉ.~Ù®~ñvJd›,&Ý;ñºQ¹Ð€Ša§‡WgEº†â„¦EÉŽ%“›'5Ç׿™á•ÆwŽñÎÕÁï Má•YQ5¹1¸ÃÅGéÁ@z<¡äæY0sC{7[3Gãsat3à-»%E¿ìØ™nÛˆ áÖ]lê)1õ–˜úJŒÜï¢?ôB~ƒ^Œ/àýÏÊÓ+/LÞsk!Õ¹uÊþõÊþ ª U—6ª.ãÍWrºCÆñn ¸¹Õÿæ6ÿ[ÛîìÝÛ)Ø%¿·[~ïÄ{ïß¾¿ -¿ƒûC”†<(ƒÀoÈ£ÊÇ•¡+Õ«ÔO :¶zZ­{ŠxÏj/ëLÏëŒÏm†g6ý3›¢•3üÔÞˆ×ðªÉøÊn|iG¹¯šÐ/- kÅ‹G¿´2¿°xŽÓI±±Ëð -½ÃF/cIo,±¥à.wT¾ÃD¿Éxw4²M>’ì™äéB·”èí”îMÆNH.31§¦`a'ç3S‡ËN¿ý˜0vÑïH?Æÿxá é ¿;¿Hø³ñ°#vó»÷ çâÍ‚Üé>0sYû¿6¿ôÎjæ×^U!a¥¬úV…rçCÕsÈïÜP¨rv0T5,kk©oUÏÓVÍ×TÍWW¥¨+æWÌ©\¨©I7Öf†Õr¿FØW.ԣ߸#®J5UßÌHˆ+Œk*I´/N‚Ÿ E° ¿aå)z”;OW1þOŒð/WeEÖäFÃ?­/ŒÃ÷iრìÙ"’ÛˆÅ6æÅðû¬ò^ºÉÙ¾ámì²ùÅ•3ù¼½Åè÷€«ßÃòÌüž$¿§¸ß@îwêÜzå9ô«¼°Qqq“âò&ù•ïäW7Ë®m¸Nxolñ»¹Õïæ6¿ÛÛýï츷3``— üÞÿA1°ýì †îï ¹Ïý†>(ƒB†Ðo(~5a×@Ú§5ú§ˆ×=¿6Ó3›ñ®×Sºç ú<ÃËFãKæ×a|‰xM¯PnÈ¥Ÿ€7‚üƾn·þŠ~¥r“(‰bðÛø[âe?ñFJPÜKr©w}É.qÂøð0{„ŸãMÄ7rIòHxÀ_|LXâׯ@X:ˆé¦¬‘““™ß‘ÓS¤‘_Ìé·šÄ/½E‡ùur ”_ñþ îwºè×wßW¾ûgúÁä¼exU¯ÿzøå#¸z@&¼³«iì²`øÖR0‚kæijçkë$Õº†ËlVŠºz¦ -?V¨®JÕÖfj³Âj³ð9âê cUš®b¡üV1¿i¦ê´°šŒ[nLC¥©8Þ¾(¡±HZëòb*ÓL)úòù:øYµáð¿Y›m+0pø×Xð{C¡µ1ßÒ˜™›òb›oÉÅèR‘ø„‚ß‚0Áoßù‡õˆ~‹E¿¾è÷ÈüÂÎwi Óï -ÕÙUøðø=Ëý*ú7È/l”_Ü$¿´Ivå;ÙÕÍ×6û_ßâwó½µÕ÷æ6ßÛÛýîßþ÷vúßÛ-só;~÷‡Þ/ ¼åØPEèÃJ5à}T¥yD~×hŸÔèžÖžÖ Þgu‚ßzã³zðkxÞ€½h„Œ,æ÷¥Ãô²#¿Œm¸à7ã~¥3—áM–þ­;é7ðK„ëI€~ïu*þ+NfIüR“†%aŽ—ü2‰.~Ý â î’½`w¿“Éïd‰\6‚Ýü -¹ÌßÏG\æ¯ aèoñ‹ÇγäßâýWÕ®xùÆKHàvÄA5sƒkç©kçkêX)ZÛHWŸjà-„ô,ø{ü )d9Òau5ü²@„«â' ë²ÂêÐ/Ì_Su†üÂü­ZH~ÂÖØT“^›Q—YC³ÐÚT SÕZ—[Y‘j(OÉ«­Z ¯M¯ÏŽ‚_ Qlm*‰oZ”ÐDcj,²6Zš€¾Åžo¶çÇ:ðö*ºC2?Ò‘á(ˆÞäÌÃc+Ýs…áη(Ì›_ó{x‘îÈûUáây™Ò»ß Šþ² €÷;æ7àêfÁ¯ï->7·ùÜüÞçÎv_ÂëÝA´„f~ ï`)%ø}@~VAè÷Qµ–üêÑo­é)ù}Vþ¬>ìY#lD¿€ÀÚMÎoØK’ËB¶má¯<üÒð•âý€ßW¿ÎÜñ‡ü&ÜÄaöËQÎÙÝ/¾,‹¿)zä'|Ó»÷)ÌßúޝÙNbç&sÅ‚_$<…¦½ðÔaÁ/3ë–ӯпå—VÎ^ˆð®V)ÅKTÕÎ ÄŸság`ݼÛüP[ІeÕ/¹úÆ4ƒ=3ÌžnÏ oJ75¦áo †T'äº̯ý.ÐÔ¥ëkÓtµéúºLƒ-ÛT— ~a ld~«RÉ/MjÓMµáuYáè77_KUdµåÇÖæFUe…•/ÔÑQ¶¤×gEâsf´cq¢ûo‚YŒ~A®Å‘ovp¿^~—?^$FÇVÆöBø5ñÍ/ù¼è·Äp°D¨Dwh‘îð"í‘ÅZO¿ ïñ%Atråî—ÖϸùÅ\ü\á»Åñn…|ol•øE¼¾ä×ï.¬¢PüxŸO^«,Sc塃Ìo•úQµæa5àe~uà÷I­ñImØS[ñÜñ¼>âYCØó3—ã {åwÖþ²òÉÛ!r£~¡Ã«×q‚_)Þÿ‚ߧߣ¢_×þÀoÒ{—W¾ƒß$Á/6ºß©ÿ%¿3ØðåxɯðVÍVUÄ•úfƒ¨`ÛüúuÃMý-š•©¼À›Ö’Ù’?áw Ü”n„0ÿšm¡F0›¿5 5¶LC]†¾.Ã`Ë2Ú²uY°6Ôdê«Óuøa(U‡çZéÆº S]fù…%4}Ÿ4?¦.7ª:;¢2ÓT¶@[6_S‘¢é 9Qö‹]ÀÛ²4‰.Æ ®í…G¥¹ÀÜ\Û\ õËîpflÜÁðüv@E&†·§ØØËð^â-A¼‡é9øäÑ5ø= -~_Ž÷øÕ ¾§–c§—+Ï _•àWE›_yÿFùÀûì2¾àðnc~qñ|ë{_ð{wàõ½ƒ‰~ƒ¿êûešûˆ—ªP?¨ä~IýÖð§uÏo$ùxÞþ¼1 zÑx_ÚmÄ+G$ÖùªŠxÕÊÀ¢Ù×íQÂ/±¯ÛÌ0|_wÄ¿vúM–ôoú}ëâ_a7L„ßâxߎG¼Ü¯8‚ÁoÒÈÑ$ Þô›$~5i䤛_çBÚ«_ áÏÜ,ÿ§ýVÁžÍ¿<(õk›\O~ëSЯ8vY0mY­¹1my±­¹QöŒpѯH˜ù…\ƒ;hêÒ´¶ =Ʋ õè×P›©«Éð¦éjÒ`=l@¼è׈kììp[ND]NDuVXu6¾¯"ÃXº@~+ѯý‚Ð’øæ%ˆ·uY2„™_{q¼£(¾¹0ÎÓos~xK>L[ѯ‰Åävog‘Qœ¼½%€×p Øx°Äx¨Äp¸W΢ߣ‹5G—¨.9º(øØ¢ ŸcÇ«N,QÑâ9ðÔòÀÓËU€÷Ì -å9ô«ê/mTžß¤¼øâòf9l~¯|çu³ïµ->× /l~/ås û@à÷Î.ÿ»°„¦õ3'\†Áü}P¡y ø3¼8|ŸÖ™žºøüb/¨—M/íQ¯ѯšc~i‰ý¥5öUk4ôKk ·ý‚xßÞö¸× ¯;]'ï_ôË ã,&¿ô.ÊÄw‡ÞЧâ€0ANxÇ‹_Q‘|]Å%¿IB’Ïzó‹ „½ø÷óþv¿tìì»ßůüãü† -~µ¶…<€ B™0£0ü¤ùkôœ¿¸ŠÆ¬©ƒÿÃt]C¦¡!«ÏÒÛ²` kimm:°…±¶†-­a:g1œÑ&›è73¬*3 †oEºæ/»‰«6#¬17Ú~‹ãš'¶.Mn[6¹}ù”–%‰ö’¸¦bk󢄖’O¿Í.~ÃÚùn—Ænâ%¿òkì¡z‹ ä— _O¿€7ôá=¶(ð§Åªã˜òÄ%Ûür¼Ë•gW*έRö{ñË篛_qþÞB¼~løÂþ÷ήð‹Ïÿ"^Ñ/ _íƒ --®tâÅ/àB ‘‚ßÈMQTôK{ôKGÌ«æØ_šc_µ@1¯^- þ&o›å àm'¿žx¥~$xãYô,¿˜²“0_NHÅ/ý~˜¦ða¾–9*æM1‡œ$~ÁðŽ@'XÜï°¿“Añ; - Ÿ¡³¬3ÿq¿x·ÆtþÌ>^6šéOþÎ’áÉâ…-ðè~çƒ_5í…Àoªx6e›³#`ñ ?¼ˆüÂÆ´ŽeKÕÖ§é2ôYúFô«¯ÏÒÙ2uu`VSƒr5è7]WËtÇ[ŸŽåDØrè˜:ÓT•a¬LÓW,¼ÚZøïl½ób˜_0Û¶,¹cù”ΕÓÚ–&;ÅÛ‹­-‹ÚÀuq|K¡…ùmÎn–úÍo/k/0QN¼ÌoW‘üvzŠ äW/.žãâ™ùÕ0¿Çpå,õ«<¾Xqb‰âç¥Jîð®P@çV)ú×(û×*û×)ú×+ÎoŸ‡õ3>_Þèe“ßÕï|¯mýú~‰- ‡¯ûþ—á%¿: UÛ€~a ­wd™š³Ãàg#ýQð«'¿/üˆ¦LHáL]}&¬¥5µé€W Ucð[—¡cKk,ÇÔÖb<¬Î4Õdè«RµU 4µð?³>;žÝ\hn.¶¶.Il_–ܹbJ×ÊiË&·.Nh.±ÂÏöʼnPkó…wh0¼ya­ùamù€7¬£ÀÔ‰rx¡.òÛƒxõPo‰¾¯Xw XO'WÚÃ%Z†ýâðuú¥Å³Ô¯oÛ€ïrÅÙåò³+åäWÑ¿Vqn­¬¬½ìüÙ…²K.mð»¼ÑïÊw>W¿›t}‹ÄïvÿÛ;îì àxwàõ£U{ƒ÷‡ âá³ïP¥~¨~jñä¹Z‡~kÄÍ/óñ´.ò™ †/øF¶N¿1Ïoì G¬Ä¯G0â5cm` ¿€b¹mIbëâøö% K;p[Z -cèÞæHš¼a-y¦Ö|S{¾É¯¾‹U¨ï.Òs¼Åº¾À«=áGº™_ ¥¿Çøâ9øØâ`O¿xì¼\qð.—]pnU@ÿYÿZjìüú€þõ6\Úèýú\Ù4éÚw“poñ¿7¶ùÞÜîkGÀmð» »ûƒ_›³7èþ¾àA~åH-L^ƒàW÷° -&¯ä>®%¼uÆ'ua4|o4à}Ñó‚ûåÃWÄËü¾l†Ì/Ñ/ \ÈŠµY_³/Þv…áþWÚW¼¿vÅÿÖ-âµz©—Þ+ÛËß.ûVì äZxR¹¢ß#b Â7 -1¿âq´óÛß.~YÃ'†Nü -x¹_lj#§ù¡–‡ß©ÿ¿øÚXöÎIW¿ŠZ/)mùe6af1#\¿ ´1UÛ”V=C0þKÝÎàïá_¹¬¦L]CºÆ–¦®K ­M ­I£ÒÕµšºL ¬e~on/Ç„œqSLÇ×°G†áÿ¡È06f™ì¹ŽüÊXh]–ع"¹kÅäÎåÉ`¹cibçÒ¤Nø¹8¡ü¶°g‹Ð¯ ýæÛòí˜êÈ×C‚_Ô]¨ë.Òõi{‹4}ŚŚƒ<õ¡õáõ‘EøÂÜùò“«`áä -¯Ž/ÁýïÉ¥ÊSË”§—ÉÏ,—Yîf…ßÙU~çVûŸ[@~ú×ù÷¯÷¿°ÁïâF¿Ë|.oœÄü^ßìƒ×éæ«[Û /ù…•3úÝHxC8Þ2Í à­„˜_ýP•î!_ݣݣZ ¬R„éðÙ~ŸÕÇ÷?M(Oߎw~)˜­¢ÅŽ[×Þ;ý&€ß‘ŸãGNÆÓBüNáñá ~“8á3°¦Îá)#äX¸Š–¾‹ú“~ñvn~ËE¿³Ñ¯m®Â&ø­Ÿ§l˜§âÍWaÌ–„ƒë„4¥j@¨=]çȘše‰‘n$-þ;N¿Ú† ÑoHmZH Äý²ˆ0ùm̼FväÕ„ õ™z[ºÎ–†5¤ë² M¹axUQlë"kûÒøŽe‰PçòÄÎe‰],ôßVln-ŒâÂð¿ùÆÖ<Ô&ÈíÈ×Aù$ÓbEÚžB5ÔW¤>PŒ,=Xr¨8ôpI(à=²(äèâcKÀoÐ1Âû^6â1¿§—)Àïið»Âÿô -ß³+}Ï®ö;·Æ¿m†~ýÎoð½¸Á÷Òú‰—7L¼²iâ5¾~ö£‡d4|åwvÉ æw`¯êþþ`áž .ž ïƒ*ÃP•q¨ -ýUëÖ`œpá1Œ`[ø[ÔÓzôû¬!æY#áðzÁrpÂ/0|-¿´Ä½j±Â/è·%Žüâþ÷5?¿²Òõ#|fÁµá—¸×ô\½ÎÎòk—?ÇÀê‹¡Ï!EýÆ¿+õû±h´Üg–ø:d~wØÂ“>êNØu9íæ7;žðþD<~GNÄüG„“†ž,ø:r -–Íà7~ä4ÁÉ#g’‡Yg'`à—5uÄõ Kì/ú-ý~+ýÖ‹ÍSHð6·)XŸT¿ ¸ZÒ˜ª•àý¦3³œªàWãøudêY°_ÖÛ³a ¬CÂéêºôÐZøEÂX†h!Í6†ú,ÄÛ˜mjÌ26p¿Z¨´ñ@¬)/ÌÛâ˜ÖE–ö%qmKâÚY‹¬‹ã:ÀuIlkQÞÞÌ $¼-ù€Wß–G3—زº¸_À«Á -Ñooah_Q蔋xÉoÈá’Ä»(øèbìÈ"ÕÑEÊc‹Z¢<¾DÅ‚õóÉ¥ -ò+¿§Ñ/›¿~ýà—~×ù^Xï{Ið{uãÄè×ïÆÖzxüÊù˯vË/t6¿ûÐ/;£_Ž·Ú8Tm"¿ú¡jýÃý#¨Vÿ¸Ž¯Ÿ~ÐïóF°›ßfòÛlyÙl}E~!ÄK~ióË{ÓnyÝ~­¿tÄI“â%¿†—üÆHŠÆÐo}‘0ñöE:;E_÷6ã‚YcßB‡X@˜ev™Âá{ßñR¿|Q톳¾?÷äbÖá"Œ~‘0{GžB'ŸŽ#ÂI¿^êý9èoóK_d_:cBÙWËgNbUÍò'¿0‚eusä6ª~®\ê·‘üÖ§ _ËjL mJc„5Ò_à'‹þÒ%{†ü6géÙzÈž­kÌÒÖg¨m꺌Ð:„LgY$—e‰Ñõ`6 äR™Æ† C}º¶>MÛNeê³õ9@Ød/ˆh.Žj-1·.¢JbZñ£½Tq4Ç›ï†Wuäi;òµB]ùZ'ÞMO¡¶†oaè"Ä{ˆä"^W¿Ç– ßc‹•€÷§%ŠãÔ‰%òKd'—Ê/÷‹„Ï®ò?·: #¿k~/o˜te㤫›pñìê—þÝ­¼ûƒòîìÞ°ÿÝ/;W°á xÁ/*¦ßk j1î×fzb‹xêô+øyF'W,\<7›_8,/š­/o¼à—ö¿­tøÜC-ÄÒk7,ä×¥×üAB+eyÓIr9Þh÷À/û´Y/ûh´$þuBÂkþAvúüº¶ ·yðs-©_dëÒqæ×B~­#?'Ž ^Ö<È:r­ô3é=`6G$„ß#á©ï%/¥ük~'ðŠ~5¡¿ÿËüúÖ~Pû­ ª›ÙfËiþ*iòòá‹¥5.jL ‘֔Ƈ’\—è/¥©›34ŽLms¶®9Gßœ«wä蛲u YšúLµ-“)Öa5¼:[&È5Õg…7d…A™úm„½vº®1]‹e€_mLsøüoæ™áø P‹´Qð¶çiÛó4ùκò‰mšÕ‹~CÁïÁ"oðaðºø ¢á«D¹KåÇ—È@îÏK “ËN/gÁúY~f…ìì*ù¹Õr<ÂÂè×Oô{eä«']Ûä#ú¼7·Ëoí¼ª»?ÞÝxõcÞ¹û_6|Á/[9W›ŠÕ˜Õ†=ª5=®5>†ïÓúȧõÒùû¼)öËûÜaf½hF¼î~9^3]f÷_EÓk¯ð/® r­ø:.ó›ÎØ_»b¼ãå~©Þ¾ÿu‹oŠ?ì×,YHƒ\3ÁÂéôˆ‹ß¸QüZɯyäg‹«ßÉt_eÜÈ)ðƒø=añUô'ü7û-ý’ ©|:}¿: ?þ+ñK¿ØfËêç*űÛèá·)á ¦ðT¨#Ý%2")Ô‘©qdiÙº–\CKž±9Ï`Ï…¡©mÈV×g1ÂÚº <|®ÍÔÕáù•±!7²1'ª‰jÌŠà~3 tÄÝ”¡kÊÐB™Œ°¶ ëšrŽ|؇ÁÏf÷˜\cKž;ÞŽ<5cËêÎ'¼ù¡Pol{5}¡ -o¨0y/ó{ÔůâØbÀ«8!Þ“˜ÿ©e~§—cg–Ëήóû7V+úW3¿~ýk}ϯ󻸯ÜýÒ›7n⛟Á/à ¶,çc eš4|‡ªL"ÞG5a¬Çµáë0Z6Þˆgõ‘Ï꣞58×Ïà#¼Ï¨çÍ̯åE‹å%Èmä^¼#æ—¶È×í¾¶ý5ûK‡Y¾«ÓÂñâÝc~ ¯‹_ j>-Êb„c>Öïá8×ùk¦açK~ã¥Ëæø}ÿs¢ôe;‚_ F¿É#’ÞŸ™üžáýžûh¿ÓÆìÞ…õ#~…¿óªtúDˆ¾<¡ræÀûA¿âü ¤h -s¿Á®9yâØÍÐPjô›î¾ì!^(GrQPaXkQ8d/§º†]}6ìvu¶l¬.[oC¿¹QM¹D8;¼‰Ïx9CO§ÜÚ&X¨gh¡L ¬Æa Ûs Ž<£¦pž©9רœkhÎ1´äXüGƒ2´æê[su혶=WÝ‘KxóÔ]Bˆ—ËÅú05à=~ Cñeóá’`†÷ØbÏà—†¯òÄRåÏK?/•1¼'—úžZæKxý¿òþUŠó«ç×(è*RÀùµ~‚_¿«}ïw¾7ØðýîRÝù!Hð,yfÏxÍÃc+wÂk#¨È'u‘Ol8y oä3º`ô¢)ÂËFMQÏìQϼçÍ´ÿeµ÷_ñèFJ¼ù9üu;uD¾îˆú¥3F½HÖÙ›®è_GÃË óõ3û¨·ð]oÇ[Hˆýí@ ô;t径&¿ ÕÊε¤›â‘£q#ǰácVÊIüZ°ãæaèD,.¡ñ,ËùÊ,æwø”™FpüÈ©$ìt’x-!,úýì#ý"aæ÷óqüµíÓ}J±‰eü³Ý½ú×Ï6qÿ;_å\E“ߦ…ò‹6S‹T]g1ˆ¶gjìYZ;úÕã£=…aíÅ‘‹£¡Ö’HGa˜½ÀÔ”oj„òŒ ø¹4ÀÖ”iϲçEÙs#ì9áMÙ¦¦L¼ÐŒ—¢èÄŒýç¢ ÊÔ4ekí9:€Í3 [”«Çå:Lü0+ÆðjÛs M{NhG.âíÌ éÊ é¦8Þ|&—wý†ˆ~qÙ,ú]BxƒZô;°"¿°ç…e3L^6|ϬÀή[!?‡~e€÷üZ–ìü:ÿ ëý/mð¿²ÑïÚ&_À{}3Ë'Ϣ߻?ÝÛLxCîCûBé¶+X<^ãƒJãƒ*Ó§_6ÃÞǵQOꢞآéØü²gøÝ’ϱÈgöðgÞóæÈ-Q@n‰~‰E²^µ°G"~i {ÝF„Ã_w á_:£¤½îŠ–öÇ~»E¿\1÷ËC¿¿ˆýµ/ú·Ñœ0)vÂäÌtk¥Û,>j9fäJ²dˆðe~‡OÄ ŸHr÷{ÒŒëgô›8ÌKÒ’̯»?Ôð÷ú­ñJýJίþ=¿ø—ÂMYØù¶E^ü„ýÒX¨sIl;)n)Žj.ŽtE4†Û Ã…o‡E²{¥¹áöl“oÑãQvó ÿOáYmÏRÛ³58ÜsasmhaÁ+²µü"Ô–£k#¹˜º#'´37êÊuñÛ›Ò—r ÀÇ[|¸(øˆà÷h ?¶:†rƒ¸ß¥¢_ù)~f ñëne@ÿª€ó«.¬‘]X+ÇÖÉ.àÍ¿›}é2¾R¿€7„ð†îSî× ÞRí`¹ñA…éA¥i¨*Lœ¿ —âx×F?©ƒbžÚb$~Ã_4áÈç”à7rú¥¿ð“¶½°lýb¿t„ÿÒñKg¤´×]Qï÷W–ÓoŒóZ0×ÏÌ/#ìæ—Æ+Â’{)ñ¾+m„©£HدEÄÂðE¿fò›àͯ…ü&~Øïˆ‹ßiÿ¶_ö©nÚùúTã[ùÔ/áýH¿âþ×¹½ðºøE³0‰°=ƒVÅQ%Q]‹bz–Zz–[¡®eÖÎ¥æ„ÓZMEèæ¢ð¨_Ù Kâ£#Ë`ÏÔÙ3´Í4yáÖ‘j‡²ÔŽlMs޶9ö×z^Ž𶹤¡ÔíÙêŽlu'”£îÌUwIüöä…^ò| ÀÙÁÂàCXÐᢠ#EÁG‹otŒ]ðuõKú*O.SœZ¦8½œ.­ð?³üúž[é׿ -;¿ÆïÂZÿ k‰ð:9÷»ÑÿêFÿÑüÞÙÃðªö†Þß‹x”j”iËôFõA~£þÐï {ÔsX<Û#i ý\\9ã*Zœ¿|ÿe¿1^û•g¦kÁçg¾yV¬ÏüÛ˯}1¿öÅxÎßúµ8 £bóù5“_+ùu[?ÇŸd‹çÿ†ß²é>å3&UŽâ·FŠ×«ß”@†÷~”Ÿ¹Íü/ÕÒ) 3±³(w/Šé]jé]׳<®{yîZf2³ Këö’ˆ¶bØ#›Z -ŒlUŒ×ž²tð_ øoŽÝLôëÈ -udƒ_usü÷AÛ‚„u°H†9+€S·e‡Bí١١è~æHý÷ä÷æc}ùA~ƒs¿AG‹¡À£%ì9bÄâ/™\¦ÀGõ—á=ϧ—ËÏß³+Á¯oÿ*ßþÕ¾°á%¿×Ê/®“_\/»¸!àòÆ€«›˜_?|gÝ6æWN_TÝÙ|oOèÀ^ tŸfp?àÕ=(3`^üÒúG>•3àuñí¶~Æ8áèç`+#ø {øÅõó/laÍ,ÌJÃóçQúµ‹¾Ümn§dŸù÷Yƒ)ü~…ç’è¦JØóºûe„šßa®~aýÌ–Ð|ñœ@¯œå„é½àÏïO%0Â#R¿| <™ù}ÎíYäwêøS?âüJâW˜¿“ª¿ñA¿_£ßjáØÊöë¿)Ε³=5Äîáµf€Vu ýlF¼è·…ýM:þ ûwZ²uá@Xðkí]A„—Y»q ¿/³tÃÒzqTGIx[‘±µÀÐ’ c]3¬³µÍ°ÏÒÛæÌGVHs6øÅšsÔ-¹V”£&°ÒB©öìòKå„’ß஼àn,ˆü‘ß ƒB„7:‚~ág ø=~‹~aÙH‰~§`øâÛ6ägVúŸYåwv•ï¹U>ý«}ίñ½°ÎïÂ:ò»N~/­—]Ú ã~¿ó¿¾9†ï-çgST·wÞÙro _ÝÀ>Ýý}ºÁýúeÆ!˜¼8|Ñï‡ß‡°ù¿ÄVLðËžù÷¿Ìïs;ÝÿÜLÝýƸúu9¿ú…auFK{ѱ3¯™½ö¾ôí|¢ÁÃo_÷K§Xž~ߢ;²8á8¶ñœ¿Ô»#̯Y\Q a³@ØB‚FŽ'a>ñц¸‘“‰ï!'á$σhô{vÚ{þš;çþ;¦ŽÛáé×ãúÑþ/}Jgø–Íð¿’ý/øeƒ¸f–ø­#¿^ï¿‚áÛ´'¯=5È~Ó„$t a¬%=´%Ã{Íø/„¶djÛr…]%Ñ=‹c{—áú™À’Y -ñRs×’èÎEáíÅ&ô[¨o)еäá`mÉÑ4g«[/š qdCÍ9!b­¼Pü™Ò楠öì ŽìàΊ _î7ˆüB}ù -²ò0¼ÎÐï"~«¤Ä¯ˆW~r¹ì¿[Çï*¿sàwµoÿ_:mö¿°.ü^Z'C¼ä÷Ê&ÙÕïØkënÀâ¿Y¦¼½#ðö® Û»‚ïüzwöÞ^ýÀ>ýýýúÁ2ãƒ2ŽÝŠ0aø²øý4#èØ -üÆRà7ö©-o›dGÐ tÏ3%úÅ'…›Ÿ™ß—Í~1|]?ê¾*`;Í£Æ?Œq¹ì3ßÝq¿»¬œÅõ³ð¾íÃU´p#VÌ[—±¨ƒ±ï8al:l>l‘äB˜oй_óŸÂ–a\K[ñŽJô›D~“™_º/:þ=#|’û}laøÒaázêÈ"ìú¦è¿èðŠ~«?䇯}a°#•J #¿âƒg3ú Á¶RÂCø¿¡iÍ1´ç‡‰#¸‡÷ \3²Å`òFw.Žì( k/6¶Z u-Ú–<ˆÆkŽº5›xæ€Ü@~ñPõ¬=;êÈ rõÔxó¡À^ª/_ÅüÂØðU)rv´XE‹gºÉ—Í /~aßо\~Šî³:½’v¾«Ä&}û^ØðšØâð•_ÆáK~ñµ“×ñƒ Š›ß+om‡É“÷öî;?hîý¨ØkØg¸¿ß0xË o%DÇÎ ¯»_¶f6?µYžÔ™!øûÅ×n ág.~£$/Ä|Ð/Maz‘]ü¥/wÿ9¿üëÞøï. ^§_«$ ]6¿eᣠ±o?ä—~G[¥!a÷µ´ElÄårRÜûãñôhøM¢Wc¡ß÷?Çc‚_šÂÞüÞÿU¿M ‚ C©!Ž47¿û½JÂÁ-PF«Ê ÿØB~›u–¶-ÏØYÞ#ØŒ§XË0X0w-‰Á± ËæE€7¼½È¡_À›iZò`… q¼­(wÔÚXÙî ~;‘pP'L^<‚¿€·;_E~UR¿‡iñ|¤³åá­’ì9¶rÆo£~O¯Pàä]éz_9ŸE¼úexaÛ‹xɯüÊFùU>Á¯œûÅá|gwèݾ?êöÁïÀ~ã`©‰‡a6>ðîf®å©ÍJ?-è·!ÙŠ¹ùuHü:Fó…¯­£Ÿìþ+ïý%¿¸Õ•Äïâ`~ñ—ö `] [<޳\ýÒ&æ—‚%t/=I PïO%aaý|f -%,¡ùsÁÿ»~YöT…=UÅ~'¿ùåµf†´f…ÐïŒph ßÃTß™ÖU„§X=Kˆ0.˜c:܈v[Ö^dj+4`úÖ|7¿R¼*im.[Õ.D~)ô S8üªFóKkfð«<&žYá¶—=g¤b¯—$¼^ýú’__ÂëÃ×Íïe¯~¿wõûøÕß{{ ÷Ø.5ÞÂå¦Á -ZEWÒõ_ÉýÏ£øµ>«·vŠqýÌϬ>HØÃ¯w¼¿JðŽîWúC,ÿüþ.]H:è°Ó²§ß#ì÷ý ñÑàòûÞ»_ìßó[6c|ùWãñÊï×üBðùU6¦¨¯"¿løÚS¯ ‚_(W¿0‚q -ƒ_1w¿y†î°î’ÈžÅÑ=K (æ·]ÀÛŽ~aàÛЖ< &o;Äü:µª ·rþ8˜¼Âإɛ/'¼òÞBy_¡â@¡:X¤:T(.žÉ/^3®ù.Vý)¿çÖúy÷»Aqy£¸~V\Û"¿¾Uv}óx ðî -aëgð{GÁ´ŠF¿¥Fa m€È/]ù¥¤ó—á…ŸÌ/>sD[`áµ9ì™}š¹’ý/Íß×ù+îE¶ÞNžÿN¿fï~ùãÀ‹_¯Y£úù·üŠ_-üx¿øÚºéìùÁñ‚ß UHxbõ7“jfùÖÎ ¿röS¬vÁÌ/ÊE¼Ž…*ÇB…ÁÊì 0ø%UÓŒ~±–tóÛšˆ#˜jÃðD¸Òà÷ÐŽmW¿(´(²wIù ï,6u:ŠôPg¡®ƒù¼¸áÅÚso{^Їð -~;?”²3WÑ•ÉA.âÍ—õÈz ú -ú -娃EŠCEÊÃxlÅübÇèžIþ†«¥Áç×ï,\õ¯ 8·:ËY7@ŠKÉï&Å•ïW7+®mU\Û¦¸þ½òÆvÕÍAà÷6ó Ã׉×pO¡Mx~…§ÐFq“_ÎrúÅ=/È#ÅfzlP8y¦çèWìä9ZØùòó+ðËÞ+-[¶rþ[ý -r]ž6{'ìæwÅÿŽ_°è¯ Kü²ËÁܯp-‰uåÌTÁ/ï#ýâýW_Nà/ߘ>®lÆ¸Š¯Æ¹øýÖ§fŽŸmnå_?7@¬a¾¢1EÙ´üâä] r,P8Ê ,÷ë@¼Ì¯¢ñb­*V[f úmËnIjN lÍnÏVwæé» Ý%á}‹#¡ž’°Î"cW¡¾«ˆ×Y i'¼¢_áäJ:|•P‡´^ç‡Rtå*ºóä]y2”‹ù÷`à÷@!v*’*’.RÒÝÁbâ&¥~íÉAЩÜïéU -îwµÿ9|Õìüzùy”«„.®WÞ‹T—7*/ã7CÉïåµmØõïU7vÝÜzk—úön _ÝÝ=€×p—ã »¿?l°4l° â§ÐƒôÒP•Ôo$»þû¬Áò¢1zÞ`yZœ£é~¼øûÂù¶gñå9ÑÒó«—Ò×>ó÷·G GXÆ¯Çæ÷71w¿âù•ÛØuú}+$ÞÈÁýŒuËË^xt¿#À–òâWx»ŽÄïÏÎÛ9øµ$î—Ÿ¡—RJúh¿¿ãÈïØŠ¯ÆV|=Þï?«^B¸‘/žUˆw¡ÊxÈ1æwA$ø•5§É[Ò¬Ö ¬lËPµgJ -jËlÅkL*î7WÛ•oè)2õ-Š8~‹Mˆ·@×]¤ï.6tº -µù¡ü¨*'H¼ªÛžCC6ö¹àWu°r\ꤺIJ%¿çÈoŽ]yog.ÊÅœx¹_™ÄoE„K˜ß ŽwïÔÊàS+ƒN¯ýâ>³&_òŒ/iW^`ß *Ö¥MÊËß)¯@›•W·ª®m ¼ö}àµíÁ×w„Ü¿»µ·ÐÝÙ£§¯ñî^tý†–†ß/ƒÂËÃÈ/¿Ú9|¿ ÷•=áE£õy#>“ß(æ÷¥=æ%á•Ü¿áB†¯ðž:óköØ>ø.!¹ùýÈ+aìºÈuõK7lð§ø?Ú/õ_öëL¼KðË Ÿ™âæwû”q;¦ŒÝ9•E„Ùà ŸIýÒkë°qR¿•3a UÏb~}¹_ äº9~0/Œ]X9§*°É¹,0 Ãw¡‹ßVKxÛxn~i -g`í™!Ùê.ô«ï)4õ‡A=EÆnò‹ŸZdÅ]šØêXᨹ5¯ µç(!š¶ÀVÎË‘wd{©S¨+KÞ•-ãåȺse=@8OÖ›9ý"aÀ{¨Pv¨PAxUtøŒ~•„b‹BñÛ ‹ƒiÿKO­P\ xƒ(øÅͯÜéw£Šuqcà¥MN¼Ðòû}ðµí!×¶‡^ß©¾±K{k·îöúÛ{ Ðï^ÓÀ¾ðû¥ØÇù…53L^Àû¼nÞà÷?ã±óûÒÁç¯äþ+~þÌ?»ÐÆÇþ‚¯Ýˆz-^Bb~;Y¯Û²YÈú{õmˆ×Û[t\£{¡cèqàèßœS8æC~‘°·Å3ø•ñ ,õ+ݻߎ%ñûž=ÎpfŠøj;èûÉc·;ýŽ¥)<ï™6ÆÅ/¾ùjù 1¿å3ÇaüÖÎö©í ZÅDÅÜïBUóBes*$ú¶nÉZÀ¯S®w¿l -#Þ,|ö§+WÓ•§ë.0ôÀ*ºÐÐÍß·¬í-1BÝEºÎ|uGnL[¶Z¹­ÙʶlԞ͆¬\’¬=[Öá­Î,¬ `ugtçÈzre½yT¾æ×WàÇü2¼‡ -•tÏd n{]ðªZú}Õw4¿§V*O­Rœ¿«åèwâ<,›7€Ü@ÖÅMA—0ïf𫺺-øÚ÷¡W·«¯íÐ\ß©»±[óí=ÆÛ{L·÷ÙØ¥ÂJ#Ë£Ë"ï—Exø¼à7Jxì(–n»ŠÅͯäù}üÈ‘à÷…ËðåçÏâgShøÆÒ§BÝG¹=ãCx?ä—ß?Æû;{‰vy"_V3úAVì0tXšyD »oÇ:ç{ºáDŸÅR¿| œÌ!Ÿ™,}»ÝGûá1¥ÓÇHübÕ³&V“_i¸Šž‹gEãyÓ¥ϬT€·™í|xñÛìݯ²=SåúíÈ -¦ðÙŸ®\¦ß÷(¾{ -–ÍÝEÚîBMg~0^ N¥`æ¶f)Z³ämYòv˜­à7~‘‰9Áºåâ׿=9²^Ñožož_ož/毌ã- ôæð†üD_õ•øU‘\†×é÷úUœ[§<Ïñ±.n -&Â0/Þ+[ƒ®"^ tm§îú.ÃÝÆ›{Âní ¿ýcø½áw÷…ßÛq¯4b 4ê~yôPe샊˜ûe‘¥a÷Ño˜‡ßÈÇ5Q’×nĦ¼lŠ’øuyy;÷Ëw¾Ü/½pòÿ¼_*FlDê—%¬¢½ÝíyE8Ás -œE'¿÷x;ÖŸô;vÿ—Ÿ‚ßòc*¾S>s,ó[9kBÍ·“¹>Õ³qÛæÂÊ9ð’_¹7¼0yÑo3ú à+gIÍ ZRem -iíè×£,U>ûÃëÌ î :sé9|‰MpwAÔ•Ü™(=U&¿€WµgŒVGv€hVš‹ß,ßîl¿žÈ·7ׯ7~úöåùÈó;„óý*P*p!Ì—Ðøaßó»Zyzµ:³Vqn=ú=¿1è<â &¼!¿ ¾´9èÒæÀË[‚®l †áK“W{u§þÚ.ãõÝá7öDÞú1êöÞè;û¢ï·?j 4ú~Yìý2ó`…e¨*n¨Ò„+¢+"+ÂéY†¡ªˆ¡ªÈ‡Õ‘.~‘p½üŠ[â×ylÅ>»ð¿è×*y…Ý_öëNø#ü~è¡/wtà‰´Çу_À;¿Ÿ -~ÇT"᱕³Æ×|;‘–Ð>ðKõ¬ µ³'Ùæù5¤ðÛ3€pŠÜA'WÍ djõw«%5 5 üÊ)KyâE¿ÊçMPÞ…¨éizˆb·5ª¤§Ê°fn#¿äÔ´:²:©.oucä ûôdûôæø_‰_¿ƒù dEÂô´ ¿~„ŸG¼ÁÌ/Þ6¹\âwKujàUž^)ÎâBï¦àóƒ/l‚/visð¥-Á—·_Ù†ï5Äkº¾;âÆQ7÷ÄÜÚ{gŸùÎ~óÝýæ2Ëýrë`E4Tÿ°&ñauüP•õAẽÊÈ•*Ã!î·ÊÃ/¾¼.ßüL_ë_¾áôëðüfŠYÄ+î~;¢Åͯ·{#G?måØùw~x%úµ: {cGÇè×Ûþc¿n7uxõ+n„Ù•ÂFX2‚ÿ ¿Ÿc„ÝýÎÀ*¾ú”üRÜï¤Ú9“oÕ7ã¿2¼=Rðk§cgîwA@ó0ë×Âó‡ZÓZÓE¿rïr~UΛ³Uð7ìÁï9xOT'^½UºG{^\9ƒßÌ€ŽLp -ùyË¿ó®˜ð2¿>à×g¿2˜Â‡ •GŠ”ôÌ‘øÌ/U>/§“gïéUAÌïéÕ*æ÷ÌZå¹õý‚Hnáe~C/n†B.m ¹¼5ôÊVõÕïÕW·ë®í4^Ûyã‡è{boþh¹½ÏzgÜÝÒø{e ÷++T%U'>¬Iz\—ü¨ƒåØ•QŒðP%ÇëmþzúÅ—oû_ákeü›eˆ—j_çù³Ëe#¼œ¶Þ®TnüÛ<|~Û‹ ì{½ÿÊÕï˜_DÿzÀÕ°þ~ß{÷‹æWòþ|Ç^‰ßýÓ?)UÌüÔÅïœIus|¨I¶9>õóý€_y£Ôo -í|añ¼Àß±ÀϱÀ·y“pkª‹_®ØÛî€`Úº$ü#úcg6PE­,ñŠ­ø7è׿=ÃòmÏôéÈôs«3ÓW¬Ë#©ßî¬I=Ù“zs&1¿"ჴ„f* 8\$;R¬8ZÂ;Æ¿âôËWÎä÷4ü\ˆ~רάU](ú• ßPÁoè¥-êËøÝ¦½º]mgøuï­}ñwö'Þ)Mº[6ù~å”Áª©ª§>¬:T“ü°6ü>¿5qCÕà7šüF‚_’E ‡W¶h¶xfëgáͱ|ñüJrÏ•óþIþÁA³ä³ÝÎë¿ââÙý²Ñ‡¯yó+°•–ð®7á-Eßÿ½/ž^»çz;´€Úí,¼î·sŒý¯ù}ïêw„_þc¿Â+tèðjúØÒcØü-Ãù;¶òkX?©æ/°k¿0qó+kJÁì@ü¦Œâׯ%GpÅo{¦¢ƒ)bIÿ2ØÅÌ©xHÑI9ÿ2K†Ã—Sõ’þîÓ)©‹•ÁëÎôå‹g>'õHæ/'L~‘ÜCxí¤Hv´DN1¿ -ö‘X?ãÝVüÌYô„~מYˆx%~iþB€W}i3…rµW¶j¯nÓ]ûÞp}GøõÝQ7ö˜oþh½µ7þöþ¤»¥“ï•}6Pñùýª/T>Tóù£ºÏÚ¦>²M~dC¿Cè×ü *z¨* -&/í|£Üü>µÅ0Âøægþ´o$¾£ûe2Àúùc‹'Ϭ÷;¯œÏý ~ß¡ßÄ·Îÿ&Pñoûâ\³R^®ÿz^v·ìáw˜HŠ•úe§Ðã×eÿëÅ/{Éù‚õ‹Ÿ-£‹G3Æ•}ÅŸÇV|=®êëq@¸úð;¡öÛ‰(w.¯ažó›"kœ/kš~eà·À´Šf‰„3ÝÃåá_’wücGc+&{\ÒÍÂųt -ÖInuñ|º3„2}z2}{²(çþ×§ÏmþøÓØE¿ðóH1ù]$G¹¬Å -ô»Lâw•‹ß3koйuø êßÃå²È¯æÒÍ%”«¿¶Ýx}‡éÆÎˆ›»£oî1ßú1îöÞ„Ûû’î”N¹Wþù@Å—÷+g VOªþ°nú£ú/×O{T?ýÖ%<¬ª1UÇ UGƒ\aøFKüâ ¯„6„»ùk¯`åýÊûJ²læx_ûõ\?ÇŽ‚×ãy^÷Ý®»ßß½øMxדø®7é-ËI8Þƒ0÷ûöïð+(Žñô;ò§ýÆ{úÅ|JüäèŸñ;c|)Ýö\N·mT}=¡ú~¿ÔÌâ~ëç²|ç“ßôÛ4ŸgŸ`¿)£ùå„ñ ‹ÖÒ¿x.-“&*–üÌí0Ùýbnvno=üò9ë4ë É8j3y½(—ÇO®FÁ‹rGÃËæ¯‹ß Óbä÷ܺ`Šã=¿äªÅ.~§¹´Y{y«îÚŽ°»"Aî­bnÿh¹³7áξä;û&ß-v¯ü‹û•Ó«f>¨þz¨væCÛÌÇ _=iüòIãç¦>®O~dKxX÷°Æú°&æ!ù¶k¢;ýÂðn˜tóKÛ^;à5cø‘Agô£Ñý:ŸðõnÑv»¼xæ~=ç¯w¿âƒH.ý­~G>è×™ç½n~£úý̹ÿÝûÅØ}¸xÆ›ŸÙ“¿•_M¨š9¡úkÖøšoÆ×ΚP÷íÄúÙ>õs°ð;ϯi~@S -5ŸgOñ‡)/ùõuõëçô‹ÇÑÂ*š¥ E2:mÏp–I`%Ó‘@SBx1È#ôëÓée Z'z†›\(“~}zÙä%¿}¹¾R¼tñˆûðbÇD¿‹ùâßó¼\¸gÍY ?é— ³koÿzìüŽÌŠ]Ú¬»¼Ee›éúÎÈ›?ÄÜÚc¾ý£ðÞÝ?ù^ég÷J?¿WöL^Âû̓šYm³ÕM~§?iúüIãÔG.~cÉ/Èy\Kbza¬à—`üÈïsVSÌ {ìK»ù%á}Õl})éÃ~…mï‡î¶ú¿Vv«¤kâúYÊÖ ¯Õ9|1áA`÷\÷¼î[`Ôê-¾>;r$v„ß‘eæ„ù *Ùk¢ãÞKóî7J†FÄØþwòX¼…r -ó;†ü~JïÅ~ü| úÅýïøÒ/ÇWLŸUΘP5cBõWã«gޝùz|-ú_÷í„úÙ“ïŸFæ û»æg‡Rü)¾ŽÇ‚IÍ |šI1¶,û -„ýÛa·Që‚ן’þŽñ½­ô09Û#6³|X®“ÀNp«;kb” ?'õbè·W¸räŠ×éWŠ÷è"ò»˜M^}ýž¹«ƒÞÓk‚Ϭ 9½Ÿ]|nmHÿºþõ¡ç7„^ØÈäjaà^Ú¢£ —·š®l »º=üæ(÷öÞø»ûï±Ýnù¿îWÀØýŠÆî·CusÚæ>j˜ó¸qÖãÆ¯Ÿ4¡ßÇ SÚ‡j­ª-ªc…õ3°}\+Fo‹E¼fF˜}ªŸÜÇb_ ^ x½ùµŽ¾~6^òk×ÌqÎ>ˆ—üâ­’^ãáU<;…–䯖äb1oû¢½t æÝÁQ†E{Ëiyäp ÅGc‘0ÈÅŸB?Yß‹/Ȣ۱ط¿…û¢Ù:#Â#'é#à§ð‰¤mIc¿O»=yì§ßOÉï§î~ÿ5ý~9U5W5c\ÍÌñµ_¯ûf¼íÛñõ³'6Ì“çú4Íõmšç5{ -k’=e"Ë- ©T¿–4¬5Í¿5 -hËpf~ÓE°~Þò•žD±³©®lgYBÙ¾]Ù>˜p’LMôóÛ›=É™·Ë¾üâQÛór¿¯ü'†ý*Ž/U_¦¼gÖ†"aô¿Ÿ^SøìšþµêóëÔç׫/l@¹—7ë®lÕ_Ýf @®éê÷áW·G^ÛM37Æî@ù´ ->s‡j¾yh›ý¨aîãÆ”Ç °¦y›f?±óÔ>ãqãgmÉCµñ•Ñ÷*"*#ñðJð‹„ÍOê,ëÌÐÄkA ægægMæç,»åâµB¯šã —’„/t{ú¥Ú-o(dKIÌÆ’;Þߺ-ÐïÝ„éL¼x$Üí’äC*½â‘\¿ôM½í‹òŽšzw zø åÙÈ¡hX&¿1ÃGbÐ/{¯ìQf9vøýÍO.‹jçÝÑÎ)÷þ¤•ƒß©#'§œšöþÔgÛ’ÆIü~ -xwMûd÷´Oö|öÉžÏð§?~þ©è·ì_ãËÿ5¡â_㡪/¡qUÓÇÖÌ[ûõ8Áï„$<± OjÅÊ/Êeù -~©tòËã+äô€˜³~ÞòÁ\ýâÚ©zíÃ~'°z²'ôfÞ‰}Ù“úr|œ¹ÜsÅ®±á+žY±•3…~1öUnúB¨òôê³kCì¾ø;ü\rñj.¬×]Ü ½¸Q{é;\*£Üïm~ ð¾Ë|{o"à½[6mv»ˆ÷«!\-ÏyÔ`SžÚSŸÚÓž:RŸ:Rž6Ï{Ú<ûYó̧ö/7Lª¬Ž¹_ x8ýš¡'µ–'uV$l³|ЯUûª%þe³³ôû¦ÃúkóÏëNðh¿ø…Ëï=n~Yf*ömoŒ·¢1*Ô ?#]‹z÷0­‘_Þ0ü$¿#Ì/›¼ÖïÏqDqò{ô;uäÔTò;öû$ò;yÌÎ)ŸîœúÉ®©ÿÜ=íŸ?Lû'&Å.~¿Âàw\%6¶jú˜ê¯ÆÔÌWû͸ºYã0®¢1TÌ»Ïb¿Ô$#,(öå¥ù¶¦ûµaIíPü¤K·é“ÜË€&v@Òcä¬IÜ©{œpwöè~³Çwg'¿X_Τ9>˜ôÌŠ­™9Þ€C´ó-8ê<¶¼2Ä»¼'– Þ“ËTgVÁ:9³kB)'^æ÷ú5\Ùj¼º-ì°E¹0y#®íˆ¾¾Ó|c·õÖÞÄ;û'ß)v·Œ55XýÍPÝì‡õó5¤è7áOúercTÝcl%Z{ÝðF~/úõ”+t(rc~£¹_N˜íˆ%~Ù¡ÿp¡ôé¤x—§ O&‘_hòûSД­‰c¶%ŽÙŽ„Çì˜üÉÎ)ÿ„vMýøýá3 ïýb̾/ÆîÿbTöŸò/ÆßŠ/ÆVükLå—ŸVÍø”àY¬ñ, ÜH„=±§_1ÏAŒ[‰°XÕž&Êè­ :2'vf‰y÷Ûãë,ÛW ,ñ›M~³Áïx‰_*Ïçâõëó¼[ƒû.ø¢_š¼lìR ï©ågVŸ[z~­æümÿ5 þxa½þâ–öÒ&ÝåÍú+[M×¶E\Û~#pònº¾3öÆ.ËÍânþ˜pkoÒíý“oïÂ_Ü+Ÿ1P1ó~Õ7ƒ5³ÔÍ}`›;d›3TÿíPý7Cõ3‡êg<¬ÇÃ燶„ûÕ1•÷«"qó[ó°&æ$¦lqúmðôk}þÿ¢ß?×[£ÈŠxw ‚ÀFxééîW¬¨Áï°àWüv’ÇÓÁ‰ïNÂN²`#Ì?™äæwúý‡›_\B>fßçc=ýVü듊ý³ú+©_ÌâFx÷kŸÇ¯|ÿ¬_Á˜Ô¯o{Ú$Œ¨zk|GÆøŽÌ @8s4¼`ÖêÊñ‡ð÷l?N8{’$N¸'gBo­Ÿs&ñø²ÙŸ&oÞç\$’†o‰âè"¥O›…Ï“±·m^~ûW‡^X«¿°N~­®~Âï7.n4^Ü? —6.o6]݆ æ«„÷:NÞ˜»¯õæžxò›xk_2.ýìNéwK¿Å÷*¾ºWùõ@ÕÌꯪg T9PóÅ@Í´û5Éj«-°ó½W>P>ˆ„£ÖÄ>‚ªE˜¿À‹^;d}öÿ_¿~Ã=B¢ßáÃÑÃË®~ãþÈïd𼉏>Åâ­ ŸnKüôû¤O·'}²=ùŸ;&ÿýNùÇnFxš‹ßÒÏÇ2¿å_Œ-ÿ|lÅÜ/Žà¯Çºö›±.§m4‚D¿œ°¯}¾}þ$aÍ<Ñ=ï{aF˜o‡Û`ò¦1¿ÛÓ&´§÷ø%ÂHxRùÅr6µÀ6ꟲ®\¬¢¿ìÉ žçóï¥åñ¶BÆñz¨€?Û{¨H. -<\tdL]D_õÅsÿ´ ->¾,øÄòËC¡Ÿ—‡ž\¡>µR}z•úì*Í94k8¿Îp~­¾-(ÖÃïÖ/l4]Ü„]ÚvekÄÕnºò}Ôµí€7öú®XÁ/Ì_(þÖÞ„Ûû“øBºôsÄwËþu·üË{•_Tþk ò‹{•ŸÝ«šr¯2y *þ~¥e 2z <ò^Yø@yø`e$l~ÑØ%¿| ý¸Îò÷¿Üï³F óK„-.„ÿŸõëåôé£üŽ^ÄÛ¾pˆÆ†»Åý‚îÃQŒ-û…÷Áù+DsÂôɕɸÕ<²`DxK§[>ù>ñŸß'ýünŸü“ÿgç”ÿÙ=õvOû÷ KèÏÀïôû9Œ`P ~ÇT|ñ)÷;ýŸÕ3?E¹_S¤XÁü,‹VÑ|ýÜ4¢}>;Þµ‰Ò-Ͻp+Õ–êÛž:©# šØž:¡=u¼giàwÔ™1¡‹î» »}{ðq¿€ž\YO®¼;WŽ/ÀŸø:Ew.Tôæ+ñ¥¯E‹ƒ¨@Ju¨8ðpIà^ÐQN5äÈ¢PèèâУKÔÇ–jŽ-Õþ´Œw|9vb…[©=¹ -ÒA§Vë¡Ók gÖή5œ[kè_g<¿ÞäÞ†° ›".~qiKäå­ 7æÚŽØ«;b®|}uàµ@°óðZénIë}x ‰Î¢§Ü-r·lÚÝòÏîU|6P1u bÊ@Åä{•I÷*ã*¬€7 -Ç÷#+¿Õ8éËò¤÷¿OlÖ§õVO¿"aq»þ[ýþ©ó«ÿ¤ßÞî·W$N™¤±üî`Ä;XEs¶Qî„zñ‹xÙA¿/ ?¹ò¿z–DYa[·$|"ñûíÉÿ#õË OûäÇiŸìÿ ýao~¿úgÍÌOáªî¾„&Â¥~íóÀïxjœK)ãà—7;.*-ôi…Èo[ªO{*ÃëÝo{긎4î·ÛÕo·«_†—½¶'OÙ›x (øPIÈáE!‡‡ -Áƒ,9º8äzl±úh]‚Z-Õ‘YÝñåúã+ŒÐ h¥ñçUÆ“ÐjÓ©µá§Ö†^vf]ØÙõá¬s"û¡Qý#Ïoм t^èÂwQ7G_Úsy[ìåïc¯l7_ße…®í´\ÙŠÍ×vYoìŽÃï†×| Úk¾³Ïrg_ÜÝ} w÷⤻¥É÷Ê&ß+Ÿ¨ä‡Ï|ñüÑ~xÿ~¿¸~dý?ä÷Ýá(–ûúù(v÷+D;ý&¼ÇLß;à Iì8:nsü?·$üì½ `Iy/¾ºÏÑ}˲ǒF·FÝÓÓÝ3’e[§/Y’%Ù–¯Õê´eË’-É{„„+ ÀBö`ÙåÚå ›!xIð.,,/ ¹ì‘÷Ï;aáq¾¼÷¯£«ºz$ÍôôôLK¢~nÛßtwU}õÕU_Wu5=r¦ñglxôœç]ç<Ÿox÷yàÂøxïÅ&à¿OBnÑü÷ÎÖÝÙòaâ¿™mü£¹Fè—[?ºŽfìËZDšº0ìHƒCø³ëŸ\öÂ#Ä᡹0õßO3þ‹\X^ü™Uá3«èð~fµÀg Ï_£ÿ~nÿEÏÜßìü+tüõou}î7»ÿ=¼µÿöûÃàøúŒ|ýÁÑzèÔ??<öÏœúÆ;Çþåѱy×xÈñÍÇ&¾ýî3ßyÏäwÞ{ß}ßÙïâÝÀ—Áñ­Ç€/ç=ß…. œwøù'†¿ÿÄÈ÷Ÿýþc/À1òb8ãìK:ûÒ‡Áqæ¥O¼wì_µû'ÿ?|À•ƒÛÍ7>pYç…¯}±óîÿ%›ýê¹qºe;/>yõu Z,롉†‡O{>ãyçYÏ£“à¨פç1èžw_hx÷EèÅï½Ðø>â½hð ¾Ôò¡;›uÿiü#Í…[ÐÇ-àAŒý—¸0<>q­ãÏ–:tÿ]nßxhþ{£ãÓÐyCý?…¡ÿÞ48oˆ ‡ñ_Úþr^ðØý«ßêÔ>Àþ›Ÿû­®§_úÌÐ…™ãà~»ûY4°ý<@o¹G;ÞÐû¥7ô}ñ =°ó :Ìoà¿yÓ paøäÅ.ü¶¬ÿ~ýÁx<4úOÿó#ÿüΉo>væÛïžüÖ{ Ç·ßsî;ï=ÿ½÷_„ÇŸâ8¾÷¾Iê¿ß|ר·]hà¿  =о°?²A\øÔ À‹Ÿñɉ—>pú%¸ò/}:/zøBÿ…>û‘aíÎKý÷£äýŠ?Cÿýø8 -^á#þÞyÇYçÝà¿!¯}·òß­ÜÓFÿ=AúÏ'iç9ĵ—Â_Ò»ºÿ¢•ÈÇÿó+ãÈ…Ï¢½GÑ+¤¯žpÂóÐDýçëÞy¦þgëCýt¤/Pÿ….üAðÇ¥¦ÝÙôỚ±ÿþátÃGf 7ý1vÕû‰kÞO"ÿýsx´o<>µÒKþK]˜ø¯wcÿ™õ_ðÀÅ{"ÆãàçÐÖcO¿<ˆ»Ñq¯ë£à/ ãÙ×u?ûúƒÏ‚g´þ˜>ŸÎo8ŒÆ¿½Ð‘Œy¾òæÁ¯à.ôïEýçãÿðvèÅðøƒ“_C^üõ‡G¿ùøYàªðx8.àã»àx?pÛ;ŸòÒ÷Ÿ¼ôÂàñüû¡ÿ‚Î3qaØ©F!¬Ñçß7ôý÷Ÿ|á‰ážyá‰Qt@~ñÉñ—>0ñÒÇÁñò‡Æ_þð©—ÿpÿú‡ÃÚ3=v©ójþ §MžÒf^¡øðßÿĸæ¼ÿ=õÃ?ǯ€µƒ:ï+ŸÞ࿟1ã¿ìü«­œwœqÞQpüüs£Äm78ïí“›ÈO5OdpF»´µ#Sÿ…Ç ‹~æDÿÅo‘~µñ]08žÃ΋ýy«ˆÖýÐsÇÿ=Oü·þ¡‰:࿜©äLÝ#gë=[÷®ÉzêÂïÑ]¸³ù—š>p±ñƒ—ÿð®æLƒ^4päÍ…çâc¾t¤5 _iÿØïǽŸ¸êý³¥öO^ÇGòÙ6@ ºmKÿÿ:âó:ïÝ0ø|7|¤/ÒfXá(´œ¡·"ÿ…]hø1vô=vÂzú5Ð…ÉèÎg^ÛõyjþÂk‰ããõðÑL/"_ÇsoOäž/ÿnßß¼yà+oøêïþí[üÝÛŽþýÇþñíÇÿñ'¾öC_{ðä×þ§‡F@/ú_ÿÖc§¿óîÉï¾ç<9Î}sß{ßùçÁñ~@œÞo¿ŒGþåÑað/Šbúî{N}ï=#Ï¿÷ä÷ßwò…÷ÿ~ñ‰‘Ÿ}ñ‰S/> —>0öÒÁqê¥zùC£/xøe0òEçÿö½çŒ^áøïœù œ÷Oó¢É“øá‹|ö}bô6úƒOŽ¢WH£È…OýǧÆþãSãd.vÞ3Øò™1th>Kä¹Ðy7ñßÍ¿ÒmEÇ8~¾É1üóÏüùç†~~'6;Žÿüö±ÍŽãôäÂ'7ÇÇ9ˆ ë‡|Ö¦sè3²  ?;b˜T‰W7<§?É–ßFžÐßÃ×Áçþ`¼îÁ‰:èÂÀyáQûNà“uMÖ?~Îón4†caÍ…ž¼ÔôäÅÆ'/Ôðbôß8…³Í4ÛÄøo+ö_ü:)Ô¯µºpÛÆº3¯x‘ ‹àøô QsÞš;ÿÅMá/€óÞô¢£ý37ÛXÿ¥Ý¿Dþ²úï¯ .¬ü£à•ÅÂþûªÀíß ->ýjìÂøè|îG|æ5ÁÏ¿:ø :>ÿšÎÏã—G¯ëzö·< ;Øø. Žî/½áàs¿sèË¿Óó_·÷oÞÜû•·ô~õ÷ûÿö­÷ÖÁxàÈ?¼ýè?¾ǾöŽã_¾ü°úÆ#£ß|tüÛÀ‹;óÇOçñ p|÷ÝøÿÎãcß~|ô[üË»N‚ã›üöã#ß}÷è÷Þ3úü{F¾ÿÞ‘ï¿oøp¼û/váÑŸ}é£/}À…G`Àùï¿~dè¿¡ºð„“¯4ÿþû?þdôþ)ë¿ä±û‰Qì¿ÿ¾‰ÿŽmá¿ãÔÿ7}æÿý)v^£ÿ’õGÚ'°ôÇ®¡Û¬ûï†cøgŸ;‰Ž¡ŸÝ>±ÙqÇ6;ð%xÛÏootÞÒÞ‡÷ßÏÿEó¢±ÿjó*Ñ#®1$˜E›ýÏ/oX—DW4ÃãXžëŸ^ŸvMuyzŽÉSà÷ØôÚúüªkØå™êèY]ï_œ]_\Yž^½ÏÝ OMž:}¬ßÝén:µz÷­û¦Ä©fw—»©ç˜(LûÁÅfw¸³ üuÞ"—ÞEL»;zÆûŽ Èýó³+só0¡ÿÐr“p¸s¤izðÀOS¯Ü¬móxϵ®uNˆþÉ–Õ™àü¥Î‹Ê9áæ` ³®k¡ëòIßÃkgnÔIƒWÜò߸ڿ&ͺØï[XoôLì?qøê]þÉÖƒýs׃Ý.Ûs¥§i¨ÿĉRÇDÛ™ñ¶ýGž!¥hyw_l -*Íím þþÞáu±gqú°Ð¿pÃ;Óºvìp'ºü3?ÒßÑÝâ“fWšŽ÷\õè?6%tx¤éŽå†ÎŽÃg<‚§Áãê½Ö·&º<Âü¨WÖ‹EÿøF;‡@É'ëw®yOõ^óuï÷ßò¯÷ç¯ö,6Ýì÷z/w7ÝòÍ÷ž˜9²UÚÁžñ[Þ—§÷ļèNLÕŠ°Øñ›×OôŒ:ªWQ†ë•ÓG-‹³s—Ñ-ÊÁΑ©Î+ÝçîšX¯í¾|¤ßPÓ¹+PÐ}]óÁU?Êëeˆe¥{}@šmZ‘WÕun©»÷róµ£!÷ÁB絫­CÝ‚"NP2–/ò°dsÙ^ÁùÜÕ{ZÀ¦Â\è[9D¤^è ,Ü¥ôÝ5ÐlÒ˃u¡’8¯\¾80#{—/.{Z}›]ØLŠW&g¯ô/46¶ÌLÔMC;*´­ K‡ò{€¿ \º|€ð3 caEî³Övx¹ïÔ…ž‰þiü<ܰuÃ}¡ýv„0§_Úß*u×ÜÕá;û®¨ç§{&úN_:r±éâ„xôB·Ë«›ò°ØxjÒå9| uj¬ÿøþ‰›ƒw ­øCù7mv ÍQSØs£u‡Wg;ûåó>]uHí.OÈõÖþÚfizéDpð®K3W[o¬ °vpnåj@KÔ7¥7 - ìFmRÇràr§ \^:ä&Yh?;6o°äC“×gnn뛸°¤¬7‰'ü·ZŽH‡o­î89Ñz§0?3yDl÷*'¼×/v Çœî…å]TΟš>:Ø7wõøçl_H¦.ÈöN©'Ðv®>ªlƒKƒ§ÎôÜ8:wj³la¦Íƒ}=—.ö;âòÀ›®ÔÀ³æ×»¾¶¥ÎiéRÇù1q¶ýÎNaáÊþ^ЮÜ\ I¸EÞH÷Üuhífß\SûMØò×¹<ñEiv°¥ùˆo°IìUÎÊ—›åÊÁSÒnîæ>è=Ðvþâ5F¡Å©ÙÐöuàbßIRÞ†Öø‹ÙöwÆ7u—®îvÅ×Õ±2:Û'ø/ž:Ò3>sãhOû Î¤s¶…e‹ÒÌ@×0hf‡Oîº!zz¯5-Cƒí=r¦eé8ôÔîÞSžÅQ˜ãXÏJÿm‡t_8D}£5ÊúÐàðýjˆ±ío¼.¡s‡;½ëƒ‡†–B@òÌì=Õ°ß7Ø´pž¾§. ö¯VyæÊ]‡;';g{Nzûú›®ö¸<”Ѿ͟4­ë£@a²Ò¿pxº¹~íš×˜ÿ–Ü5>ÐzUú.MˆPñÍ}‹Ý/÷Ï· ô[`É:?ÒT×ÅÖÎÅ;Ïõ.y (çNõ{[G'•-m=[Þg¢€z9ÓµÛû:å¦pè´ÚC°‹Ñ {›=-¢ÿgÃSÌô?AÙtñÖK óOíÆgeJ W—ØÅ›Äb6%fÒâ§Ö®ý8š€ùºÄbvH,² ÄY/µJ"J WÛM ʺX4Û$Ö¡—Úc±Äißv°R—èMÀ^‰me ÔˆÞ@â´o§ X–XT&½lb‰öÊxš€™º8ÙÆâ¥£ 8Ò&ÇÉL×ÅÉÞ¸Iˆ«^¨ 8÷D¶ß¢«‹“½ñÈ&½@p¸?f« X¨‹“½ñ°&0½DŠ‹^ì2«s²7¾• $Ö+ãk&êbƒ Ä$1g££LÀ69n&`¶.±™@ìs6::ò†7ÁÚ› DUË&`“ÄœŽj&àhÌfˆ¾.VLÀN‰9…¥Øó®ÐºÄì3‹‹Òl׋ÓÑQÞÆ(1[L ‰™7øèÅéèh{Ð9íÇl|ö -ã³ùìAç´oÑøìA›õÂgòÙƒÎi?*à³ã¦>{ÏtNû&L€ÏL€^øìA>{ÐŒš‚§GÖZ[”%—§gb¢¡µÿØÌõñ#Á 5ðêƒðË)èk*>÷èÒôìüœ{òä¨~¤…ù¬JÐÝÔìž<ë꥟mš¾o~µ½ÿ¸ŒÎ¸D7þ#€?ðŸ,»Õ <· O͸šf¦g¯Í­®Ühv-Güî‹~ófŸ}ݽ++KðÊøàY÷À½7VV×݈÷ÄŠ»o|<ò}g×g–æ ÷£z îðwò×-—Ï-xI­&ïgò*øqÛï>é¾pIpÏÁ{ǰD—æ;áh_¹bɸ:úçï^œ;Òëžv] ò’dð¨â’[òùÜ~(´É+›^‡¿µ{´ÿn J\E7ûÁp‹ËãAÅC}vºýª$©®ÉcÙÿƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒÃ!ÜÄawP$%'§¤rD‰”ää$b)iY99¹Q ''+#-ÙaRrj†«¨¼jÏžÓØ³§ª¬07#I05³ ÊÓ¡»p˜FWPöÖUäA&%gä×tôŽ]š[¸|…Ã$./Ì^én©ÈMK&˜]Þvdæ7Þôއá0‡xãúùƒõ…ÉIÉiyûº.½î=ŸøË§?ÏaÏÜþìS­z˲R’’Ó =×þ‹¿ûÖ÷_ä0‹žÿÆsO½ñ¢\•“ -šÁ¢Æcëï{ö{ÿã?^ù1‡I¼òÃûÆg˜ îL/l8ºþÄ—_zåç¿ü‡Iüòg?üÞ퇺jrÓòëúo¼÷¹—ò«ÿü¿&ñŸ¿|å…g¾rJ0)-Ï}øúc_ü¿NÑwþï¯~üâçÑ$˜êÚ{ðê£_xéÇ\‚æa”`nM÷â;?ÿ"—`•à+p F.ÁXÁ%+¸c—`¬àŒ\‚±‚K0Vp Æ -.ÁXÁ%+¸c—`¬àŒ\‚±‚K0Vp Æ -.ÁXÁ%+¸c—`¬àŒ%øð3/¼òK>gÁ4 s€»ºý½þŒÏ›1 vÞLRjΞàìŸýÆ¿ýÏÝ2 vî`•|ñO=÷ç_pzVÞÎ;0)%«Ì;ºþÐSŸ½ýŒÓ3CwØ9¬IÉ…õϯ¿ñ‡œž›¼“ÀÌ£¾#9-·¢¥{äâ,ŸËoì\þ;’R2ò*ê¼2_O ˜õ$H„¹…e|MST`×4ñuu–À¬«ãk;-B_ÛÉ×[–Ç3°<×?½>íš<êòô“§Àï±éµõùU×°ë–öGt÷Üp îðWt èÏä}.EQÝ>Õç¾®Q‚WòK·¢È^Eç}Jüð£ÿû\’" jÈ%Éx§„~J2“ÿðÁ»% ºR~¥"¹iRIPÜ0GøŸ –©!-þ„lѤø‡„îÆ¥ ¹zg@ÕšN//O_ŸŸs_^ž[œ_^wËB3ªc{ÖטüÛ{ÙÕ.xŸ»]RÁ_QòƒAÙO‹~PT•?y]»°ínˆAÿVwüÁ WU%¿»wÖ öªŠ Ê[g.kw_§ÜˆîvŸêDŸ´U*_P×U=UD¾ †G €§Þ^¾$‰î0þ39íòs Xj»ÂZ\ž©ŽžÕõþÅÙõÅ•åéÕûÜðÔÉéµkˆšìÿÜè/ð?Æ[È«àÇ=n¿û¤ûÂ%Á=ÎNŽ¡ut“s.E«ìi©vË-ÌDðÁ5¨$D>Ì>(ˆŠŸ¬)š]Ž—5Éh•쟌~*Š‚–5¡ø^Ö¤hËš0%xAUvÓ¤à ^Žþ×–c -/Çw¢_pùM‰àÕXº+ —MRB¦ðb,™.Æ’Á̓.ÑÝOg]w‘[Ì0´ŽË¸Â‹,Ó"‹Á†\!kÄØÕcÚ¢2\*^^²þ̰2,/#‹Á†\!kÄ «Çü–—-¸ZNÝ"ýèÊÖSöGo`<'éG5 Â%uáÀb_¤’ †Y -פx}I (ÍîŽñõUàwî¦ÞÞžÙÙ[×ÇVÖ§á­ŒƒéVÏR›fLÝ¼çØøàY÷À½7VV×ÝCÓ÷ͯº'VÜ}ãã!ÍÁ&÷Y\[>o¸_st`ÂÐo}X¬!úÂKú𲾑«úôu„¿²Ñ3¥¯m´‰Õð.¢^B‡_á9!*†td%ëõ€)zg,£^뙊fm,¹;ºÕ±PѬÕyŠn…¬iî´5²ž©Ä[o/ü/·öL…>9v§Uñõ³q_?øúYkàëg-ƒ¯Ÿ|ý¬eðõ³VÁ×ÏZ_?k|ý¬Uðõ³VÁg™Y—œUpÉY—œUpÉY—œUpÉY—œUpÉY—œUpÉY—œUpÉY—œUpÉY—œUpÉY—œUðõ³VÁ×ÏZ_?k|ý¬Uðõ³VÁ×ÏZ_?k|ý¬Uðõ³VÁ×Ïr8‡¹~–®—‹u-”¶XÖ3¥¯È3Ö´­2¿lv“5 endstream endobj 1824 0 obj <>stream -|dé,^×iñ,¼K¡ëšÌ, ÕÖg¡%´x}V„E´è&fyVÄ…´z-`‚A¤Û~fÍÖu²~ËÌ¢Z¼.ŒÔÓÌÂZ\Y‡ffq-^#F*jf­q\UÖrZ³ mé&k*"YKÖ¿K—Õ-o±¬®g.CËr{޹{n­¯¸qk±øóúú\â¿s+3óSЋGfÖæW›:1ß¾i {uÇäÉ¡ÓÇúÝî¦ÓËóKÍnäø¢0J ¾/‚KË+Ën)¨%M–ÚƒÐEÏš±# ;té³ea†]Ïhz4#Ï+‹—¯,¿ëad*iõ«~,С^ºc/ZáÜÞîÒWE¢3."IÜš‚FI–Ýjý'¸exvhÆÕ´6»zkf}uz4ßC[™“Î,{ûfÜÆy±vü„Â=.îI앃ª/Úw¯,ú$6ø² ª"|øQòá§ÑBú1óŸYèÁ Äu µï:H¿ëà‚õƒ¦}ƒQC®^s™^BBòM…±‚¨•Ngô=sk}ÒÚéÙùÕ5S:ÇI¦hçôÞ1~ßõ™•¥cËkëÓ˳ó€Ñ¦áù{Üø¬[lv»µ;Ææ@r,†v´¢ªÄþí›X^^[XY½~r¸è½®.׿"ÐÊfz a¿êaøp€eN‚uNíá tš¬-Uvެ'9ÀZp¿pšIušYqÚ°/ >õ'9À¾à$X ÈÕ‚“`-8ÉÖj—Õ‚“`-8ÉÒæÃI-8Ê*ÛQ°$Õ‚“`-8ÉÖú×Q-8ÉÖ‚ƒh=UûZOÕIpOÕI°ìhZp’¬'9ÀZp° iÁI°œä•ídÿkÁQåkÁÁþ¦'9ÀZp€oЯú)¿C ãfl8Ð2Ø}N…6cÃqiÈNu¼>Q©m¨NE lÈ‚S¡g#>i;°¡)ÅnífJqœ ¬'ØØÄah7 Òð;œ7²ôm 6§^yý>‘ô70-q°ZŠ™YUÝ~Ÿà¾Ž)?|§®~–òÁiUä¾!W˜×ÙÃ+sóøG4»ÜM÷^_Z—Û§×Afn­Ï“I1ú4æ®Ù+‹Ks«óÚDŸ»ãØòº~þ³~ßy|UŸ%Â^¿{zé–vCÓõùµµéË̤Ãðít½µm›×izi}bú²™*‘;­Q‡¨Jà¨Èâ&÷±5»¼ºr뜹jôÖí®­[«KfêƒnÛîuYŸ^½<¿n¦:äNgkÔ´¼²¼•ï³õš™ž½ jyÎLÝØ»­T¼UÅfç—–&æï]?¶vtâä™Ê…¦p¶‚‘Œ++«¿Ñ³´xyÙLÕ˜›·w­àtrÓµbnÞÞµÂwšh:ô‡s Ç=Ó«Ëhî~Ķó¹Z†&8·¡òñ”Ÿ?ÆGIÝìÜôútûÚü,žÕQ€má¸ÙÌö¢á†´zNó±¶´8kÊš´ sB§Wç§ñ)) È -áÝJzJ> )æ§ÁÝWæñ¤iãÙ{çÖ¯à“pP ½WÓ9"hgîÛ0{ê^©oj–¨©)IÜb.® ñŸ/Pæ#7 ¬Å2QW‚3³7NÎÖ&ë.LÏÎG5UWKàÜDÝ[̼éHûá±[û„nìC¶õÑ6õ;Ò ÷ôaöëñ´T÷% ¹ [”7ÚÒg³àorù?” ÷ô1îèþÈpK§ spppppÄŠ5Æ–ïáàØ¡³ä>ª{6½3±UáØ1°l'q2°0Âge·»–í$F “ļÇë‚ãØE°l'±XøTQ±M°_¬; -–í$³j­qDœÅ̱­aÙTb±±¨Ò& <Ç6‚eS‰ÅÆ,¤M҇ðl*±Ø˜…´‰„Cªàp ŽØXâ N«…#ÑpÄÆ_h´pZ-‰†Ó·Má´Z8 §-n;Âip8§n;Âip8§nÛÁi…p8§ín{Áimp8§M/¡SegµÀá8lŠwX ŸnÊ­Éê$T ;v™¥ù„ѦuH0¿vH€1o4i I¶Jk¹¦‰O{e-çc vYu,³gcˆÉm¹ß©„ᥑ0ÄÂÏ.®NâM%*b)%LYÛ3!‡#ˆÅÒâ—pcr ¥D,4Á M¦âp -æ­1ª´ñ(Ô²MnLžà„Q¥âp -ÖŒ9LÚøÊ#~ˆÅ6MK¹æS™,Åñ„Ѧâp–ycòXÊ*UTqp˜wŽ;bv„;ìèxD•–;G<ÀƒãŽéÜ8lwŽ;v¬#p_à°1:‚- ͧÑg98¶ÂŽvî va£i%À,­ºi*Ë‘ø„Û–ÊÞ„Ó†÷‚hÍ2ñ 9¶3,ÛU<†IÉ gÏ–rlgÄÉ,-'ܘÜd’0…Fd# 9¶3¬YW,fi2m´°\ñ„%䨶°ÅÀlOh–k˜„qE,J±×Àì2K3icñšO²S`—Æ-Ëgk³µ–¹Šw“$>¡É$;ÖmkçÀ²X“ÐrGF•j!Žö·m`Y,‰Ih9IâF•dÇ!¾Vè4œ–.ÇŽÓ¦_8-]ާM5¾pZº;N›j|á´t9v œ6ÕøÂiérì8mªñ…ÓÒ5…Âçî†Ó¦_8-]SØA¬îb8k¨ñ†ÓÒ5…Åín…ƒVš8-]S؉<ï>8bŸ‰„e™$&¡-l'>áîƒÝv·í`Y&‰Ih Û‰O¸Ë`·ÑmSX–I¼ÚÂvâî>DoS;Ö‹0c¾…Bp·Â„íX…ƒb´\hœîzØ­Àm -ËrpP†–‹‹SB3¢ØéHL5£5ƒ¨î· ßˆÆX»Ø¥aY€ñH•48Â#ZE˜LUnf˜Œ±v’lsXGXõnU_ æ™88-¤]ˆXä¼[ug‡©ÆN‹gײ¨w«îì³Ù¸ÀiñìZÄ"çݪ;»×N8-›]‹Xä¼[ûµ NËf×"F!ïJÅÅÍŠm€Ó²Ùµˆ]»Lqq6äXá´xv-b—ð.S\œ 9V8-ž] [Ä»k—[Ž NKh×ÂñîÝÅߊm€ÓBÚµ°K¶ÛJwÑš #¶q’‡]²µQ}¶$4™Ö^+M¢‡#ˆ]ƒ–õn­ÐXÒ!˜” ‡SˆQ}¶' ŸÜŠ nD§'`Y‰ñK¸1¹É$Ûvêì×ñ§5=Z6+6ÿ²0fEqhˆ“<­)ݲ©D•6–RL—°„a•Àâ$ÏÍ,|1–nòfËÕLdB3I8L""ÊÍç#æï·\P"F•„à ¶­#°¹ÅȆ…ä -JXBŽ8ÁF]Øë¶0“˜‚œ#°KÛÊ 88¢…-¶Þ ¸#plÄh±]€{ÇŽ€KŽNW‘ƒ#2¸#ppÜÁƒaW:‚…B¹Ûþš#Ž`Ù,c¬Q´÷sGøuÆ6t[šO#·»q´þÄš¥µBcaucV NÈa#ì³ôȰÆOŒ‰Gª0Y%2!‡]ˆÍ®£†e~b¬ˆ½©"f•˜„6"’寖™‰±1&‰J’ HÈaLƒí°ÌIâkaY’ñNøë€ÄH#®ö³Â3³o±WÊB­-—˜È„&“ì8˜WÓŽƒS’ŒöþXR9’0®âM¼*MÓŽE\Eg#,pk¹š¶$äØAˆJË;–k{BŽ‚hU¼Ca¹¦±$äØA°¦e3pZ·fá´¥ìr8­^³pÚRv9œV/‡)8m&»Nk˜Ãœ6“ݧ5Ìa -N›I¢a¹Ê±$äØþ°¦ÜíkÌ[®uŒ 9¶?,(×YĹS 9¶?,(×)Äμƒ 9¶?¢Unâa çÎ&äØþˆJ¹¬Š-'Œ*­]Ì;žcûürï°µ…´Åœ,g’ø„;Öôk&UðŜ,çø„;–ÍÒr­rˆ…yk©¸s°°fÌö:‚-<[KÜ}v%Âs›Ih!¹-<Ûž0Lr3 slsD4 {a¾ÐØy¶1¡™´±ë‚Ã)˜4 Ça™g[šOw…qÄQÆv€žc©¬…´h‘#fX°Ë5µ&(çôÉaÖlã× -Öå¬Z9¢E<,g÷Áš œÖ-‡YØn0,œV/‡Y8m)»N«—Ã,œ¶”]§ÕËaN[JÔp„gk…:­[Žè`»ÙÄ òl­P'”Éañ°Ûa ϱ$´6ÑŠäˆÖlÃBª;ì{9e­h ©îà/Ô~møÃj÷f×ð̱ý‘ÛØÔzÀç.)¬hé½tó¾›—z›Ër³€OÔì­)/ÌNÛ9f%P¼¯MíRÛöcÆ“’Ó]•Í]ÇGŽw5WºÒQ]@£—ž_\Rœ¼#=§¢µïâò­å‹ýí5•õ]ç_õàã¾ê|çþ"WAù>O£g_y^æÎ1ƒ¤”̽=#§Gz:ö"Æ“SsÊš½zóêÙCMe9©Éè¶ô삲ê=Õe9™ù{åSK¯ý×.<îöc×ßþÇŸüã·_?Ú\^X²§¾µ½µ¾º(;u§˜0‚ÜŠ–Cã³WfǵTä3nPàL¬Üÿ–ûW&îè -Àý3óJ÷ì¯Û¿§4?;»pç™›àúͳÝÍõ¾‘õG>þ™?²>ì­*.ÛÛÐÞÑÞPSœ³c<Öw¯ïèÅk7®]<êÛ ë›”šUÚÔ{׫ÞöðÛ^uWoSiV*~Vì«o¨ßWQ˜›SèVG¯Ü÷êû®œ -6Ö '–~ïýyÿï-k«,*ÝS×ÜÒ\W]´sàEûåã¯,]¹x\Þ_<øAEÛàÌ«ÞòÀ[^53ØV‘“ -»?é9E•ûêêëöU¹rò«Ú{&îš¿k¢§Ã]ÓØ}öÆëÞøºgÔ—ä–íq׺÷”ågîGHÍ*©SŽMÎÌÏLSêJ²R“kTu¾ûõ¿óú»§vTaçHÏ-ªØ»¿vÿÞŠ"Wvnñ¾öξÁ¾Nïþò’êÖîás—Î w·Tæåä””———ägbRjvI½rdâÂ&Ž(õ%ÙP®jáèÔßxõoܘ:*T»pûD°gŸ{ß ‚¬ÌÜâªÚƦÆÚêbWnAe]»_ñƒ¾Q~fzFVŽ+ϵ£úFPuRßðÄ™‰á>©Žˆ £ÿÜ•›k7¯œëï "(,«ÚS³§ª¬073==ËUž®¬ôôLp¥²ªœÏH…ÝÃôŒÕCŽP´¯½«ÿ؉cý]íûŠ#äT4¾037saø@sEv„ìü’òÊÊJ`ä9 †©i™™™i ® /:ÓY 7Œ:Ñ);kœ„;‚íþ@0àÇÝ|Ðf¹½O <àu©€æ09-37¿¨¸¸¸(?73-B«*®u*©wRÒN-à -çƒV¼®®¶ãYpô›œžSRãiõvx[=5%9°{ˆFÄ œ zÈxȚw^µ €žœ¼Â¢¢¢Â¼ü$Ã}á²ŠŠŠ²bÒ´¤¦¥CÛß¹µÝ`ü“–Ž;=-…ŒRÓ3³gg¦“ -C{ǶŸ.^Å)›Ÿ$h[2!‰PÝØF žIME1&†ZXò&§hy¸E¡e~6­”-™l"N£Xp¦[ ´™Y™L Åä) ÉÊÊÆÈÊBÁšdô`É­ FNŽöˆÙ¼®6dj!ç6FÒ4Qé?R2r@× (Ïh‰| -È$+¯¨´¬œ ¬´(/;=5w<öÔ`ìAŒÔd¨ÉÐú0vs&Æ0!hèÒØs@È uH7tó‚‚ÓrwcS]u!›:ž®9Å{<-íFG{‹gOInfV~EWvÀè -Ê^ðŒÎL…‘8W^>êy‚“6d¸8¨.¸ž“™ÆØjZv~Q‘¡£m/- -Ô¤¼Q9Üh©Î×K¦NÁ1I­xèøÈØØ8ÄØØÈñCbmi^~UK÷ÈÅÙ…ËW ./Ì^ƒWffì’U ®YFFNì™°uKÉp•VU—èÃ[Øe¬®­ßWæbC‡©ÀåÈC#9£À­?{æ˜\[„D¦N>G^xôÒµµ{îøgíÚ¥£¾}¥åžƒç×ßøÀC`<ôÀ×Ϭ/ÎÉ)(¯©­÷4`xêkkÊ r²ócÎu¨ÆsJ÷·´7í-¦¡CÀçž¶À¹©’ fää廲ӵ®Cfqãá³sÓ£ÁºâLô6ÁÜ)06÷¾tÏ[z×cC<ö®‡ÞrÏ¥ÃMÕ5ÂèúCO}öö3Ÿ‡xæögŸzh}´£2?¿´¦¡­C1„޶†šÒ4Š´ÔŽ6”±3èW‘“‰Sii9eÞ‘µ‡žúÌí§ŸxúögžzhmÔ·¿þÀìŸýÆ¿ýð•C¼òÃûÆg˜íÜWTTUß¡tèÆ8ЩtÔWTvÄš‰nàšIŸ™½kDÝ_Hš¬œ*ÿéµû_»x¼­<›XFº«´f¿»ª€¯T·(A©¡² Œ›aÓ™šùTNfnyÇØ=ïúÄç¾øÜ—!žûâç>ñ®{Æ¥ZÏÁ…‡nï‡?ûå¯ ~ù³~ïöC ÜÅÅÕ!pàà!Œƒ‚§º¨°Jˆ5“ª|V%M½ç¯,LtÕgTËçî}ËïÞ*st”í­«ì ©Y…Õµu{Ë -ò -àùꬴ´È§Šró*„±{ûäí/}ù¿B|ùK·?ùؽãþº†C—~úû?úÅÿùOˆÿó‹}ÿé‡/wCîÄ`÷¡Ã‡ºƒbk&FX°í¹Y\ƒF RPi©ÎËHMxj°á˜h¿Xi Hï)3ËUÖ<>z,PW” |?Ò©úÒÂÊí×Xz"àÇ$?g앎_œ>ÓÓT’•’ñTsyaì¹íOKýÜ_„±†âºàèôÜÙð!‰xª©¬ dÛõ ¬õiÚÌ¢ZùØ™³ÇwA†æEáNÁ·ŽÛ®whqŒ@Å—_Ýè9¬4–ç`—‰pÊ•eC÷Þî1‚µ‘¢.«¢êº¦Fw9q™H§ÒìäÙeKàÌæ÷ ß’_^³ooÍÞ} ¿ Í5Ê.ÙרÒÜØÜÒ¸¾kFÊË„¯V²¡ã"1¥f—Ò‘€f(&NÙ8c{5vHök[½í­íÞÖÚRô99#¿¦=ØÝìê¶×ägÀS©°{œÜH¥ç“‘@iŽ’d‘OÙ8+±w%µ©]A5Ø¥¶íÉOOF?Oçñ‘“ÇOŽïô Ž~rZV>x°—åg¡—í™E¸Û*—ƒÕɦN¥Ø8cF8¶ˆ %£Ð-îï;Ü×Xr¢éVÙe­}§/œ;}îÂé¾Ö²ìTøN(§°t@ÊÊK sàŸtûO¨u¥®lØ’Â(YÄS¶Θq®="\*ýÇŽô9Ö¯ P7A…÷è…™© S3Žz+`YYQ^Q‰HÚíW[ö–—–Â×Eéi™‘OegæVØí°Kuêà‰cƒÇN ªuX9Ç/ÍM_šž»t¼Í8ƒ³­ˆrÑŒóÔìBÐíoªÛ[½þW]”žŽFáO¹ò*cœÅA¬ÍÝÝþÒÒò½-*~]”™–ñÔž"g¶‹ÀR[@zTÙ®Ò:õ„öº(5%ò©ÒB[c^¶ˆÀÚámø“žSÚÔƒ_JNŽtª¾Ô†À™ÝOkýœNT*%¯‹Ð}‘Ní+Ê‹=pfs¿Àjï&&¯‹Ji´=Ü©²\›c^¶ˆÀÚ$&/•*\ú° Ü©Œôìm7F°:RÔk/•Jõ@køS©)vǼ쑥x–vC 5ü©ääMâp¥KZ¦ Å `¼À•™ßBÐhŽ ®Ý25Š<Ûh { -Ž”B¢Fp6'è9§gfçBmçåÑpRVÔ‚!êã~(m³!l*“q—M­aOm”jhñ9G-œêŠ®å2w²BÓ†F@(³[K ™‚˜}2ŽÇ*³yΛîÔ†ÀrÍ-Šós6º…80L'}o…ШxÒV±Päø°¥OM%¾g Âé¨ÐéœT,£AÕØ83b‹ÆÑ­©ýÐP¤¥o…4ÃTaX§t8ÁvÞZ²róór³³²…e¦¡1PFna1|'îÊ/ÈÇ1 -Çse6,äF!3#¶xD¡=0+rÓê@ï;gsd‡NøÌÈ!•Ù(Ü¢Ê=ÕåEE¥e%ùprjVAÅ~¸«¬bÏÞêøtCN˜k:c$°!pfÄ%#´nSQV:Š»o- -ODŸYPá®sWd¦†úhrznÙþV¡ÍSSµg?¸ŒîÒ2 jÚ:u‰µ mÞ7è¦hB„¶’ƒmÅ¢BgFlÑ]6Bë<{Ës2³ròÁ°es i=úœ× P§àÁ`[MAè /Ìé<$5¡úî+ÉIÏpU{ûÏ^š½Rg7š6‰_Ua"ô vœ­R²J Ã$#¶4¡ ¡äjè4•èoÕŒ(+)reU%§¹ª:ÏÝun°£Ê¥M™ Zk±úOŸ9ÔÑØ"øÚkË\™YEžCVï¹:qHî=à­)–‘ úê{«K \yÀ¬‹ Û83b‹¡³Ú@:X“—“W\VQ¹9*ÊŠóH÷ ÍìŸ}Õ^5Û'~Ÿ×ûƒ§æ.Ÿô56!+ÈÍÌ)kºþ†7Ý{©O–»°À÷Á°‹[^èÊ‹Í -²3ÎŒØ"€b„NéÚ›Ÿk?ÁŒ&` ´/xá5}ð±×\î#o9¨ -ëºÏ\]ºtD¨s×Á¶ +#§¼ãÔÚï=ð[S=­Þؤ§¦ç–ÔÔƒ² 7'7–¶ˆÀ83b‹0šZPí@"HÍ.o;¹öè§nêѵ“t -Yˆœëk«Ak,³ÒÓ²±Üs¾«aß>ôDHMIÓ¬ ?uÓ-?œ°¨çÚƒ³oùøßüÓß|ü-³k 3 wÜœîj(/Ã080ÉDmÁÝWF|{K‹ -Ñ£>'A[PÄ:ÖûŽ´pù­oüUO>û—¿ó쓯÷Uå²-¢öDèîØ[˜ :Oð%=h=½ýg.Žj*seãIx©fyiAvZJ,½C'žpriãÀµ?ûÿþïÿýŸ}ðÚ@c ûu­_ÐÑZ[š‹^[£—^¨_lß“½õ ´·iÖiNô €JkîÿèW_þÑÿþÑË_ýèý{ó f€{‡U0ÂAÞ›ãÞaÝ´ŸŒ›`` Ðbª;Ð;„FÐ|ìæc·¿óƒŸþâ§?øÎíÇV·ŒhŒÇ>ç´1BQ>û mŒk°"ác„¤¤ÔÜjåüžúÛ—ô³_üìG/ÿ퟼ñ¢ZãJcE€GŠl#OFŠgœYA¢GŠÀî -j{®¼ã/¾öò~ôÊ~ð¯_ÿ̃×ú=E†}Óg8R`d?–V€f²Y¼€‰l:íÆ: ÇL¼<‹\èS_ù&h\_xþ›_ý‹G׆ÚʲBG -¦Â«]´Dû52F„6Ÿ|eusô–b+àb¡úÞôOþÕÓ -}ú¯?õ¡·.µ»G„ÍM+ƒM¾fâTâEžïL,¿þ­> ÛÒßö†õ‹=ø -†ênX›ªEÎŒb0F›ÙÙÙì¬d3§ípuEyS×Éó3¨mm饱>a¯qÈLÚCÜ+ ª‚í¡¡d Œ”VàHw²éS‰œ‘/4»Pn]ªØTSlüà‰œe¥“=œåd¦Ó™×$rFæ8¦fïmö¶yª‹sµ¯×˜8•”ø‡â¸g[Y­c÷TW”äoŠœ•äj³f“Hälo i+qä,#M›E -¿‡$öž8ÑãóTâ/š™9•ì@àLûü– £ôÆÇ=‰œÕWäåfâ‰D8r&ÔU¢˜6 Žœeio2R³K›{Ï_]š;äÅGK2q*%tÆYBg!Ór7¼ä ‘3_}UY1ž·ÆIg/Mô u5Ueh­'Ñ¢WZ©9ÞW_ûæû×ïjðW±"ŸJu(pî‹9;غ¯²´¾\NÉÐ"gcÁæý5…ðu¾6Z®.ÍÏÎDÓ€S³ËÛO,½é]½õž `Ÿ;ÉÄ©ÔTGga¡Gμû*J¤di‘³‹[ÜÕØ -’I̤ [û”°èžÙûûÀc÷/ j³q"ŸJKu"pQZäl°½¦~°Ô.GÎ~óRwCU ZZ[ 9+Ïϯv¡õøÆÖßúØÃ¯Ÿl-‡ÓÒLœ‚"H|à̤œëm©ÈÃo+‰Ü}.à.v¡'µ‚²<ÔyKÂ3’ÝyÏý¯¿yþps9þZÄSéiÛÑ -H䬳¾$.“3´ÈÙ°X•‡»4I4r–›® ˜“Ór+½G.,ÌŸ;hD“À’"ŸÊLÏÙvm9ƒm¸ÖÓ"gáL#m%œÑžnfá>áàààá€×SU˜…£Negä”:ñDˆ`Zäl)™ÈÅFÎô%VLä §„=¿š†ÖÖæF:6)⩜ŒlG^¨E9£ï IäLO1‘3݇²  €7âÇFäS9™Î¼V(k‘3P;ø»Ü¼Â¢2Y-Ò©´g‰z¹A–#gx¢¬a6y¿ñTè*ËDM±ˆ,k‘3²À#HffZ˜SWY†4b›®¹ ™gcm¢MlZ9“‘³o>E8ºÊÒˆ­Ö\‘cuºÕÖõ “ëôˆ <±a¢M–ë☘~—™S&t—´qÍ¥¶NºÓ¦Y¢¥D¤ÚÉxfR*;ãŒJ¯cÚÑȧ6Ü6Óœ=ú5#dô9ÿ\ØóÇ3Πfææ惮1q–Dt©Ï8³9Ûv€3ÌóŠË++@Z›qš"øÕçZwUI^®«OÒ‚v¡}µµÈ™ÓÞ¸Ô¢ rSksmuIQqYY œ?à*Ûß&o}uye ž_ºE9.ÐwÈÊ 3Î’­Eζ `7°ºA 蔚÷×ì­­sWºòË륞£'ûÕ¶ÆfoG«»473÷¸0/'[›qf1r¶ÝdãË• þƒýGŽô¨Þ¦ævoËþŠ’ò:ÿÀøÅ»¦Îï–ÕîƒÖ=…99y…0ô_VœïÊÃ#…k‘³íö™p4Jô:rüäðñµ£Ã'ã¯t }Ss—¯Ìž=vè`__7Ð^@èäW–Âg)Ö"gÛLpT\ÙÚudhèäèð`—è:Zk«÷4vNÍ/\¹våÎážîÇ­5Åù…%U•UÕUå%ùx¼hˆ‰µ”e…†É¶:åt­ @ó„ž¡‘á‘S#ƒÁ¶ÆÏþêòê–ž³ W¯^_¼s¨Kò‰­ûË -òŠÊ@ý¡€'¸p[ ÇÄ^7×ß\š•†ÉœrºÖ`ôÃ1ÚHŸT¿§ª¢´¨¨¢¹gòÊÊÊÊÅsýBC­»º4?wØqß<+‹L?Òbbhgô…8s§¶Px¨µûø©‰ÓCÝm{€†ssr‹ë:OÍ,ÝX½1?ÖÙPUZ: ™Ùù%ð…ÔžJ4)÷ hälîl?yMiîÔvlkŃG‡O ÈõðÙ7‚ªööŽßueiñâ< `·1 ŒÛJ+ Àºô )ZL¬ÿ€PWŽW£™;µ¿³Q^ç êë ¶îÉÏ„¯àfOœ>?9Ôé)Ñ>:š™[P\Z^Vœ—…^:âä8&ÖÒ\¿·¼@[ÂjîÔvúÚJ§MZÜ%¨+ƒ¾Dµ§Qì<|8ÐR…‚Àh|›‘‹l`ÇÄJÑNú‡¬"ŸÚN€ßÊÉ/©ª! /pŸ9¯¤º¶±©¾º|ÛŽ&aÔ'$‡bbhˆO×»˜;µ€wt±¡a4vt–”ç3öÆQŸÐIwIxs6>cîÔ¶ŠŠÖÚ xйAåI4ŒbL½qønîÔ¶BÒÆÝ“6™62Óˆ=»ñ̶­ìØ$2L'[ïÛX³kÿ¶´{™¶h4Ã:`8ËHKe'œéF6mrhA‚n)ÂïÛV4pã¶šÇj³Ü,mÂY놉yzZÒŽ´ì74õ´‰¯_dÐÀèôhßãKÆÛ¥Õº«@WP[‘¤ÎÒÓØH°ž–„Ä’ô´9¤#Ȥݎ2 ³¦ÚÊ´D¾Å(E³öÚò|¼c Ѝ¢Àü^“6‘M›×?ÂדZZú’NkuAS\AgA_cu1ú>BFfnYÔsbäd¯ßSY‚椥j†ºÐ„3-|JÒŠ ø3pIëÛ_„ÆðsZZ“ïy -=p6xÈßP] -7EËÉ-©•Æ/NÝyz@ª¯©ª,+ÈÎÈ}%8+2È@o’Ø´>¸÷lD²Šµ´}Þj´$z I›»íƉlàìä±îŽý•e`hì*ÜÓgÓcÛj÷î©(ÊÍÌÊųŠÒä.xâ!I{ô@k¥+ O?ò¢´—ï âu`hjN[’·ý¢èLà ˜®T_UVR˜—WR™š_¸|uáÜžw˜“•¯Î`È„.â"i‡z„øA$¸NK;öpþ RjfN[YV° ÈLàl¸Oª-/ÌËÍq•5F³¥+çû½ûÊ‹á¼Ü8‡· -‰ '#]{A¬§í‘à§ÔIÚs=ä›P$í¶œ ÷tì-aFNi#œ­\9{¨©"¾=ÉÈ. ³‚ìt3aÓFŽ·ÐÒžé®/Bß„J£iKíþ‘ 0δÀͲSÓ2 kIàìT`Q6Ú;1‹΀?£˜‰1msyN*v’vTÝ ãìzÚäÈ\%†ÀY]1ÜQ3%ÝUEgÞ*W:úxsF œ‘CCÒjÑb&menjî,1i·™„ÎÐæNII©™…$p¬/FÛIBUê3ÚécÓ¢Åà(LȤÕ>ˆ·1ív†Àd™ œi_îegtâ@ i·Bgwlœ‘y!g±¤ÝNˆ%pcÐmû –ÀYlA·m<ý)$p–œ’:çn³€X,i·6 xšøÆM¼Yvö²g$mÜZ›ófœÛ¶½ÃÀ±5Ùx.ýÞ!³ƒ6»Rs¿ ˆðIF6P§³ñ3ô}Ôõ OvÞvêæC=EUµÍµUE8ØE–¸*d ò;H¨ÔŸïn:Œ$´ÃzWß`_Þ_M ¨hé9çy4ç}ö# õƒÊ+âñõU‡¡…zÎÌ^ž=ƒƒ]pmRaýÁók÷¿éþµóëqðnÍ^^³¿v¿ýßàuh„ÛufùÕ÷¿zùL -vÁjÞ‘µ?ò±<¸6âEß{€î·¢oCÑoÇáŽu 8GÿÌ«ßþÈÛ_=Ó#=)Ù•þ ÷äé/?ý‘û/ø+³Ñ”!0.Üß*Jbë~›¿Çí8Ð'oŽ,üöÃï~ø·Ž4—àͪ”;ßô±/ÿ×?ö¦;•*¸¯&A^Em›$Kmµy»N¿öVÀÛþDàý‚;xï‚øHb‹xAо)"¹o·Æ 6Ömw×—ÀãXžëŸ^ŸvMuyzŽÉSà÷ØôÚúüªkØu ýÜ#.Á —K¢; ÿLNƒ‚×'»ôgò>—_ð»ýAÙ}]£üî!—~³” (rßkÁå™êèY]ï_œ]_\Yž^½ÏÝ N5‰^YÔ Òìî__]\¾ìnêí홽u}le}ÞÚìn7v¿ ; d§ b%-c üf)+i”MÅú@v**Ö§e,ß,¥¢b}eS±"È.€ŠµŒ%𛥨XQ£l*VÙQ±‚–±~³T+h”MÅBSñQ“©!锚”ÏÞbEZ¬@  èLÙRìéÍ3Aׂî¦f÷äYä§¢îsR@Ö|SÈÓTÅ@!7ï³…S)à×|S¨U5PÈ ´ûl+VÒ|S¨5` h÷ÙV¬Oó9L¡"Ô Bn Ýg[±¢æs˜ÂE*ˆ(ÑNŸÃ¦â£&%RCÒ)5)Û|ŽFŠha‚‘ÊTB}NðªÌ£NRâv -u6Y5PÈâ€öÈH‘‰Û)ÄŸ%9` 'h÷ÙV¬Ÿ¸BüY’ƒ -y‚vŸmÅJÄí‰!(ä Ú}¶ë#n§øh¢Bn§Ýg[± -q;…Ú:2$òQ“²Ïí´ÂH±-L02@™J°Û±=LÔ½Q³°¥Š¤§HçG§Ô0ÌâªÃ^‹Š$Žî÷Ñ”AÒ§a¨0×{Hª„r "Ф ~CIsf¦úIKõÓ”*éÜ1”?bnÀTU™tU™¦TH•¡Â4W–»)ð‰§Õ -« ^Õ©ÈŠƒ>¬8•¨SAò`d¨HŠCO¬¸Q ¦äáÊP‘‡úHqø~?M©’CERêȨ2éy¨2M©nCÙ¥¸Ðg@t'í -k ^թȺƒí'ÖB´ƒ© i]*¢î`Œu§í`*@Zh†Š¨;ø ÁºSˆv0¥’Ç CEÔ|bÝ)D;˜Rȳ’¡ìÓ±Á£Œ›8QÚˆX¡M§NÉ‘›8Ÿ–jÁ­½Èðᮑb "yІ. eU¥¬ª´âj€¥"›3i¹QuªÔèàU2‘›H &@Ô‰óÀã3‘¥"›_€³JYç’r¤—™7?åÍoH©sDî‹Ô -óS©q0²²TdóSi#@µÆæ4P‘µ jæ‡:šÈÀ0…»‹ªŠd~fI³” B™Ö[¦õ–©å KE®7|<ãÜj -µ`xU§Läæ#Ö§PÛP¨ë:Ùúê -µ9†KÑ@EÎÍGlY!ÖÊré3P¦:SØ–ejiºì‘)Ù–Ú¢P­1ùÒ<ôÚÇÞa {‡]}lïˆÂ\ ”ö¾¡IVI ¾ñÀ}4•öT•¥"÷”UÚãSiR~Ú èTäÜ´§¬Òž2ʃ6ë:¹§¬åAxóÞ$ÙÀ‘^VdÞ$Ê›dH©sDî31•èƒQRBd`©Èýn•Ž¥¨ÖØ|*²Ò§†oÂ0ˆÂ²W TÄ>u @úÔpì{¼Òò °Tä>u@!}jÈîS#*H8b¨xõ©"mþÁÒRI–Š,í Õ]êR~Ú#Ô)¹Q›R›GyÐ~¹NE¶y-›Ÿð&ÉŽô²"ó&QÞ$CJ#r_¤ÜTâAHÎJˆìU–ŠìAAÚ*R­±ùª*òèAÖ<Íßðã>µ_“=¾ªS‘<È/¨š¡°§„gÁøh¾*KEô T¦¤Þ$•ð¦å+({<¨£ç˜(NÌß».ŠîŽÁÕùùÓËs+î6à[à×ôõùcËsó÷‚ßøjoeõ>ò»Ë¦€ÐúoÎ¥håF=Ý Äú‚T /CÜgQ Tä 0cA$Áä´|ƒ*ò[ Õ-iïŒDÞDÊ¡¤pïŒã¢65:µ‰6ê, ÁÇ€@ç`M9Œ :ƒ(†¬µ|*ò[D…è p¤é ñ&RŽ•x)ѺšÏFWC­‹@§Ý tŠà'mCE~Ñ£jjCí¢@_iùª*’Ú`™’6ѯ)ó&RŽ•xµÉζ7|­ƒG/Ò(I³°”=¯ -Ì‹Æï`+¤¹üD.ˆÂ$Õ@%Z.’³ž®h¢QE\yLáØ®b ìÍÆ7yÀ@倸qàž×ÌW§ä0³¼6Ú Ò1Î ·´¬!…3„WuÊDÖ¡ÓÝ%’;èŠj¹CJ‘‰u*bî#Z~QBó jDŸ6³R2nÞÀUÂWÃ6›Z07‘æ&‚<š/¡Ìäæ§¹I47‰æág(3¹‰47æF¦·â«:97ä&In™£‹¯êTäÜdÊ›Ÿòæ§É*rn -ÍM¦¹É”#Å@EÊÍB|Éï£ÕñÑêøüÄ”ÀU2Q555ŸŸ¡ÌäF…CKÇá<†2“uu™²‰¯êTäܨûø¨ûøÈ¤P|U§"ç¦ÒÜš›B9R TäÜ47•æ¦RŽÊ.£ -i %Z#‰ÖHRˆ5«:e¢Fµ‰Z‚D-ARÊLnT>´tÌÎ#ÀPfr£$Q’hƒ É*rnÔƒ$êA™ÏŒ¯êTäÜ‚4·Í-@9 -¨ˆ¹ùiCJïÇâÈ/¨H¹ nÁh.20F)UŽÏ`8vLj1¶„°‰U$Ô«ˆ”L`RÂÄ»š$¯Úð dnilíÔáBûB -“YJ 7Í;Êbñ¬#íÁƒ'Ö1…ùYJ 7Í;Êbá´'<=!¤0‰¥”0¡¶h‹…³Ü‚¤{"C -ó¨pSø£*6œÒÞoÓŽ»¥å—†ç:œ$‰í5¤Q2yR1T8A+^_@&ÊÁÇ,’Ç¢,†æ3PáÌ*ÊbÉ|Fœ±/¤0É@…s¢(‹…–+‘îŽ,…æ7Pᚌ(‹…~Jûl²?¤0Ù@…i‡£+6k6ß Çdóð ‹[p‰´ÑˆÂ¾-É,ec Ÿ—HÍæg)I"-¸DÚh¶0‰¥llÁ%iÁ%ÒF³…ùXÊÆ\I .‘6š-L4P iÁuÃEÜØÂînl%“îCÙרúEÒØ¢ŒÅÂDe_cë§³þýtÖ?S˜Ï@Ùרú%ÒØ¢Œ¥Â$e_cë÷“Æeì)Ìo ÒØF;5 -²¥µ‹2iù…=Fö³”í¢,‘vQ&-[˜ÄR6¶‹²´‹2iùØÂ|,ec»(‹¤]”IËÇ&²”í¢,vQ&-[˜` Ö³õűg+Ic‹Ö?`AˆÊAe_c«¤±E‹ÆÂÁ@Ùר*tQ]¹Â&(û[ÅG[”±R˜Ï@Ùר*ilQÆþÂ$•°žmkNPÏVÄ‹µñ+^› ©€HÐ:¥âÙ3h4¯ªd¨W3wÊ,¥ªZ-Ô¢j äN…¥Ô€–FEK4µ† ¹Se)5¨¥ÁK}µXK@¹3` °;:˜&«nÑ0K¥c:U #>† -÷u‡èÚvY:Œ3ö‡æ3Pá¼!ÊbÉúgœ±R˜h ìë.øÈ"nœ±/¤0Á@Ù#+ÑqÆ¢±0tU§lë.ì€Á´Dš‰~RØ1%‰¥H“#ùI“#‘µÑì~–"MŽ$“& „Ü)³ir$…49èl0äN…¥H“#©¤ÉA×…;U¹ÉaGôc -~âÿ˜È…¡ìküô‹~âÿla¢²¯uð“ÏZàŒ¥Âec…|›gì3& ”Aòœ±RXÀ@%¤uˆ~ôç#Ž,Ó/|@ -›»ìc)âȲDY&Ÿ;`ï”XŠ8²ì'ŽŒÎBîô³qdY&ŽŒÎCî”YŠ8²¬GF×…;e®ïÏáŠ"’ÖA!þ)ô©ʾÖAHë ÿg  ”}­ƒ$­ƒBüŸ)L(C Ò:ÈÄÿÙÂÊÆPƒJZ™ø?[˜j Öwˆy¸bë'´J õ£Ð:,L©¤KÇPZƒã#+âðYÙp_Õ)YK#i+ÕðY¿á:¾ªS~- Y†ús˜D(—¿ ôÎëx8¢¥!ë½ÐU"i´œ®³¹ëw«:%j!ªoÊ-r§ÈRbP—^ÌpDV¥á«:%¸é —‡v"­äó–"åÀÁÖ:+Ó;ékr"úÉjb|V¡wú(—”™A«¾öÑ÷ÃZî²"õÁëOµÁ±ÎÓr÷(Q“ EúæN¤oîDú2¡$S‘x@ýdá#ê|`QJÔ€ý‚ÒDé'ËBñYÙp_Õ)Me~²øŸõ®ã«:¥¹”DÝC¢î¨å2`àwÞ©ÍÀÑÒ%ÃèªNÑ4AâRLîúA–".利£³Aã~¥ˆ©ûEb‚ Gda3¾ªSš J2-ÇOËñG’d–"åH -Ñ:+Ó;é{K"ú‘È÷!ðY…Þé£\RJde>úÂÎG_Øi¹û ©D\J¢M¢|4µNi.å—ˆK!ë ïgDúÊ„¡"»3À¢K¹ýt)7¦Tòœg(­Ö -YàÏʆë~º@ØO—L/àþ¶~…,ãׯûé"h?]½@ù¸Žò*±O9` HOY¥iš†|¯]Õ)š&@¬ŸÉ]¿3ÀRÄúå ±Jt6rg¥ˆU*±†#úU º`›ÜG{þZ9-G"6/ûYŠ”#ËT?~ªj‹²ÌRD?²Bí@¦v [”–™‘Œ¾–ñÑ×2Zî’"õñë—©·Ë"ÍÝg 4ëW|Äú‘uЀ¹HcØ eîÏQ ¨€„?V* IL¢“VYŠôi$·„¿«ŽÎ*†ëøªN‘~Î÷iHžY¦ƒ® e/Ð;qßIK#’Uw¨GD)=H1¹ëwŠ E¡>‘ >§ „Üé3P•¶tIçH$kñUÒLöyp9°Ç¤Íƒ‡îE©ŠôiDÖ¢Jd-’¨ÇD)*k$-ÒOÕtî”(—„¢:ZºPJ¤Ë¹DÅ@‘úÐÅ`"] †(Ú3c(Ÿ)SkßI$bñ D,~jŒ~Ñ@ibñûˆøÑYÅp_Õ)Òߢf+Q³ET–4”½@ïÄ}’†,VD=JÑ4ZN×ÙÜõ;ýCQS÷‹ÄÑu!äNÑ@ Tši0‘%•øªNi¦!)¤Ø“ÑfQËÄÀ%Å@‘¾†Jd-)DÖ5L/Óù2}H{€y0Ãõ˜u…†jÂ0ºªS&2• -ž¬$Í…¦™¡«:n²ÎÖRA¹#Y ô2]ž®ê”©ÜC¥‚YWè<#…0Œ®êTÄÌáB&8p×r“|$7¿„ª/°”i9/ºKäé '¨ ïÐU#}ƨ1øôFŒÊðË…ÖŽB؃Wu*2£(þ!‘ÜD‰ä†ÙCqJ™`T𲬪~Â* e`V!…„Wu*2«*‰DÊ40‚(Ì êg)S¬²¦ª"qà™¯‚(äYèªNEëÀ²,“Ìé‹PDá6¾“#÷Ecj€dM_Z! -g¨XÊDÖc.ø°|°=UÔ !øÀØNðQñ“Â{€€ øaÿG -^Yû¢“Œ¾û@”4j&L¡§™7µÞÙ‚‡MïÊÊ’»©çØøàY÷À½7VV×ÝCÓ÷ͯº'VÜ}ããøíO¸ûÎ,®-Î,Íî7ô9=S·ÀßPñLé»´š›gJß©Ð2¢õÝÚÖïît7Í_Ÿ—צÓÏ5»»`£ -S ¸ÁWh ²Þ¯ïGhÍãéžq„ÖÜ0 ·6ÕUß;ŽÐZQtÿ8BknH÷³‘²¡µ¢è^r„ÖÜî'g# >êýú®r°Ø`­¹!Ý[ÎFDêýúsBè F‹n›½_ßkŽÐ"c‚,ícÌÑVï×÷#´À+ld‡a3ÁÞ¿rÏrTžopÖé®u„Öžî\GhÍ ½!°KÚt;BkEÑ]ì­y!ÝÉÎFüºó+zÛ¢ïhGhÍ é®v6²@v¶#4)J¡5/¤;ÜÙÈ‚Ow~ÅÇ%†ÐšóÓÝîldìxGh‘1A–ö1æh¯óÓÝï-0Å -ÙaØL¬óŸ¾¥ë{ýúÎyZ¿V%]+2ýY»‡¥Õ°%"¤»è‘T>&‡ Þ‡4ÐaµÈöNÑäB’Jbr b!„–LåLæR“T~&ÒãCh¿©œÉäp’Jfr Ã_¶‰5m'7–¦ï³¡‡H·êÓú@ÄRTÆ:è†}úý&,…nÛGRù˜HC¡ÍXо…I%19žŒB›±};?’ÊÏä@z‡¾ÚŒ¥è[û‘T2“éúJ!´–{oBÐ EÖ@ßP»‡¥Í -Ý#¤ò19ç‘B›2º_ I%19§ž/„6e(tï@’ÊÏä@éRmÊPè>‚$•Ìä@ºIþÚ>C‰ùÉC¶ ôLé›ïi´Â<…XZ6÷|ðÑœõM5Z!cuŸ‘6™³Èä,09 Ln¢‘6•³¾M¡gJߨP£©#m*gÊœ¾µ6oÓ‚Tnñ§Ñ„mºÝ¡~¿™&ѯçL·"Ôh’ÝúP¿ßdcKsö19û˜Ü$#m.gº¢gJßQ£qÉlV¨-í8©¬ëJßZP»‡¥ÍɆn«¨µJ$g…Ñ¡"i“93–¢0–¢0:4”bÚRdƺeƺeF‡¬dd³ÖmRŸQ5··g’ö| ›5j´_йgiÉÌóAß¶Q«'Í™l£ÝÃÒ&sµ­+H*?“Ñ¥h¤%sOKAÏ™nèÂ?Ã'[ºž%†giC,Ÿú¦lNRt›“”M´4ÒRØ ˆ!g™É™ ±HʆÜX)Y²æ Vªoé™Ò7$4Ñ®B ¦ôÔ6ÞÐü["½A?SJÐHKa#4g²5¤Æ§¤ê<ÓRÔ:l„Èt°¶rkyîäÊ*h¦Ä©Ø{^¢¢÷¼Dò^‹ÌïÖîaiÑ”YÑ&=Sú>†í#=š ‘6•³¾ë$I%3¹Iz/Œ¥ESMÝ’ð,ëõ])#óLVí¨›h-`¤E3†¨ïRiÔ»±”@mNƒdÇJíÅ­OÐj-Q>õ}+õû#ç¼i_”©†ÊTCe¤Œ´9§»Yj=Xš3cÖtOKý~39‹º!t³Ðw·Ôîais&`œGeœ‡åŸá“-Ý Ï~†gÿ†X>õ/#÷Ÿƒº‰«ŒÁ´4ÒæL\e)FïÆR‚!´9 ªÔÄõ}1 MFjmÆÄM>†æ×Ö¢è÷G“kôÃÃ-F2#}™‘¾ÌèUisÒ§{sj}/’³Âx#Ý¡S¿ßLÎ>ÝÆšÆénúýfy–ž™Þ'å_ ¡ÍåìÓ=SѽÎÈ¿/„6Ý“&ž)3~Âj.Óï7›³ÂäÌô>EuCn¬”lóÓã,}OPÏ”¾+(¡IÝ!´ÍÞ}o0ä9©ê㺱¨F“þ±ªis#9ºÅ¨Ö²Òœú¸n4ªßoòiFFrt+O’óÔeis#9ºõ(áÙ¯ó,ÉødK7óÄð,mÈåSߎÔTœIbz:’²‰ÖFÚÜ‘nOjÔ»±”@mNƒŠ>ö£›•šhM ¡Mýè¶¥ž)}ãR¦¥Œ´¹±ÝÂT㓌ýè6¦ä–¶yìg!¦:ôStÒmP5šÈ$¨is: 2Öd¬…nŠªÝÃÒ&sf¼2Èx%Ý U»‡¥Íy%Ý(•ðì×y–ä |²¥›áYbx–6äÀò©ož9g²*ÑŽ²‰ÖT#mÎ߃̳€Ñ»±5„67–©¿ë[«š¼B‘Ch3þ®o²ª½Æ‘È„TSŠj¤Mù»¾áªÆ§¤ê<ÓRäÚn¾×Í.^‚-»|IûÍ,`|‡,a¢Ùn]zm)“gJ¡¼ÀåLàßh4y¦ô­\=Súf®„&X5„6÷b ¨­¯óL黚” ¡Í½”&[¼b>%:1JaJQ ´~”iC¹ykziqènvõÿoï\{Û6Ö…ëÏô¼íö ‡×ìOÎÎ¥>õN_ärj (ÙfícK9²œÆýó>¼ÏbÊ¢¬‹×rì<‡ERZâpžh¸ä%‚ew”z:ÂV;Š\Ë^R&Íß~‹×¬L [”1ãv—½—”©d‹¸¨%¨Åíú¸xz/)ÓÊë,õÔñšö’%?D,»ŸÔoþlyB±×rBÑ kó3·0îŽ>sWâv]ürWÑék‹¸¨Å¯ÅmvÈ6[Ïb7ÐÉl‹õÔñºv•õ¿ÿÔãnøý§H”›i|–Ù´ˆ‹/w‚ZÜÍEÞ|Ó¿ˆà\^Oü½És¹¯·x™„·ˆ‹/ºýZ¼–-¾æób=q÷†Ï‹^¹Ùu‚ß"..¡yµx=›}¹sLS?•"Qp Sç±çê،݅æÍÏâ³Éçï‹s·R9z}ÊüÂy\¬C™cX—o¿>ßÝS›îîTz¥Ê´Äyì¹úÅ7ãåVªÍëØ|M@g4Nâ"Qj»Å»\™×X—oñ^Zf7Nbi,¹Èp\Ô¢ã¶KvŒ%+cÉÊXšS‰Û.YKÆ’õ-W:÷qµ]ß[²ÐK¡^²Ð÷“é<ÈÕÚ¿·d×XgÇXgÇXO··[²g,Ù5–ìëéÕâ6KnááçÓ›³³hºdO×ÊÙ@'VNbc˔ɕ³2fÜrËØÆh{ mì¶S‰Û.ÙØæÆúè¤ËY3n»dãH·#½LÀ\”1ãvK6ŽtÛ8ÒËdÌE3n·dßX²g,Ù3ÖÓ¯Åí–Kö%ûÆzµ¸Û}{寔u†ç$66O™À7+cÆ-72vCeì†ÊØ •W‰Û.ÙØðÆúèìÏY3n»dãpWÆá®Œ¡rkq»%‡»2w¥ïÔy¡«µoÉ¡±äÀXr`¬gX‹[-Ù1ÞpŒ¹t¶è¢Œ·Y²°D}'t ¯ìxEî袌=·Cvv$Ý·‹Dõý¢L?ÄEêE-½ -EêëbñNCµn-^øÆ²ì*tpd|ÿ½åÏ›ËËwçÓ(ŸDÃ/ËßÒÉqW¦ÓÎ?bïHÊx;Pn5îø©L­],Þn¨Ö©Æ¿#•i¶‹ÅˆjU5îø©L¹],^4TkWãŽß‘ÊôÛEUaCµ²?à;RõÐ ¹óÏœÅ[F™”»(cÆÝ¾e”ɹ‹Åˆje-îö-£LÔ],Þn¨Ö®Åݾe”I»‹Å«†jU-îö-£Là],Þi¨Ö©Åø–±L¿ìÚûÂ’Ÿe2ð$Ögl~—^=•N¤^¯VÖân?h•)Õ‹ÅÛ ÕŠZÜñºzô0`½Vm™d]—Ð~aór<[òÊqw_Ø)Ûû´=‹Ó†RÕØ<…–éÛ‹i~Ã_LóæQÕØ< •‰è‹iAÃbG½ó!²tðžþÜœƒ•1cã$jë¡+²iî\¹¬Œ»ÆüªF"›æÌ•Ëʘ±c̯‹H?Óë™ÆÑ–`®]ódóÆüz0…´Œ›óç˾ª×iÎc‹j,7t;…Æöæ‘ÕX†Õí_ŒzTYg=0DVÆŒ…Ñ~O×/]]¿,r‰çeÌØ¬?ùÚ xý¥§_'é•Õ¤eÌØ|ý¥H)›æóØF[ŒX־ޱ^4eû£N·›íwòÌýì+ b;IeÔéÔbilÿ"­V±o}¤Ñi ësv‹ÁGãß¿Cà!¿vqô(*YºûBÿŒÃϵØxÉ=&M6Í+—•1cc—qôÈ3Ù4g®\VÆŒS†2yeòªHi^” æÚõ§1OÙ¹³œ_¶”–1ãÊü¡>eTê4ç «±yÊp„>dÓiáü<Ž¨Ææ!ëH}ÈTÖY••1cãQ®Q¿cÔïèÓ„r«±Y¿òôë¯\ý:)ã0U^56_¥‡̦yÆ<¶Ñ#–µ¯l£›CÙ~eÔéÔb³ýJŸ2”qjU¶Q§ªÅÆ)#Ï¿Wú´4®UKã¢q%^ú”±¤Q9ƸYŽ1nVfÖbc«zz ¸lš;WÎ1ÆSrŒÑ¨²ùõHoÙ4g®œcŒ-åcNýi¬gV¿qT¦q`´%˜kןÆ<Ùüž1¿&0-cÆ•ù}TWê4ç ª±yT»¡>ªÒiaÃ’]§›õ»®ñú;ÆëoI®[Í×ßõŒýÏ5ö?WI®WeÍæmã2wÙ~Û¨SÕb³ý¶>ª]ãìçJ£N»Gµgë£:Ý7‹‰Ò¸ªW‰—?ªÛhÂú»mçÙ¨ûé§SjSPÆÍ0ÕØü­ò ØÅ4o®\VÆŒM‘yñ~ú©Y×#ô­íi™pn½þ4æ)>Á—óK=BGúi܈«óK};}¥NsY‰ÍÛéÓOäB”ÛÏ¢a»‹Êö+ -0×YêÑF²2flì¸É'í¢þäS{yC¡—ç+/ʘ±ù :ЯŸôõë'õ8*é§v#®¼~2ÔûO:Í00¡Œ¶è¸²ÿHÏh¿1l4†]^-6Ûo á !ÒØ°†J¬¿òhuà&oÆÛõ^êî½Ñãrd-66ºcë=æÍ•Ëʘ±éÆA§Œƒ.Cc]¹õúÓ˜§ø ­çצ¤Ÿ‡¸2¾ì«zæ<ލĕƒÖ‘ú Iˉ†yd-•íWî´•uÖƒ¿deÌØØi•§ëO>7—7’¹ú@U^-6?ÃúúõSž~ý”q (¿W^?èý'f8Pq ¨ Wöåí7ÆQƸ)Ê­Åfû}Ð*ãä–ÆÆçöJ|ƒvÙOÑžÐÛÅÕ'ª,ÊO^ÕØØ.žÔ¯K:Í›+—•1cóSq\¸Æq‘Æ¡±.áÜzýiÌS|ŠÕóëÑeÒO¤F\?ÔÇU¥Nsž°WŽ+Oèý:-'æçñD-•íWîW•u6FÊI˘±±_¹®Q¿cÔïècÉuk±ù)ÒÓ¯Ÿëê×Ï5öe׫ÄÕ×Ï7öÏØ<½/»~%®ì?®c´_íWFN-6Û¯ôqåçŸ46>9WâûW}Ž]zü¨e›VäýäãÇËïÝ(Ój¡¥W|™‘¯¾µâ-†öøÞ8&cÄÍòŒ‹~žnJZÆŒ[V5¿ýŠ.È¡¾1óNøi3^ÜyñöËëJ·Y¾׸±8-cÆ­ëšß~E³<£gµ§›’–1ãVU%c$_1–KV¶^²£ò$ª±j3¤RZ²üê"4¾º˯{Ò2fl|uÑþ5O>æMp“ôªxm=½ÚI3nׄô;^¥—,•^r±ÚéwÂFܲ âÕFøŽnDòÕlш$.V<)cÆíáëkI®ñ¥o+î;Õ¸u#ª‡„'¤>¥º¿lçÇvZÆŒïwJq]WWetOJãâŒeôY)Ê/¿{ù®Èè¶‘ÆÅÂý ·¬èmò7~Ovòîàù¡¨4vü¾,þ -é9ÅÊ¥2yѲOÒn(þá–#S»i✠ßܪŒÏ¬‚ŠßñÆ“±%m¤ob'Ï{ý£cwðr|q2¼¦?ý”=~}ÓgzÅ»W²JÒ --;Þ®RØéc7ùsrÖ{rv3›ÅË=~Nê¼~jŒ›WÃxcÎæèyšÞã7ýç“Ée2åݫ߬—_?O¦3+]3ëýÄú×»wß/÷ߣëQü¦_)ŸnaÅ¿§õnz¢la¼ë¿âð?ñƒ¿,Çú·õûºHJ¾Í¶Î«ÑeôÌØPo‡×³xKÅŸ âÙ_÷_D_FçÑÛ×Ï­Ó7½ßË%'öâJßúÊÏÖAúaôSãääqV$ÿk©ä%ðÓ¢ñ•èõûiÝ/†³á3Ë–Ò {§Ç?ÜÀrP`>¬MÝЪ=µöšAíá¾2ÿŠ—¯û~7¼¤q¨=ÜïM1ßêÇv€íäZ -T~›P‡KÍ~ï²?.5YáN/_׃î×µûí -°-ôû/ÇI¹ÞéÏe*À<ŸÝ›Þ7ò0çÉ󌬉yvÜûg÷ —Iî{4³ðÉѱut3›XÙ*þŽž& šŽÆ³…XOŽ.&gÑàè8üzvM¿Dƒ_¢ÛAVèÚÈ(ó䈶²UÚŠZVÀ•Rÿraê¿r2©ÿv„²7¦ù°6uC«ö@4¥}; õ©ÿª÷{SÌ·ú±`;Y˦{Ç©ÿHý°,Û’úOº{žûO¹ sÿ•“Éý°#”Ý1͇µ©Zµâ )ïÛ¹ÿÈýW}¸ß›b¾Õí<ÛÉZ1Ø;îÈýw@î?€eÙšÜr«rÿ9çþsË ¿û¯œLî?€áà1¥÷jä1·=ÃÜæÒœe=57µnÂ-0¿Aö’Å[ dƒk¸nÚìûÍ|Û͆ïý[Ë:Æ0hGÇÉéÊ¥®ƒ»2A_·¹ÿîÖ’û¯Xj—Úg®kwÜ•›C€}dkrÿù{žû/ sÿ•“Éý°#<¦äV<æ¶g|;ëÙÝãÈùµ` Ìo½dñ(Ùà®›6ûÀ~3ßv³á{¿ÀÖ²Ž1LÚAî?rÿ‘ûö›­Éý'ö<÷Ÿræþ+'“û`G8xLÉ­yÌmÏ8øvÖ³»Ç‘ókÁ˜ß {Éâ-P²Á5\7möýf¾ífÃ÷~€­ec˜´ƒÜäþ#÷ì7[“ûÏ{¹ÿüÀúÃ’B|+ù_:=}œ•Éÿk‘þÏñ„"ýÀÖqÐ.ýßÁãȘ¹˜eÛþ¶UÖïÿîÛ FÍb椅÷’ƒjÚM3XüpÁó{LËÀ¶Êh³qØVµ“ÌüIé[›èîñm+ØÚ¦ƒX+wµë0Öú2»¬ãN'ºÏn;¾Ó»ªâà L{Ÿÿ)ÿï²’µ×QYüzê(ïþÎ^5µ`;é÷_Ž/^ gÃÞéϽþѱ;ˆ¿^Ï¢iïMïC¯?8<šÎ^ŒÎg£Éx8½µžÅOý3þí KZ"ý9½í¥ÿ]ô<ëÉSëô·t®c)ßG_gé Â:|5¢㋉õcñxx/¢¯é3Ò±ßÍ&Ó[ýTZKcýñSÓa>9:¶Žnf+[çÑßÑÓdAÓÑøc¶ëÉÑÅä,‡ƒ_Ï®£é—èbðKt;È -]?Õuɸìx2¶9:¶Žnf+[çÑßÑÓdAÓÑøc¶ëÉÑÅä,‡ƒ_Ï®£é—èbðKt;È -]?Õuɸìx2¶>ŽÆù–Š[—yÝ;|}Go_?·Nßô~/gwEh9~`ýaI!¬ÀN¶Ö§Æééã¬Lþ_`©¸„ôÓÂNüéõûiõÉ ÷̲O¨ÞéñíÿuÚe{.‹µ,¿—,Ûöǰ­²^ÿwMÙ×ËIwsÙÈÞKÌÖÍ7ÁÃÏï1-7Û*£ÍÆa[ÕN2ó'¥om¢»Ç·­`?h› `­ÜÕ¬ÃXëË첎X±ÓµN];ùs§vUÅA¾eôŸòÿ.+Y{•ů§ŽòîïìõXS;¶“~ÿåøâÅp6ìþÜ뻃øñÛáõ,šöÞô>ôúƒÃ£éìÅè|6šŒ‡Ó[ëYüÔ?ãßž°¤%ÒŸÓÛ^úßEϳž<µNKç:–ò}ôu–Î ¬ÃWÓ(ú0¾˜X?‡WÑñø"úZ<ón6™ÞêgÒJ«Ÿš³ðÉѱut3›XÙ*þŽž& šŽÆ³…XOŽ.&gÑàè8üzvM¿Dƒ_¢ÛAVèú©®KÆeÇ“±å†aÚˆ›²‰2ibºq^.£gYø<ú8ç[*nu\æuïðEôet½}ýÜ:}Óû½œÝ¡å¸¡õ‡†V`'ëSãääqV$ûX*ž.ý´¨ÿÄzý~Zwòª=³lG¹~ïôø‡v'ØCH9ÝŽ½ßPYïûÚæ<æß*\ƵʠÖÌNî%µÖ-µ)ÌÛAæ§îîBû½¡î¾wŽ*Ÿ\P¸V %­“"tÄÈh‡U”w@ßåQþ§»*Ò…}ãOwUÔœ~-°öV¬éµÈêëþµxxúý—ã‹$×}ïôç^ÿèØÄ߯gÑ´÷¦÷¡×Mg/Fç³Ñd<œÞZÏâ§þÿö„%-‘þœÞöÒÿ.zžõä©uú[:×±”³ta¾šFчñÅÄú±x<¼ŠŽÇÑ×ôX‡ïf“é­~*­¥±þø©é0 Ÿ[G7³‰•­óèïèi² éhü1[ˆõäèbr ŽŽÃÁ¯g×ÑôKt1ø%ºd…®Ÿêºd\v<[n¦­¸)Û(“6¦[çÕè2z–…Ï££q¾©âfÇe^÷_D_FçÑÛ×Ï­Ó7½ßËÙ];´\éYXü‹·Ö§ÆÉÉã¬HþÏRñté§Eø'.Ðë÷Óº“—í™e 黽Óã6ÚûºáàQf„|<­Îzî•q-ØKjÍ4ÿî1ó­Þû&ß=Ö×úîQ×°<Ìà‡°%tïÝ.1Ï -Öyz³.“™¥Kì²Ùݯc÷ÛÛ’Új‹2[)_ù§¶rí…©­Êɤ¶xÜ<Êl(§ÕYϽ2®{ÉÁ£Lw4ßê½oòÝc}­ïåq ûÇà ~[©­:Z"©­`ßÙ–ÔV¶ØóÜVÂ[˜ÛªœLn+€ÇÍÁ£L‡òxZuÝ+ãZ°—<Ê|Gó­Þû&ß=Ö×úîQ×°<Ì臰%Ûª£%’Û -ömÉm%Ã=Ïmå*ËñëËw›r[•““ÇY‘ìï÷s[ÉÀq¹­`W9Ø÷Ì4pס°åð -l'›Y -à!é6E‹zx¶s­¶›mÉñ`;[˜ãáäy¹IN†·Ñô§ŸŒäé3ñ<ÒÒ‰ |KÚAù+,7yúä¬÷äúrtÅuŒ¿Ñ¢ÓŸ|8~a=³Ê¢ÉšK1ˆ ÇS²Õ”ÖáóÉä2™òîÕoÖ˯Ÿ'Ó™•®‰õ~býëÝ»ï—ûïÑõèì2ª”Ï›¿Ž§ÅŽê¯îÅÁâ§þ²ëßÖïë")û¶çˆÐrBǺJ#W8ÖIÏ‘ž%SOÊr'½[àÍä"Ê,31ÞP_¯.Çñ䟆³øE=»™EùËjì(F©óO£Ë‹i4ÎÊØÖáñx¦§&f·Ÿ£lj¹3U¦^Þäž\E××ÃÆnW)9Ž÷ò§ÅžXýqËÛ4¼œ½~lÓ¤¢äf[th [ùŽï‡^C9³e§“›ÏÉáôý¦•E·ýÕº™^¶iOZlÛÛ2N?F³6Í)Jn¶EOâ7Œoûf»Î†çÿ“ìPã‹6m3Ko¶}¢x'ùVÃΣËËä}þøúç÷ÿ>iÓ¸ú›m üÎ ãÓdú÷Ñåèã¸MÓŒÂÛݪ/ÑtÖºUFáínUV²Å©C¿qlîÄq}>½9;‹¦ƒ›Ï-ÎÙú¿i•-Ö¾ƒ °Îmè¬øvòÿÎ/b·ùé:JWªÅüqÑÚ4íˬMqæÛôz¤ŠÑfoÊ V”b8†ù‹#”ò‚|]Ò¢¥§Äoo£a\úS4úø)—ö‹'ÿ]Ì>Ë‹g¿æÏÄ–?s«Ò\Ž_Õ¿ï’ªâèå`àØƒfSùj%o1É&ÿõs²˜¶çز0—8Ê}%¶6åæ’—Ã\0—5˜‹ ÇõÅ 0ÌsÁ\0Ìe7Ìåbò×·^ÜwÙjw±…ôÝÝ%6ƒÜE©û»‹R…»ÄQn,Ž0¢Ü]òr¸ î²wq7ð‚°©î‚»à.¸ î‚»l£»Œ®‡g—Ñ·N ø þ²Õþ¢¼0°Wô—ØVñ—û_{Q®m%¿WYäËØP’¿F?R–Ã_ð—5ø‹#\åŠ@¸è ú‚¾ /è ú²Íú‚«à*»ç*~†vØè*a“«èg YI4 *+Æ3ß—Û¿¿¬ä:re*J(Ì(“•R[•í?Q(†ôCVdYAVdeÓ’°o²âzJ6w [BVüzϰåd%¸¿¬ä:re(Jre²Rj ²²ý'Ê”éËð{ïgÈÊv·YAV¶ê0²‚¬ +È -²’ÊŠmûB®*+¡XIVÂպŵgÝÀ9É®¢è(™zR–CV•uÜÆâ8Â÷=)šÎuØ -¶‚­`+Ø -¶²5¶òäo†—£Ùíñø<þ,x1†³›sè‡~„ߺ—e¥þaÚkZXŒ\­Xf1Ú]âÇ:Ê-¦ô,fÓ'н´ßöC娋Áb°,‹ÁbvÊbOlÑÆÄc¶ÜcBáùÁÊ÷¹Ìw[ÊcV¸)?7•+Ã^Ò´-e”{Li4x̦O¡{é1#”¯lÃcð<ÁcvÌc[ —Ùq—±•[&Óë°gÙR.sÿ’‹aÅ®Œ¾cF2}9ü.³éÓè>ºŒ+”¨ÀS¸ .ƒËà2¸ .³ .ó"¢g³óãG¨U-f¾g™¾FÓÂbœÕz–e£ÝE÷'Óc•>ƒÅlúº—c»a,2.=˰,‹Áb°˜Ý²z–-Ú˜x̶{ŒëÛR¬ê1ó=Ë–òwµže™Ç”ö¢û“éáÉ´Ñà1›>…î¥Ç¨Àžp5Ácð<Ù1¡g.³ã.ã;BúÝ÷,[Êe¼z–IËöTÚ³LZJ&C({¾2¢dêIY—ÁeÖà2a m;´m.É 2¨ *ƒÊ 2Û­2É1þb:¡;겋ê"…œÆAÊœFmIï_nèKV¿“8B[oYån'pó»a\áä}Æt”L=)Ëá,8Ë:®¿„®};û‘¤iAZ–m—–è?ñ‡iîAZvTZ”ã¸+ßÅ?wÿKâ­¯µ¬0°r¢#žW¤‡ÉEËJÅSOÊrh Ú²m±E „´¥$= Ú‚¶ -h Ú²ÝÚòùrx‹µ`-;j-®´½îïÚO¡}±Õ¬Åñ kÉ E»JÅSOÊrX Ö²k‘ÒsEàx.Ö‚µ`-X Ö‚µl·µ op mÙYmñá¯|“þ¼¶ÄŽÐZ[V19¹?×;(dEGi˜¢Ú‚¶¬£˜í;¾ïÙâ{ïlhËv·mA[¶ê£0Ú‚¶¬åÄqÞ'ñ'ÔuÙMuIîËlÛwîõE„íõe…!Æò~aWæ-¡0¢zÿ1ôeÓgÎ}Ô—0–' -}A_Ðô}A_¶[_²[\ yÑ&D^¶X^l8¡\U\æG^ê&—ÆË»†]™·¶h]I¢Z2ÄeÓçÌ=[„Žç{ÒçÞ|ÄqA\Äe»Å%½ÉoY´ñ–möåÚaн·,s›‹¿š·d·¹è›[´­$Qv›Kyà ޲éSæ>z‹t”¯Ü@p› Þ‚·à-x Þ²åÞ’Þæ‚¸,Ú„ˆË6‹‹kËòóV‡â²Ì.ÁJÉ(óžbeÿ°¤“šŽêa—MŸ3÷Q\„´_I…¸ .ˆ ₸ .Û-.yO1RP"/»+/JÄú²òÈsé'—y…1‘óK,W†ŸhgI£Ú¥ìeÓ'Î}´)\Ø6÷¹`/Ø ö‚½`/[n/Yw1äyÙay‘¡R+Œ—î£ÐHønâ3ø >ƒÏà3øÌÎø WepšÝu[H/pVõ™ù+2ËøL¸‚ÏHCf\;—«,ªåy1®Øäådf2ãú*ôG2„26ƒÍ`3Ø 6³6óïÉ4Ü|Æcð˜ô˜äÚL Bד«ºLl5—‰]¡ýí1+ö.ËüE[‹ÎX©û™•&ƒ¿lúÔ¹—þª ¾äf~üÁ_ðüeWü…Þe‹6#³íãzÊ[ùþ˜ùÞeKŒ»Ú þ™Á”Þ¢oë×Ë´Ë`0›>yî£Áx•+dÓùƒÁ`0 ƒÁ`¶Ò`èO†Åì¸ÅøJúîª3ß§l)‹ñîm1ÉpdŽçþ#PÊU&}8ÙÃØb‚pîaQø¤:/zƒÞ¬Ao; /°›Ša7Ø vƒÝ`7ØÍöØÍ4:ŸL/è\†Ôì®Ô„¡ìÆelÑ$5¶j#¥e™äÒm/5Þýï”É<ÅK|&˜ÄN\i›Q6 -sPŒÇŒ»lú¼¹îâ¸Rx¾òpÜwÁ]pÜeÜ…Že‹¶!ö²Ýöá{j‰[cší%çìÅ[Â^‚{ÛKá'W¦³(׌Rgу½lú̹öâºã¥c[`/Ø ö‚½`/ØËØ Ê0˜7ÛqÔ·Æ4L⫌¿Z§²4÷eÖE¬z­%²›dòr ³Ž[cÛž -’_¢0( -ƒÂ 0Û­0—£/ŒK¶hû¡.Û¬.¶'BÇ“¡¿êÅ—ù®cËd½ôï?.Y!'W†°è -i”©K)1¨Ë¦Ïš{©.ÊõC7>žPÔuA]PÔeûÕ…žc‹¶ ò²íòâ)!–HÓ¶çØRò"Wë9–Ê‹¡,º¿X¥Ê¢5yÙôys/åÅu„ã{7í#/È ò‚¼ /» /tC`v\`ü0«ÞúÒÐql)±Wë8&¢ãX:j²+”ÅSOÊr ³Ž[_eî¡·8¾ -„osõkÁZ°¬kÙkášË¢Mˆ·l³·øÂ ½î¯·,å-jµÛ_2oѶ’Üô¢£Ì[JƒÁ[6}ÒÜCoñÜ@B¼oÁ[ð¼oÙoá–Üe‡Ý%ð¡Vu—ù[^–r—ÁÄõ¨P}Åj×W’(™zR–Ã]p—uܺ¯¤-ããÈG^äyA^—m——“¿ÆtC\vS\\áØrå›\æ:‹%’Ð^\VÈü’«É•©+º‹XåâR* â²é“æ~Š‹ }[qÕqA\ÄqÙ q¡¿Ø¢ˆºl³ºÄâ"WNZ9×_l9uY!åK.'W¦°è^bq”«K)1¨Ë¦O›{ª.plFKF]PÔuA]vD]è2†¾ì°¾(?°»%y9}Y!ÛKÒÌ—y—±úU–4Чž”åÐôe·éÛaàª0àÊ ú‚¾ /è ú²Ýúò¿7ÃËÑì–.cˆËŽŠ‹ëxeVŠ»ŒÅ’Ð^\VKï’‹‹ÖÝQ,‰2q)qÙôIsÅÅ =åe¾WÄqA\—•? #.ˆËZÅ….c‹6"ê²ÍêâKG«ªË|—±¥Ôe…”.¹œ\™Â¢;Š%Q¦.¥Ä .›>mxN(• -šŠ¡.¨ ꂺ .¨Ëª ]ÆÐ—Ö— °·û.cËè‹'î­/®PéhÈWY¯ÇIÏu„¥c%åÐôe úÛ²ëÛŽâÊ ú‚¾ /è ú²Ýúr}sv5šqásÙUs9”¾rÜPŠp‰Ä”ÊoЗDjƒ$ëë1ß×ÿþc¥Z"ÂB_2UÑÒ’Dé­ûE9ô}YÇÕ—Ð2tB2S¢/è ú‚¾ /Û­/çÃq|$ /èËNë‹'üP,‘Ÿ²­¾ˆ%r¼ø÷o¬P•+óš‹ï›QMiЗMŸ:÷Q_¤J¾ °›Îwè ú‚¾ /è ú²=úR\}¡ï -³ë -c;¾\"Me³Â8b¥+0÷s¬¸Ære^wÑââÃ(ëk1(̦OŸ{¨0® C/t÷¿ 0( -ƒÂ 0Û­0Å…Ùu…q¤k/‘°²­Â,uæþ£¹n`%7ê_eQà&ºH3Чž”åPf -ã9A¸!÷À 0( -ƒÂ 0[®0“ÿ¡겫ꢔ'—Èõb«&iqëãŽ%‚ÐZZä -¹^\e9¡›Œ;–FÉ•Ïó+Q¢/E9¤iYGªJ¡Â¤¦C²¬kÁZ°¬e»­åú|zsö|8}?vÜwÙAw‘^ ü&wqÕE:MƒŽ¹s·½ÄžÐÚ]Ôý;yÞ뻃—ã‹“ám4ýé§^¿ÿÿãèñ!9ºŒ¦½×Ã/‘5'³á,úO±>N£ëÙdYן&%ÏijÅûý—¿¾êý™©Au endstream endobj 1618 0 obj [/ICCBased 1764 0 R] endobj 7 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <> endobj 13 0 obj <> endobj 14 0 obj <> endobj 15 0 obj <> endobj 373 0 obj <> endobj 374 0 obj <> endobj 375 0 obj <> endobj 376 0 obj <> endobj 377 0 obj <> endobj 378 0 obj <> endobj 379 0 obj <> endobj 736 0 obj <> endobj 737 0 obj <> endobj 738 0 obj <> endobj 739 0 obj <> endobj 740 0 obj <> endobj 741 0 obj <> endobj 742 0 obj <> endobj 1099 0 obj <> endobj 1100 0 obj <> endobj 1101 0 obj <> endobj 1102 0 obj <> endobj 1103 0 obj <> endobj 1104 0 obj <> endobj 1105 0 obj <> endobj 1451 0 obj [/View/Design] endobj 1452 0 obj <>>> endobj 1449 0 obj [/View/Design] endobj 1450 0 obj <>>> endobj 1447 0 obj [/View/Design] endobj 1448 0 obj <>>> endobj 1445 0 obj [/View/Design] endobj 1446 0 obj <>>> endobj 1443 0 obj [/View/Design] endobj 1444 0 obj <>>> endobj 1441 0 obj [/View/Design] endobj 1442 0 obj <>>> endobj 1439 0 obj [/View/Design] endobj 1440 0 obj <>>> endobj 1088 0 obj [/View/Design] endobj 1089 0 obj <>>> endobj 1086 0 obj [/View/Design] endobj 1087 0 obj <>>> endobj 1084 0 obj [/View/Design] endobj 1085 0 obj <>>> endobj 1082 0 obj [/View/Design] endobj 1083 0 obj <>>> endobj 1080 0 obj [/View/Design] endobj 1081 0 obj <>>> endobj 1078 0 obj [/View/Design] endobj 1079 0 obj <>>> endobj 1076 0 obj [/View/Design] endobj 1077 0 obj <>>> endobj 725 0 obj [/View/Design] endobj 726 0 obj <>>> endobj 723 0 obj [/View/Design] endobj 724 0 obj <>>> endobj 721 0 obj [/View/Design] endobj 722 0 obj <>>> endobj 719 0 obj [/View/Design] endobj 720 0 obj <>>> endobj 717 0 obj [/View/Design] endobj 718 0 obj <>>> endobj 715 0 obj [/View/Design] endobj 716 0 obj <>>> endobj 713 0 obj [/View/Design] endobj 714 0 obj <>>> endobj 360 0 obj [/View/Design] endobj 361 0 obj <>>> endobj 358 0 obj [/View/Design] endobj 359 0 obj <>>> endobj 356 0 obj [/View/Design] endobj 357 0 obj <>>> endobj 354 0 obj [/View/Design] endobj 355 0 obj <>>> endobj 352 0 obj [/View/Design] endobj 353 0 obj <>>> endobj 350 0 obj [/View/Design] endobj 351 0 obj <>>> endobj 348 0 obj [/View/Design] endobj 349 0 obj <>>> endobj 346 0 obj [/View/Design] endobj 347 0 obj <>>> endobj 344 0 obj [/View/Design] endobj 345 0 obj <>>> endobj 1469 0 obj [1468 0 R 1467 0 R 1466 0 R 1465 0 R 1464 0 R 1463 0 R 1462 0 R] endobj 1825 0 obj <> endobj xref 0 1826 0000000004 65535 f -0000000016 00000 n -0000000736 00000 n -0000061098 00000 n -0000000005 00000 f -0000000006 00000 f -0000000016 00000 f -0000385829 00000 n -0000385984 00000 n -0000386056 00000 n -0000385910 00000 n -0000386126 00000 n -0000386208 00000 n -0000386286 00000 n -0000386360 00000 n -0000386432 00000 n -0000000017 00000 f -0000000018 00000 f -0000000019 00000 f -0000000020 00000 f -0000000021 00000 f -0000000022 00000 f -0000000023 00000 f -0000000024 00000 f -0000000025 00000 f -0000000026 00000 f -0000000027 00000 f -0000000028 00000 f -0000000029 00000 f -0000000030 00000 f -0000000031 00000 f -0000000032 00000 f -0000000033 00000 f -0000000034 00000 f -0000000035 00000 f -0000000036 00000 f -0000000037 00000 f -0000000038 00000 f -0000000039 00000 f -0000000040 00000 f -0000000041 00000 f -0000000042 00000 f -0000000043 00000 f -0000000044 00000 f -0000000045 00000 f -0000000046 00000 f -0000000047 00000 f -0000000048 00000 f -0000000049 00000 f -0000000050 00000 f -0000000051 00000 f -0000000052 00000 f -0000000053 00000 f -0000000054 00000 f -0000000055 00000 f -0000000056 00000 f -0000000057 00000 f -0000000058 00000 f -0000000059 00000 f -0000000060 00000 f -0000000061 00000 f -0000000062 00000 f -0000000063 00000 f -0000000064 00000 f -0000000065 00000 f -0000000066 00000 f -0000000067 00000 f -0000000068 00000 f -0000000069 00000 f -0000000070 00000 f -0000000071 00000 f -0000000072 00000 f -0000000073 00000 f -0000000074 00000 f -0000000075 00000 f -0000000076 00000 f -0000000077 00000 f -0000000078 00000 f -0000000079 00000 f -0000000080 00000 f -0000000081 00000 f -0000000082 00000 f -0000000083 00000 f -0000000084 00000 f -0000000085 00000 f -0000000086 00000 f -0000000087 00000 f -0000000088 00000 f -0000000089 00000 f -0000000090 00000 f -0000000091 00000 f -0000000092 00000 f -0000000093 00000 f -0000000094 00000 f -0000000095 00000 f -0000000096 00000 f -0000000097 00000 f -0000000098 00000 f -0000000099 00000 f -0000000100 00000 f -0000000101 00000 f -0000000102 00000 f -0000000103 00000 f -0000000104 00000 f -0000000105 00000 f -0000000106 00000 f -0000000107 00000 f -0000000108 00000 f -0000000109 00000 f -0000000110 00000 f -0000000111 00000 f -0000000112 00000 f -0000000113 00000 f -0000000114 00000 f -0000000115 00000 f -0000000116 00000 f -0000000117 00000 f -0000000118 00000 f -0000000119 00000 f -0000000120 00000 f -0000000121 00000 f -0000000122 00000 f -0000000123 00000 f -0000000124 00000 f -0000000125 00000 f -0000000126 00000 f -0000000127 00000 f -0000000128 00000 f -0000000129 00000 f -0000000130 00000 f -0000000131 00000 f -0000000132 00000 f -0000000133 00000 f -0000000134 00000 f -0000000135 00000 f -0000000136 00000 f -0000000137 00000 f -0000000138 00000 f -0000000139 00000 f -0000000140 00000 f -0000000141 00000 f -0000000142 00000 f -0000000143 00000 f -0000000144 00000 f -0000000145 00000 f -0000000146 00000 f -0000000147 00000 f -0000000148 00000 f -0000000149 00000 f -0000000150 00000 f -0000000151 00000 f -0000000152 00000 f -0000000153 00000 f -0000000154 00000 f -0000000155 00000 f -0000000156 00000 f -0000000157 00000 f -0000000158 00000 f -0000000159 00000 f -0000000160 00000 f -0000000161 00000 f -0000000162 00000 f -0000000163 00000 f -0000000164 00000 f -0000000165 00000 f -0000000166 00000 f -0000000167 00000 f -0000000168 00000 f -0000000169 00000 f -0000000170 00000 f -0000000171 00000 f -0000000172 00000 f -0000000173 00000 f -0000000174 00000 f -0000000175 00000 f -0000000176 00000 f -0000000177 00000 f -0000000178 00000 f -0000000179 00000 f -0000000180 00000 f -0000000181 00000 f -0000000182 00000 f -0000000183 00000 f -0000000184 00000 f -0000000185 00000 f -0000000186 00000 f -0000000187 00000 f -0000000188 00000 f -0000000189 00000 f -0000000190 00000 f -0000000191 00000 f -0000000192 00000 f -0000000193 00000 f -0000000194 00000 f -0000000195 00000 f -0000000196 00000 f -0000000197 00000 f -0000000198 00000 f -0000000199 00000 f -0000000200 00000 f -0000000201 00000 f -0000000202 00000 f -0000000203 00000 f -0000000204 00000 f -0000000205 00000 f -0000000206 00000 f -0000000207 00000 f -0000000208 00000 f -0000000209 00000 f -0000000210 00000 f -0000000211 00000 f -0000000212 00000 f -0000000213 00000 f -0000000214 00000 f -0000000215 00000 f -0000000216 00000 f -0000000217 00000 f -0000000218 00000 f -0000000219 00000 f -0000000220 00000 f -0000000221 00000 f -0000000222 00000 f -0000000223 00000 f -0000000224 00000 f -0000000225 00000 f -0000000226 00000 f -0000000227 00000 f -0000000228 00000 f -0000000229 00000 f -0000000230 00000 f -0000000231 00000 f -0000000232 00000 f -0000000233 00000 f -0000000234 00000 f -0000000235 00000 f -0000000236 00000 f -0000000237 00000 f -0000000238 00000 f -0000000239 00000 f -0000000240 00000 f -0000000241 00000 f -0000000242 00000 f -0000000243 00000 f -0000000244 00000 f -0000000245 00000 f -0000000246 00000 f -0000000247 00000 f -0000000248 00000 f -0000000249 00000 f -0000000250 00000 f -0000000251 00000 f -0000000252 00000 f -0000000253 00000 f -0000000254 00000 f -0000000255 00000 f -0000000256 00000 f -0000000257 00000 f -0000000258 00000 f -0000000259 00000 f -0000000260 00000 f -0000000261 00000 f -0000000262 00000 f -0000000263 00000 f -0000000264 00000 f -0000000265 00000 f -0000000266 00000 f -0000000267 00000 f -0000000268 00000 f -0000000269 00000 f -0000000270 00000 f -0000000271 00000 f -0000000272 00000 f -0000000273 00000 f -0000000274 00000 f -0000000275 00000 f -0000000276 00000 f -0000000277 00000 f -0000000278 00000 f -0000000279 00000 f -0000000280 00000 f -0000000281 00000 f -0000000282 00000 f -0000000283 00000 f -0000000284 00000 f -0000000285 00000 f -0000000286 00000 f -0000000287 00000 f -0000000288 00000 f -0000000289 00000 f -0000000290 00000 f -0000000291 00000 f -0000000292 00000 f -0000000293 00000 f -0000000294 00000 f -0000000295 00000 f -0000000296 00000 f -0000000297 00000 f -0000000298 00000 f -0000000299 00000 f -0000000300 00000 f -0000000301 00000 f -0000000302 00000 f -0000000303 00000 f -0000000304 00000 f -0000000305 00000 f -0000000306 00000 f -0000000307 00000 f -0000000308 00000 f -0000000309 00000 f -0000000310 00000 f -0000000311 00000 f -0000000312 00000 f -0000000313 00000 f -0000000314 00000 f -0000000315 00000 f -0000000316 00000 f -0000000317 00000 f -0000000318 00000 f -0000000319 00000 f -0000000320 00000 f -0000000321 00000 f -0000000322 00000 f -0000000323 00000 f -0000000324 00000 f -0000000325 00000 f -0000000326 00000 f -0000000327 00000 f -0000000328 00000 f -0000000329 00000 f -0000000330 00000 f -0000000331 00000 f -0000000332 00000 f -0000000333 00000 f -0000000334 00000 f -0000000335 00000 f -0000000336 00000 f -0000000337 00000 f -0000000338 00000 f -0000000339 00000 f -0000000340 00000 f -0000000341 00000 f -0000000342 00000 f -0000000343 00000 f -0000000362 00000 f -0000391643 00000 n -0000391675 00000 n -0000391525 00000 n -0000391557 00000 n -0000391407 00000 n -0000391439 00000 n -0000391289 00000 n -0000391321 00000 n -0000391171 00000 n -0000391203 00000 n -0000391053 00000 n -0000391085 00000 n -0000390935 00000 n -0000390967 00000 n -0000390817 00000 n -0000390849 00000 n -0000390699 00000 n -0000390731 00000 n -0000000363 00000 f -0000000364 00000 f -0000000365 00000 f -0000000366 00000 f -0000000367 00000 f -0000000368 00000 f -0000000369 00000 f -0000000370 00000 f -0000000371 00000 f -0000000372 00000 f -0000000380 00000 f -0000386508 00000 n -0000386591 00000 n -0000386666 00000 n -0000386743 00000 n -0000386824 00000 n -0000386903 00000 n -0000386985 00000 n -0000000381 00000 f -0000000382 00000 f -0000000383 00000 f -0000000384 00000 f -0000000385 00000 f -0000000386 00000 f -0000000387 00000 f -0000000388 00000 f -0000000389 00000 f -0000000390 00000 f -0000000391 00000 f -0000000392 00000 f -0000000393 00000 f -0000000394 00000 f -0000000395 00000 f -0000000396 00000 f -0000000397 00000 f -0000000398 00000 f -0000000399 00000 f -0000000400 00000 f -0000000401 00000 f -0000000402 00000 f -0000000403 00000 f -0000000404 00000 f -0000000405 00000 f -0000000406 00000 f -0000000407 00000 f -0000000408 00000 f -0000000409 00000 f -0000000410 00000 f -0000000411 00000 f -0000000412 00000 f -0000000413 00000 f -0000000414 00000 f -0000000415 00000 f -0000000416 00000 f -0000000417 00000 f -0000000418 00000 f -0000000419 00000 f -0000000420 00000 f -0000000421 00000 f -0000000422 00000 f -0000000423 00000 f -0000000424 00000 f -0000000425 00000 f -0000000426 00000 f -0000000427 00000 f -0000000428 00000 f -0000000429 00000 f -0000000430 00000 f -0000000431 00000 f -0000000432 00000 f -0000000433 00000 f -0000000434 00000 f -0000000435 00000 f -0000000436 00000 f -0000000437 00000 f -0000000438 00000 f -0000000439 00000 f -0000000440 00000 f -0000000441 00000 f -0000000442 00000 f -0000000443 00000 f -0000000444 00000 f -0000000445 00000 f -0000000446 00000 f -0000000447 00000 f -0000000448 00000 f -0000000449 00000 f -0000000450 00000 f -0000000451 00000 f -0000000452 00000 f -0000000453 00000 f -0000000454 00000 f -0000000455 00000 f -0000000456 00000 f -0000000457 00000 f -0000000458 00000 f -0000000459 00000 f -0000000460 00000 f -0000000461 00000 f -0000000462 00000 f -0000000463 00000 f -0000000464 00000 f -0000000465 00000 f -0000000466 00000 f -0000000467 00000 f -0000000468 00000 f -0000000469 00000 f -0000000470 00000 f -0000000471 00000 f -0000000472 00000 f -0000000473 00000 f -0000000474 00000 f -0000000475 00000 f -0000000476 00000 f -0000000477 00000 f -0000000478 00000 f -0000000479 00000 f -0000000480 00000 f -0000000481 00000 f -0000000482 00000 f -0000000483 00000 f -0000000484 00000 f -0000000485 00000 f -0000000486 00000 f -0000000487 00000 f -0000000488 00000 f -0000000489 00000 f -0000000490 00000 f -0000000491 00000 f -0000000492 00000 f -0000000493 00000 f -0000000494 00000 f -0000000495 00000 f -0000000496 00000 f -0000000497 00000 f -0000000498 00000 f -0000000499 00000 f -0000000500 00000 f -0000000501 00000 f -0000000502 00000 f -0000000503 00000 f -0000000504 00000 f -0000000505 00000 f -0000000506 00000 f -0000000507 00000 f -0000000508 00000 f -0000000509 00000 f -0000000510 00000 f -0000000511 00000 f -0000000512 00000 f -0000000513 00000 f -0000000514 00000 f -0000000515 00000 f -0000000516 00000 f -0000000517 00000 f -0000000518 00000 f -0000000519 00000 f -0000000520 00000 f -0000000521 00000 f -0000000522 00000 f -0000000523 00000 f -0000000524 00000 f -0000000525 00000 f -0000000526 00000 f -0000000527 00000 f -0000000528 00000 f -0000000529 00000 f -0000000530 00000 f -0000000531 00000 f -0000000532 00000 f -0000000533 00000 f -0000000534 00000 f -0000000535 00000 f -0000000536 00000 f -0000000537 00000 f -0000000538 00000 f -0000000539 00000 f -0000000540 00000 f -0000000541 00000 f -0000000542 00000 f -0000000543 00000 f -0000000544 00000 f -0000000545 00000 f -0000000546 00000 f -0000000547 00000 f -0000000548 00000 f -0000000549 00000 f -0000000550 00000 f -0000000551 00000 f -0000000552 00000 f -0000000553 00000 f -0000000554 00000 f -0000000555 00000 f -0000000556 00000 f -0000000557 00000 f -0000000558 00000 f -0000000559 00000 f -0000000560 00000 f -0000000561 00000 f -0000000562 00000 f -0000000563 00000 f -0000000564 00000 f -0000000565 00000 f -0000000566 00000 f -0000000567 00000 f -0000000568 00000 f -0000000569 00000 f -0000000570 00000 f -0000000571 00000 f -0000000572 00000 f -0000000573 00000 f -0000000574 00000 f -0000000575 00000 f -0000000576 00000 f -0000000577 00000 f -0000000578 00000 f -0000000579 00000 f -0000000580 00000 f -0000000581 00000 f -0000000582 00000 f -0000000583 00000 f -0000000584 00000 f -0000000585 00000 f -0000000586 00000 f -0000000587 00000 f -0000000588 00000 f -0000000589 00000 f -0000000590 00000 f -0000000591 00000 f -0000000592 00000 f -0000000593 00000 f -0000000594 00000 f -0000000595 00000 f -0000000596 00000 f -0000000597 00000 f -0000000598 00000 f -0000000599 00000 f -0000000600 00000 f -0000000601 00000 f -0000000602 00000 f -0000000603 00000 f -0000000604 00000 f -0000000605 00000 f -0000000606 00000 f -0000000607 00000 f -0000000608 00000 f -0000000609 00000 f -0000000610 00000 f -0000000611 00000 f -0000000612 00000 f -0000000613 00000 f -0000000614 00000 f -0000000615 00000 f -0000000616 00000 f -0000000617 00000 f -0000000618 00000 f -0000000619 00000 f -0000000620 00000 f -0000000621 00000 f -0000000622 00000 f -0000000623 00000 f -0000000624 00000 f -0000000625 00000 f -0000000626 00000 f -0000000627 00000 f -0000000628 00000 f -0000000629 00000 f -0000000630 00000 f -0000000631 00000 f -0000000632 00000 f -0000000633 00000 f -0000000634 00000 f -0000000635 00000 f -0000000636 00000 f -0000000637 00000 f -0000000638 00000 f -0000000639 00000 f -0000000640 00000 f -0000000641 00000 f -0000000642 00000 f -0000000643 00000 f -0000000644 00000 f -0000000645 00000 f -0000000646 00000 f -0000000647 00000 f -0000000648 00000 f -0000000649 00000 f -0000000650 00000 f -0000000651 00000 f -0000000652 00000 f -0000000653 00000 f -0000000654 00000 f -0000000655 00000 f -0000000656 00000 f -0000000657 00000 f -0000000658 00000 f -0000000659 00000 f -0000000660 00000 f -0000000661 00000 f -0000000662 00000 f -0000000663 00000 f -0000000664 00000 f -0000000665 00000 f -0000000666 00000 f -0000000667 00000 f -0000000668 00000 f -0000000669 00000 f -0000000670 00000 f -0000000671 00000 f -0000000672 00000 f -0000000673 00000 f -0000000674 00000 f -0000000675 00000 f -0000000676 00000 f -0000000677 00000 f -0000000678 00000 f -0000000679 00000 f -0000000680 00000 f -0000000681 00000 f -0000000682 00000 f -0000000683 00000 f -0000000684 00000 f -0000000685 00000 f -0000000686 00000 f -0000000687 00000 f -0000000688 00000 f -0000000689 00000 f -0000000690 00000 f -0000000691 00000 f -0000000692 00000 f -0000000693 00000 f -0000000694 00000 f -0000000695 00000 f -0000000696 00000 f -0000000697 00000 f -0000000698 00000 f -0000000699 00000 f -0000000700 00000 f -0000000701 00000 f -0000000702 00000 f -0000000703 00000 f -0000000704 00000 f -0000000705 00000 f -0000000706 00000 f -0000000707 00000 f -0000000708 00000 f -0000000709 00000 f -0000000710 00000 f -0000000711 00000 f -0000000712 00000 f -0000000727 00000 f -0000390581 00000 n -0000390613 00000 n -0000390463 00000 n -0000390495 00000 n -0000390345 00000 n -0000390377 00000 n -0000390227 00000 n -0000390259 00000 n -0000390109 00000 n -0000390141 00000 n -0000389991 00000 n -0000390023 00000 n -0000389873 00000 n -0000389905 00000 n -0000000728 00000 f -0000000729 00000 f -0000000730 00000 f -0000000731 00000 f -0000000732 00000 f -0000000733 00000 f -0000000734 00000 f -0000000735 00000 f -0000000743 00000 f -0000387058 00000 n -0000387143 00000 n -0000387220 00000 n -0000387299 00000 n -0000387382 00000 n -0000387463 00000 n -0000387547 00000 n -0000000744 00000 f -0000000745 00000 f -0000000746 00000 f -0000000747 00000 f -0000000748 00000 f -0000000749 00000 f -0000000750 00000 f -0000000751 00000 f -0000000752 00000 f -0000000753 00000 f -0000000754 00000 f -0000000755 00000 f -0000000756 00000 f -0000000757 00000 f -0000000758 00000 f -0000000759 00000 f -0000000760 00000 f -0000000761 00000 f -0000000762 00000 f -0000000763 00000 f -0000000764 00000 f -0000000765 00000 f -0000000766 00000 f -0000000767 00000 f -0000000768 00000 f -0000000769 00000 f -0000000770 00000 f -0000000771 00000 f -0000000772 00000 f -0000000773 00000 f -0000000774 00000 f -0000000775 00000 f -0000000776 00000 f -0000000777 00000 f -0000000778 00000 f -0000000779 00000 f -0000000780 00000 f -0000000781 00000 f -0000000782 00000 f -0000000783 00000 f -0000000784 00000 f -0000000785 00000 f -0000000786 00000 f -0000000787 00000 f -0000000788 00000 f -0000000789 00000 f -0000000790 00000 f -0000000791 00000 f -0000000792 00000 f -0000000793 00000 f -0000000794 00000 f -0000000795 00000 f -0000000796 00000 f -0000000797 00000 f -0000000798 00000 f -0000000799 00000 f -0000000800 00000 f -0000000801 00000 f -0000000802 00000 f -0000000803 00000 f -0000000804 00000 f -0000000805 00000 f -0000000806 00000 f -0000000807 00000 f -0000000808 00000 f -0000000809 00000 f -0000000810 00000 f -0000000811 00000 f -0000000812 00000 f -0000000813 00000 f -0000000814 00000 f -0000000815 00000 f -0000000816 00000 f -0000000817 00000 f -0000000818 00000 f -0000000819 00000 f -0000000820 00000 f -0000000821 00000 f -0000000822 00000 f -0000000823 00000 f -0000000824 00000 f -0000000825 00000 f -0000000826 00000 f -0000000827 00000 f -0000000828 00000 f -0000000829 00000 f -0000000830 00000 f -0000000831 00000 f -0000000832 00000 f -0000000833 00000 f -0000000834 00000 f -0000000835 00000 f -0000000836 00000 f -0000000837 00000 f -0000000838 00000 f -0000000839 00000 f -0000000840 00000 f -0000000841 00000 f -0000000842 00000 f -0000000843 00000 f -0000000844 00000 f -0000000845 00000 f -0000000846 00000 f -0000000847 00000 f -0000000848 00000 f -0000000849 00000 f -0000000850 00000 f -0000000851 00000 f -0000000852 00000 f -0000000853 00000 f -0000000854 00000 f -0000000855 00000 f -0000000856 00000 f -0000000857 00000 f -0000000858 00000 f -0000000859 00000 f -0000000860 00000 f -0000000861 00000 f -0000000862 00000 f -0000000863 00000 f -0000000864 00000 f -0000000865 00000 f -0000000866 00000 f -0000000867 00000 f -0000000868 00000 f -0000000869 00000 f -0000000870 00000 f -0000000871 00000 f -0000000872 00000 f -0000000873 00000 f -0000000874 00000 f -0000000875 00000 f -0000000876 00000 f -0000000877 00000 f -0000000878 00000 f -0000000879 00000 f -0000000880 00000 f -0000000881 00000 f -0000000882 00000 f -0000000883 00000 f -0000000884 00000 f -0000000885 00000 f -0000000886 00000 f -0000000887 00000 f -0000000888 00000 f -0000000889 00000 f -0000000890 00000 f -0000000891 00000 f -0000000892 00000 f -0000000893 00000 f -0000000894 00000 f -0000000895 00000 f -0000000896 00000 f -0000000897 00000 f -0000000898 00000 f -0000000899 00000 f -0000000900 00000 f -0000000901 00000 f -0000000902 00000 f -0000000903 00000 f -0000000904 00000 f -0000000905 00000 f -0000000906 00000 f -0000000907 00000 f -0000000908 00000 f -0000000909 00000 f -0000000910 00000 f -0000000911 00000 f -0000000912 00000 f -0000000913 00000 f -0000000914 00000 f -0000000915 00000 f -0000000916 00000 f -0000000917 00000 f -0000000918 00000 f -0000000919 00000 f -0000000920 00000 f -0000000921 00000 f -0000000922 00000 f -0000000923 00000 f -0000000924 00000 f -0000000925 00000 f -0000000926 00000 f -0000000927 00000 f -0000000928 00000 f -0000000929 00000 f -0000000930 00000 f -0000000931 00000 f -0000000932 00000 f -0000000933 00000 f -0000000934 00000 f -0000000935 00000 f -0000000936 00000 f -0000000937 00000 f -0000000938 00000 f -0000000939 00000 f -0000000940 00000 f -0000000941 00000 f -0000000942 00000 f -0000000943 00000 f -0000000944 00000 f -0000000945 00000 f -0000000946 00000 f -0000000947 00000 f -0000000948 00000 f -0000000949 00000 f -0000000950 00000 f -0000000951 00000 f -0000000952 00000 f -0000000953 00000 f -0000000954 00000 f -0000000955 00000 f -0000000956 00000 f -0000000957 00000 f -0000000958 00000 f -0000000959 00000 f -0000000960 00000 f -0000000961 00000 f -0000000962 00000 f -0000000963 00000 f -0000000964 00000 f -0000000965 00000 f -0000000966 00000 f -0000000967 00000 f -0000000968 00000 f -0000000969 00000 f -0000000970 00000 f -0000000971 00000 f -0000000972 00000 f -0000000973 00000 f -0000000974 00000 f -0000000975 00000 f -0000000976 00000 f -0000000977 00000 f -0000000978 00000 f -0000000979 00000 f -0000000980 00000 f -0000000981 00000 f -0000000982 00000 f -0000000983 00000 f -0000000984 00000 f -0000000985 00000 f -0000000986 00000 f -0000000987 00000 f -0000000988 00000 f -0000000989 00000 f -0000000990 00000 f -0000000991 00000 f -0000000992 00000 f -0000000993 00000 f -0000000994 00000 f -0000000995 00000 f -0000000996 00000 f -0000000997 00000 f -0000000998 00000 f -0000000999 00000 f -0000001000 00000 f -0000001001 00000 f -0000001002 00000 f -0000001003 00000 f -0000001004 00000 f -0000001005 00000 f -0000001006 00000 f -0000001007 00000 f -0000001008 00000 f -0000001009 00000 f -0000001010 00000 f -0000001011 00000 f -0000001012 00000 f -0000001013 00000 f -0000001014 00000 f -0000001015 00000 f -0000001016 00000 f -0000001017 00000 f -0000001018 00000 f -0000001019 00000 f -0000001020 00000 f -0000001021 00000 f -0000001022 00000 f -0000001023 00000 f -0000001024 00000 f -0000001025 00000 f -0000001026 00000 f -0000001027 00000 f -0000001028 00000 f -0000001029 00000 f -0000001030 00000 f -0000001031 00000 f -0000001032 00000 f -0000001033 00000 f -0000001034 00000 f -0000001035 00000 f -0000001036 00000 f -0000001037 00000 f -0000001038 00000 f -0000001039 00000 f -0000001040 00000 f -0000001041 00000 f -0000001042 00000 f -0000001043 00000 f -0000001044 00000 f -0000001045 00000 f -0000001046 00000 f -0000001047 00000 f -0000001048 00000 f -0000001049 00000 f -0000001050 00000 f -0000001051 00000 f -0000001052 00000 f -0000001053 00000 f -0000001054 00000 f -0000001055 00000 f -0000001056 00000 f -0000001057 00000 f -0000001058 00000 f -0000001059 00000 f -0000001060 00000 f -0000001061 00000 f -0000001062 00000 f -0000001063 00000 f -0000001064 00000 f -0000001065 00000 f -0000001066 00000 f -0000001067 00000 f -0000001068 00000 f -0000001069 00000 f -0000001070 00000 f -0000001071 00000 f -0000001072 00000 f -0000001073 00000 f -0000001074 00000 f -0000001075 00000 f -0000001090 00000 f -0000389753 00000 n -0000389786 00000 n -0000389633 00000 n -0000389666 00000 n -0000389513 00000 n -0000389546 00000 n -0000389393 00000 n -0000389426 00000 n -0000389273 00000 n -0000389306 00000 n -0000389153 00000 n -0000389186 00000 n -0000389033 00000 n -0000389066 00000 n -0000001091 00000 f -0000001092 00000 f -0000001093 00000 f -0000001094 00000 f -0000001095 00000 f -0000001096 00000 f -0000001097 00000 f -0000001107 00000 f -0000000000 00000 f -0000387622 00000 n -0000387708 00000 n -0000387786 00000 n -0000387866 00000 n -0000387950 00000 n -0000388032 00000 n -0000388117 00000 n -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000388913 00000 n -0000388946 00000 n -0000388793 00000 n -0000388826 00000 n -0000388673 00000 n -0000388706 00000 n -0000388553 00000 n -0000388586 00000 n -0000388433 00000 n -0000388466 00000 n -0000388313 00000 n -0000388346 00000 n -0000388193 00000 n -0000388226 00000 n -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000108772 00000 n -0000144702 00000 n -0000144788 00000 n -0000144866 00000 n -0000144946 00000 n -0000145030 00000 n -0000145112 00000 n -0000145197 00000 n -0000391761 00000 n -0000061152 00000 n -0000063790 00000 n -0000065489 00000 n -0000146961 00000 n -0000103111 00000 n -0000102746 00000 n -0000146113 00000 n -0000146238 00000 n -0000146363 00000 n -0000146487 00000 n -0000107487 00000 n -0000146604 00000 n -0000146721 00000 n -0000146836 00000 n -0000133782 00000 n -0000066418 00000 n -0000067491 00000 n -0000067816 00000 n -0000068068 00000 n -0000068320 00000 n -0000068641 00000 n -0000068962 00000 n -0000069287 00000 n -0000069615 00000 n -0000069936 00000 n -0000070257 00000 n -0000070584 00000 n -0000070912 00000 n -0000071386 00000 n -0000071637 00000 n -0000072126 00000 n -0000072566 00000 n -0000073020 00000 n -0000073372 00000 n -0000073728 00000 n -0000073985 00000 n -0000074242 00000 n -0000074499 00000 n -0000074756 00000 n -0000075013 00000 n -0000075264 00000 n -0000075521 00000 n -0000075778 00000 n -0000076035 00000 n -0000076292 00000 n -0000076549 00000 n -0000076701 00000 n -0000076952 00000 n -0000077203 00000 n -0000077454 00000 n -0000077705 00000 n -0000077956 00000 n -0000078208 00000 n -0000078460 00000 n -0000078695 00000 n -0000078947 00000 n -0000079199 00000 n -0000079451 00000 n -0000079700 00000 n -0000079949 00000 n -0000080200 00000 n -0000080452 00000 n -0000080704 00000 n -0000080956 00000 n -0000081208 00000 n -0000081510 00000 n -0000081762 00000 n -0000082014 00000 n -0000082263 00000 n -0000082515 00000 n -0000082767 00000 n -0000083016 00000 n -0000083265 00000 n -0000083514 00000 n -0000083763 00000 n -0000084012 00000 n -0000084264 00000 n -0000084513 00000 n -0000084762 00000 n -0000085011 00000 n -0000085263 00000 n -0000085515 00000 n -0000085767 00000 n -0000086019 00000 n -0000086271 00000 n -0000086523 00000 n -0000086775 00000 n -0000087027 00000 n -0000087279 00000 n -0000087531 00000 n -0000087783 00000 n -0000088035 00000 n -0000088284 00000 n -0000088533 00000 n -0000088784 00000 n -0000089033 00000 n -0000089284 00000 n -0000089533 00000 n -0000089785 00000 n -0000090034 00000 n -0000090286 00000 n -0000090538 00000 n -0000090790 00000 n -0000091042 00000 n -0000091294 00000 n -0000091546 00000 n -0000091798 00000 n -0000092050 00000 n -0000092302 00000 n -0000092554 00000 n -0000092806 00000 n -0000093058 00000 n -0000093408 00000 n -0000093660 00000 n -0000093912 00000 n -0000094164 00000 n -0000094516 00000 n -0000094768 00000 n -0000095020 00000 n -0000095272 00000 n -0000095524 00000 n -0000095874 00000 n -0000096126 00000 n -0000096478 00000 n -0000096730 00000 n -0000096979 00000 n -0000097229 00000 n -0000097481 00000 n -0000097733 00000 n -0000097985 00000 n -0000098237 00000 n -0000098489 00000 n -0000098741 00000 n -0000098993 00000 n -0000099245 00000 n -0000099497 00000 n -0000099749 00000 n -0000100001 00000 n -0000100253 00000 n -0000100505 00000 n -0000100757 00000 n -0000101009 00000 n -0000101295 00000 n -0000101608 00000 n -0000101907 00000 n -0000102188 00000 n -0000102454 00000 n -0000065555 00000 n -0000385790 00000 n -0000065851 00000 n -0000065903 00000 n -0000138166 00000 n -0000142792 00000 n -0000142916 00000 n -0000143036 00000 n -0000142208 00000 n -0000138231 00000 n -0000138531 00000 n -0000138943 00000 n -0000138101 00000 n -0000138036 00000 n -0000137971 00000 n -0000137906 00000 n -0000137841 00000 n -0000137776 00000 n -0000137711 00000 n -0000137646 00000 n -0000137581 00000 n -0000137516 00000 n -0000137451 00000 n -0000137386 00000 n -0000137321 00000 n -0000137256 00000 n -0000137191 00000 n -0000137126 00000 n -0000137061 00000 n -0000136996 00000 n -0000136931 00000 n -0000136866 00000 n -0000136801 00000 n -0000136736 00000 n -0000136671 00000 n -0000136606 00000 n -0000136541 00000 n -0000136476 00000 n -0000136411 00000 n -0000136346 00000 n -0000136281 00000 n -0000136216 00000 n -0000136151 00000 n -0000136086 00000 n -0000136021 00000 n -0000135956 00000 n -0000135891 00000 n -0000135826 00000 n -0000135761 00000 n -0000135632 00000 n -0000134546 00000 n -0000134481 00000 n -0000134416 00000 n -0000134351 00000 n -0000134286 00000 n -0000134221 00000 n -0000134156 00000 n -0000134091 00000 n -0000134026 00000 n -0000133961 00000 n -0000133896 00000 n -0000113590 00000 n -0000124145 00000 n -0000113655 00000 n -0000113525 00000 n -0000113460 00000 n -0000113395 00000 n -0000113330 00000 n -0000113265 00000 n -0000113200 00000 n -0000113135 00000 n -0000113070 00000 n -0000113005 00000 n -0000112940 00000 n -0000112875 00000 n -0000112810 00000 n -0000112745 00000 n -0000112680 00000 n -0000112615 00000 n -0000112550 00000 n -0000112485 00000 n -0000112420 00000 n -0000112355 00000 n -0000112290 00000 n -0000112225 00000 n -0000112160 00000 n -0000112095 00000 n -0000112030 00000 n -0000111965 00000 n -0000111900 00000 n -0000111835 00000 n -0000111770 00000 n -0000111705 00000 n -0000111640 00000 n -0000111575 00000 n -0000111510 00000 n -0000111445 00000 n -0000111380 00000 n -0000111315 00000 n -0000111250 00000 n -0000111185 00000 n -0000111120 00000 n -0000111055 00000 n -0000110990 00000 n -0000110925 00000 n -0000110860 00000 n -0000110795 00000 n -0000110730 00000 n -0000110665 00000 n -0000110600 00000 n -0000110535 00000 n -0000110470 00000 n -0000110405 00000 n -0000110340 00000 n -0000110275 00000 n -0000110210 00000 n -0000110145 00000 n -0000110080 00000 n -0000110015 00000 n -0000109950 00000 n -0000109885 00000 n -0000108707 00000 n -0000108642 00000 n -0000108577 00000 n -0000108512 00000 n -0000108447 00000 n -0000108382 00000 n -0000108317 00000 n -0000108252 00000 n -0000108187 00000 n -0000108122 00000 n -0000108057 00000 n -0000107992 00000 n -0000107927 00000 n -0000107862 00000 n -0000107797 00000 n -0000107732 00000 n -0000107667 00000 n -0000107602 00000 n -0000107422 00000 n -0000107112 00000 n -0000106774 00000 n -0000106451 00000 n -0000106146 00000 n -0000105856 00000 n -0000102795 00000 n -0000103150 00000 n -0000103206 00000 n -0000108938 00000 n -0000109216 00000 n -0000115071 00000 n -0000124263 00000 n -0000124332 00000 n -0000124364 00000 n -0000124631 00000 n -0000124708 00000 n -0000134796 00000 n -0000134861 00000 n -0000135111 00000 n -0000135176 00000 n -0000135567 00000 n -0000139417 00000 n -0000139747 00000 n -0000140748 00000 n -0000139482 00000 n -0000139352 00000 n -0000139287 00000 n -0000139796 00000 n -0000140695 00000 n -0000140866 00000 n -0000140935 00000 n -0000140967 00000 n -0000141232 00000 n -0000141309 00000 n -0000142357 00000 n -0000142396 00000 n -0000142548 00000 n -0000142670 00000 n -0000143163 00000 n -0000143244 00000 n -0000143268 00000 n -0000143519 00000 n -0000143662 00000 n -0000143739 00000 n -0000144672 00000 n -0000144000 00000 n -0000144076 00000 n -0000145993 00000 n -0000146026 00000 n -0000145873 00000 n -0000145906 00000 n -0000145753 00000 n -0000145786 00000 n -0000145633 00000 n -0000145666 00000 n -0000145513 00000 n -0000145546 00000 n -0000145393 00000 n -0000145426 00000 n -0000145273 00000 n -0000145306 00000 n -0000147039 00000 n -0000147293 00000 n -0000148317 00000 n -0000157977 00000 n -0000223567 00000 n -0000289157 00000 n -0000354747 00000 n -0000391844 00000 n -trailer <<748C6204CB554CBBB49FB95A2BB8DB07>]>> startxref 392016 %%EOF \ No newline at end of file diff --git a/lib/osmf/samples/OSMFPlayer/html-template/scripts/swfobject.js b/lib/osmf/samples/OSMFPlayer/html-template/scripts/swfobject.js index 8eafe9d..b17981f 100644 --- a/lib/osmf/samples/OSMFPlayer/html-template/scripts/swfobject.js +++ b/lib/osmf/samples/OSMFPlayer/html-template/scripts/swfobject.js @@ -1,4 +1,4 @@ -/* SWFObject v2.2 - is released under the MIT License -*/ +/* SWFObject v2.2 + is released under the MIT License +*/ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/OSMFPlayer/src/assets/default.css b/lib/osmf/samples/OSMFPlayer/src/assets/default.css index be2054d..7a053bb 100644 --- a/lib/osmf/samples/OSMFPlayer/src/assets/default.css +++ b/lib/osmf/samples/OSMFPlayer/src/assets/default.css @@ -1,2 +1,2 @@ -/* CSS file */ -/* This file exists solely to remove a Flex Builder compiler warning. */ +/* CSS file */ +/* This file exists solely to remove a Flex Builder compiler warning. */ diff --git a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/configuration/PlayerConfiguration.as b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/configuration/PlayerConfiguration.as index a7bd1d5..263bbb9 100644 --- a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/configuration/PlayerConfiguration.as +++ b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/configuration/PlayerConfiguration.as @@ -1,93 +1,93 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.player.configuration -{ - public class PlayerConfiguration - { - public function PlayerConfiguration(parameters:Object):void - { - _url = parameters.url || ""; - - _backgroundColor - = parameters.backgroundColor == undefined - ? NaN - : parseInt(parameters.backgroundColor); - - _autoHideControlBar - = parameters.autoHideControlBar == undefined - ? true - : parameters.autoHideControlBar.toString().toLowerCase() == "false" - ? false - : true; - - _autoSwitchQuality - = parameters.autoSwitchQuality == undefined - ? true - : parameters.autoSwitchQuality.toString().toLowerCase() == "false" - ? false - : true; - - _autoPlay - = parameters.autoPlay == undefined - ? true - : parameters.autoPlay.toString().toLowerCase() == "false" - ? false - : true; - } - - public function get url():String - { - return _url; - } - - public function get backgroundColor():Number - { - return _backgroundColor; - } - - public function get autoHideControlBar():Boolean - { - return _autoHideControlBar; - } - - public function get autoSwitchQuality():Boolean - { - return _autoSwitchQuality; - } - - public function get autoPlay():Boolean - { - return _autoPlay; - } - - // Internals - // - - private var _url:String; - private var _backgroundColor:Number; - private var _showStopButton:Boolean; - private var _autoHideControlBar:Boolean; - private var _autoSwitchQuality:Boolean; - private var _autoPlay:Boolean; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.player.configuration +{ + public class PlayerConfiguration + { + public function PlayerConfiguration(parameters:Object):void + { + _url = parameters.url || ""; + + _backgroundColor + = parameters.backgroundColor == undefined + ? NaN + : parseInt(parameters.backgroundColor); + + _autoHideControlBar + = parameters.autoHideControlBar == undefined + ? true + : parameters.autoHideControlBar.toString().toLowerCase() == "false" + ? false + : true; + + _autoSwitchQuality + = parameters.autoSwitchQuality == undefined + ? true + : parameters.autoSwitchQuality.toString().toLowerCase() == "false" + ? false + : true; + + _autoPlay + = parameters.autoPlay == undefined + ? true + : parameters.autoPlay.toString().toLowerCase() == "false" + ? false + : true; + } + + public function get url():String + { + return _url; + } + + public function get backgroundColor():Number + { + return _backgroundColor; + } + + public function get autoHideControlBar():Boolean + { + return _autoHideControlBar; + } + + public function get autoSwitchQuality():Boolean + { + return _autoSwitchQuality; + } + + public function get autoPlay():Boolean + { + return _autoPlay; + } + + // Internals + // + + private var _url:String; + private var _backgroundColor:Number; + private var _showStopButton:Boolean; + private var _autoHideControlBar:Boolean; + private var _autoSwitchQuality:Boolean; + private var _autoPlay:Boolean; + } } \ No newline at end of file diff --git a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/Debugger.as b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/Debugger.as index adce23b..5ae0e3d 100644 --- a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/Debugger.as +++ b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/Debugger.as @@ -1,109 +1,109 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.player.debug -{ - import flash.events.AsyncErrorEvent; - import flash.events.SecurityErrorEvent; - import flash.events.StatusEvent; - import flash.events.TimerEvent; - import flash.net.LocalConnection; - import flash.utils.Timer; - - public class Debugger - { - public static const FLUSH_INTERVAL:Number = 200; - public static const MAX_QUEUE_LENGTH:Number = 30; - - public function Debugger(instanceId:String) - { - this.instanceId = instanceId; - - sender = new LocalConnection(); - sender.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError); - sender.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError); - sender.addEventListener(StatusEvent.STATUS, onStatus); - - queue = []; - - timer = new Timer(FLUSH_INTERVAL); - timer.addEventListener(TimerEvent.TIMER, onTimerTick); - timer.start(); - - send("TRACE", "debugger instance constructed"); - } - - public function send(type:String, ...parameters):void - { - parameters.unshift(type); - parameters.unshift(new Date()); - parameters.unshift(instanceId); - - queue.push(parameters); - if (queue.length > MAX_QUEUE_LENGTH) - { - flush(); - } - } - - // Internals - // - - private var sender:LocalConnection; - private var instanceId:String; - - private var queue:Array; - private var timer:Timer; - - private static const SENDER_NAME:String = "_OSMFWebPlayerDebugger"; - - private function onAsyncError(event:AsyncErrorEvent):void - { - // - } - - private function onSecurityError(event:SecurityErrorEvent):void - { - // - } - - private function onStatus(event:StatusEvent):void - { - // - } - - private function flush():void - { - sender.send(SENDER_NAME, "debug", queue); - - queue = []; - } - - private function onTimerTick(event:TimerEvent):void - { - if (queue.length > 0) - { - flush(); - } - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.player.debug +{ + import flash.events.AsyncErrorEvent; + import flash.events.SecurityErrorEvent; + import flash.events.StatusEvent; + import flash.events.TimerEvent; + import flash.net.LocalConnection; + import flash.utils.Timer; + + public class Debugger + { + public static const FLUSH_INTERVAL:Number = 200; + public static const MAX_QUEUE_LENGTH:Number = 30; + + public function Debugger(instanceId:String) + { + this.instanceId = instanceId; + + sender = new LocalConnection(); + sender.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError); + sender.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError); + sender.addEventListener(StatusEvent.STATUS, onStatus); + + queue = []; + + timer = new Timer(FLUSH_INTERVAL); + timer.addEventListener(TimerEvent.TIMER, onTimerTick); + timer.start(); + + send("TRACE", "debugger instance constructed"); + } + + public function send(type:String, ...parameters):void + { + parameters.unshift(type); + parameters.unshift(new Date()); + parameters.unshift(instanceId); + + queue.push(parameters); + if (queue.length > MAX_QUEUE_LENGTH) + { + flush(); + } + } + + // Internals + // + + private var sender:LocalConnection; + private var instanceId:String; + + private var queue:Array; + private var timer:Timer; + + private static const SENDER_NAME:String = "_OSMFWebPlayerDebugger"; + + private function onAsyncError(event:AsyncErrorEvent):void + { + // + } + + private function onSecurityError(event:SecurityErrorEvent):void + { + // + } + + private function onStatus(event:StatusEvent):void + { + // + } + + private function flush():void + { + sender.send(SENDER_NAME, "debug", queue); + + queue = []; + } + + private function onTimerTick(event:TimerEvent):void + { + if (queue.length > 0) + { + flush(); + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerElementProxy.as b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerElementProxy.as index 165a831..c1bb3e2 100644 --- a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerElementProxy.as +++ b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerElementProxy.as @@ -1,168 +1,168 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.player.debug -{ - import org.osmf.elements.ProxyElement; - import org.osmf.events.AudioEvent; - import org.osmf.events.BufferEvent; - import org.osmf.events.DRMEvent; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.events.DynamicStreamEvent; - import org.osmf.events.LoadEvent; - import org.osmf.events.PlayEvent; - import org.osmf.events.SeekEvent; - import org.osmf.events.TimeEvent; - import org.osmf.media.MediaElement; - import org.osmf.traits.TraitEventDispatcher; - - public class DebuggerElementProxy extends ProxyElement - { - public function DebuggerElementProxy(wrappedElement:MediaElement, debugger:Debugger) - { - super(wrappedElement); - this.debugger = debugger; - dispatcher = new TraitEventDispatcher(); - dispatcher.media = wrappedElement; - - dispatcher.addEventListener(AudioEvent.MUTED_CHANGE, processMutedChange); - dispatcher.addEventListener(AudioEvent.PAN_CHANGE, processPanChange); - dispatcher.addEventListener(AudioEvent.VOLUME_CHANGE, processVolumeChange); - dispatcher.addEventListener(BufferEvent.BUFFER_TIME_CHANGE, processBufferTimeChange); - dispatcher.addEventListener(BufferEvent.BUFFERING_CHANGE, processBufferingChange); - dispatcher.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, processDisplayObjectChange); - dispatcher.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, processMediaSizeChange); - dispatcher.addEventListener(DRMEvent.DRM_STATE_CHANGE, processDRMStateChange); - dispatcher.addEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, processAutoSwitchChange); - dispatcher.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, processNumDynamicStreamsChange); - dispatcher.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, processSwitchingChange); - dispatcher.addEventListener(LoadEvent.BYTES_TOTAL_CHANGE, processBytesTotalChange); - dispatcher.addEventListener(LoadEvent.LOAD_STATE_CHANGE, processLoadStateChange); - dispatcher.addEventListener(PlayEvent.CAN_PAUSE_CHANGE, processCanPauseChange); - dispatcher.addEventListener(PlayEvent.PLAY_STATE_CHANGE, processPlayStateChange); - dispatcher.addEventListener(SeekEvent.SEEKING_CHANGE, processSeekingChange); - dispatcher.addEventListener(TimeEvent.COMPLETE, processComplete); - dispatcher.addEventListener(TimeEvent.DURATION_CHANGE, processDurationChange); - - } - - // Overrides - // - - private function processAutoSwitchChange(event:DynamicStreamEvent):void - { - debugger.send("EVENT","autoSwitchChange", event.autoSwitch); - } - - private function processBufferingChange(event:BufferEvent):void - { - debugger.send("EVENT","bufferingChange", event.buffering); - } - - private function processBufferTimeChange(event:BufferEvent):void - { - debugger.send("EVENT","bufferTimeChange", event.bufferTime); - } - - private function processComplete(event:TimeEvent):void - { - debugger.send("EVENT","complete"); - } - - private function processCanPauseChange(event:PlayEvent):void - { - debugger.send("EVENT","canPauseChange", event.canPause); - } - - private function processDisplayObjectChange(event:DisplayObjectEvent):void - { - debugger.send("EVENT","displayObjectChange"); - } - - private function processDurationChange(event:TimeEvent):void - { - debugger.send("EVENT","durantionChange", event.time); - } - - private function processLoadStateChange(event:LoadEvent):void - { - debugger.send("EVENT","loadStateChange", event.loadState); - } - - private function processBytesTotalChange(event:LoadEvent):void - { - debugger.send("EVENT","bytesTotalChange", event.bytes); - } - - private function processMediaSizeChange(event:DisplayObjectEvent):void - { - debugger.send("EVENT","mediaSizeChange", "[" + event.newWidth + ", " + event.newHeight + "]"); - } - - private function processMutedChange(event:AudioEvent):void - { - debugger.send("EVENT","mutedChange", event.muted); - } - - private function processNumDynamicStreamsChange(event:DynamicStreamEvent):void - { - debugger.send("EVENT","numDynamicStreamsChange"); - } - - private function processPanChange(event:AudioEvent):void - { - debugger.send("EVENT","panChange", event.pan); - } - - private function processPlayStateChange(event:PlayEvent):void - { - debugger.send("EVENT","playStateChange", event.playState); - } - - private function processSeekingChange(event:SeekEvent):void - { - debugger.send("EVENT","seekingChange", event.seeking + ", " + event.time); - } - - private function processSwitchingChange(event:DynamicStreamEvent):void - { - debugger.send("EVENT","switchingChange", event.switching); - } - - private function processVolumeChange(event:AudioEvent):void - { - debugger.send("EVENT","volumeChange", event.volume); - } - - private function processDRMStateChange(event:DRMEvent):void - { - var error:String = event.mediaError ? "ErrorID: " + event.mediaError.errorID + ", Message: " + event.mediaError.message + ", Detail: " + event.mediaError.detail : ""; - debugger.send("EVENT","drmStateChange", event.drmState, "[", error, "]"); - } - - // Internals - // - - private var dispatcher:TraitEventDispatcher; - private var debugger:Debugger; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.player.debug +{ + import org.osmf.elements.ProxyElement; + import org.osmf.events.AudioEvent; + import org.osmf.events.BufferEvent; + import org.osmf.events.DRMEvent; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.events.DynamicStreamEvent; + import org.osmf.events.LoadEvent; + import org.osmf.events.PlayEvent; + import org.osmf.events.SeekEvent; + import org.osmf.events.TimeEvent; + import org.osmf.media.MediaElement; + import org.osmf.traits.TraitEventDispatcher; + + public class DebuggerElementProxy extends ProxyElement + { + public function DebuggerElementProxy(wrappedElement:MediaElement, debugger:Debugger) + { + super(wrappedElement); + this.debugger = debugger; + dispatcher = new TraitEventDispatcher(); + dispatcher.media = wrappedElement; + + dispatcher.addEventListener(AudioEvent.MUTED_CHANGE, processMutedChange); + dispatcher.addEventListener(AudioEvent.PAN_CHANGE, processPanChange); + dispatcher.addEventListener(AudioEvent.VOLUME_CHANGE, processVolumeChange); + dispatcher.addEventListener(BufferEvent.BUFFER_TIME_CHANGE, processBufferTimeChange); + dispatcher.addEventListener(BufferEvent.BUFFERING_CHANGE, processBufferingChange); + dispatcher.addEventListener(DisplayObjectEvent.DISPLAY_OBJECT_CHANGE, processDisplayObjectChange); + dispatcher.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, processMediaSizeChange); + dispatcher.addEventListener(DRMEvent.DRM_STATE_CHANGE, processDRMStateChange); + dispatcher.addEventListener(DynamicStreamEvent.AUTO_SWITCH_CHANGE, processAutoSwitchChange); + dispatcher.addEventListener(DynamicStreamEvent.NUM_DYNAMIC_STREAMS_CHANGE, processNumDynamicStreamsChange); + dispatcher.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, processSwitchingChange); + dispatcher.addEventListener(LoadEvent.BYTES_TOTAL_CHANGE, processBytesTotalChange); + dispatcher.addEventListener(LoadEvent.LOAD_STATE_CHANGE, processLoadStateChange); + dispatcher.addEventListener(PlayEvent.CAN_PAUSE_CHANGE, processCanPauseChange); + dispatcher.addEventListener(PlayEvent.PLAY_STATE_CHANGE, processPlayStateChange); + dispatcher.addEventListener(SeekEvent.SEEKING_CHANGE, processSeekingChange); + dispatcher.addEventListener(TimeEvent.COMPLETE, processComplete); + dispatcher.addEventListener(TimeEvent.DURATION_CHANGE, processDurationChange); + + } + + // Overrides + // + + private function processAutoSwitchChange(event:DynamicStreamEvent):void + { + debugger.send("EVENT","autoSwitchChange", event.autoSwitch); + } + + private function processBufferingChange(event:BufferEvent):void + { + debugger.send("EVENT","bufferingChange", event.buffering); + } + + private function processBufferTimeChange(event:BufferEvent):void + { + debugger.send("EVENT","bufferTimeChange", event.bufferTime); + } + + private function processComplete(event:TimeEvent):void + { + debugger.send("EVENT","complete"); + } + + private function processCanPauseChange(event:PlayEvent):void + { + debugger.send("EVENT","canPauseChange", event.canPause); + } + + private function processDisplayObjectChange(event:DisplayObjectEvent):void + { + debugger.send("EVENT","displayObjectChange"); + } + + private function processDurationChange(event:TimeEvent):void + { + debugger.send("EVENT","durantionChange", event.time); + } + + private function processLoadStateChange(event:LoadEvent):void + { + debugger.send("EVENT","loadStateChange", event.loadState); + } + + private function processBytesTotalChange(event:LoadEvent):void + { + debugger.send("EVENT","bytesTotalChange", event.bytes); + } + + private function processMediaSizeChange(event:DisplayObjectEvent):void + { + debugger.send("EVENT","mediaSizeChange", "[" + event.newWidth + ", " + event.newHeight + "]"); + } + + private function processMutedChange(event:AudioEvent):void + { + debugger.send("EVENT","mutedChange", event.muted); + } + + private function processNumDynamicStreamsChange(event:DynamicStreamEvent):void + { + debugger.send("EVENT","numDynamicStreamsChange"); + } + + private function processPanChange(event:AudioEvent):void + { + debugger.send("EVENT","panChange", event.pan); + } + + private function processPlayStateChange(event:PlayEvent):void + { + debugger.send("EVENT","playStateChange", event.playState); + } + + private function processSeekingChange(event:SeekEvent):void + { + debugger.send("EVENT","seekingChange", event.seeking + ", " + event.time); + } + + private function processSwitchingChange(event:DynamicStreamEvent):void + { + debugger.send("EVENT","switchingChange", event.switching); + } + + private function processVolumeChange(event:AudioEvent):void + { + debugger.send("EVENT","volumeChange", event.volume); + } + + private function processDRMStateChange(event:DRMEvent):void + { + var error:String = event.mediaError ? "ErrorID: " + event.mediaError.errorID + ", Message: " + event.mediaError.message + ", Detail: " + event.mediaError.detail : ""; + debugger.send("EVENT","drmStateChange", event.drmState, "[", error, "]"); + } + + // Internals + // + + private var dispatcher:TraitEventDispatcher; + private var debugger:Debugger; + } } \ No newline at end of file diff --git a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerLogger.as b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerLogger.as index 88e8a70..231c4ee 100644 --- a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerLogger.as +++ b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerLogger.as @@ -1,67 +1,67 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.player.debug -{ - import org.osmf.logging.TraceLogger; - - public class DebuggerLogger extends TraceLogger - { - public function DebuggerLogger(name:String, debugger:Debugger) - { - super(name); - - this.name = name; - this.debugger = debugger; - } - - // Internals - // - - override protected function logMessage(level:String, message:String, params:Array):void - { - var msg:String = ""; - - // add name and params - msg += "[" + name + "] " + applyParams(message, params); - - // trace the message - debugger.send(level, msg); - } - - private function applyParams(message:String, params:Array):String - { - var result:String = message; - var numParams:int = params.length; - - for (var i:int = 0; i < numParams; i++) - { - result = result.replace(new RegExp("\\{" + i + "\\}", "g"), params[i]); - } - - return result; - } - - private var name:String; - private var debugger:Debugger; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.player.debug +{ + import org.osmf.logging.TraceLogger; + + public class DebuggerLogger extends TraceLogger + { + public function DebuggerLogger(name:String, debugger:Debugger) + { + super(name); + + this.name = name; + this.debugger = debugger; + } + + // Internals + // + + override protected function logMessage(level:String, message:String, params:Array):void + { + var msg:String = ""; + + // add name and params + msg += "[" + name + "] " + applyParams(message, params); + + // trace the message + debugger.send(level, msg); + } + + private function applyParams(message:String, params:Array):String + { + var result:String = message; + var numParams:int = params.length; + + for (var i:int = 0; i < numParams; i++) + { + result = result.replace(new RegExp("\\{" + i + "\\}", "g"), params[i]); + } + + return result; + } + + private var name:String; + private var debugger:Debugger; + } } \ No newline at end of file diff --git a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerLoggerFactory.as b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerLoggerFactory.as index aac9d78..bf60049 100644 --- a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerLoggerFactory.as +++ b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/debug/DebuggerLoggerFactory.as @@ -1,48 +1,48 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.player.debug -{ - import org.osmf.logging.Logger; - import org.osmf.logging.LoggerFactory; - - public class DebuggerLoggerFactory extends LoggerFactory - { - public function DebuggerLoggerFactory(debugger:Debugger) - { - super(); - - this.debugger = debugger; - } - - override public function getLogger(name:String):Logger - { - return new DebuggerLogger(name, debugger); - } - - // Internals - // - - private var debugger:Debugger; - - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.player.debug +{ + import org.osmf.logging.Logger; + import org.osmf.logging.LoggerFactory; + + public class DebuggerLoggerFactory extends LoggerFactory + { + public function DebuggerLoggerFactory(debugger:Debugger) + { + super(); + + this.debugger = debugger; + } + + override public function getLogger(name:String):Logger + { + return new DebuggerLogger(name, debugger); + } + + // Internals + // + + private var debugger:Debugger; + + } } \ No newline at end of file diff --git a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/preloader/Preloader.as b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/preloader/Preloader.as index 34da2c6..3d4aa80 100644 --- a/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/preloader/Preloader.as +++ b/lib/osmf/samples/OSMFPlayer/src/org/osmf/player/preloader/Preloader.as @@ -1,116 +1,116 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.player.preloader -{ - import flash.display.MovieClip; - import flash.display.StageAlign; - import flash.events.Event; - import flash.events.ProgressEvent; - import flash.utils.getDefinitionByName; - - import org.osmf.chrome.configuration.Configuration; - import org.osmf.player.debug.Debugger; - - public class Preloader extends MovieClip - { - public function Preloader() - { - super(); - - // Set the SWF scale mode, and listen to the stage change - // dimensions: - stage.align = StageAlign.TOP_LEFT; - - addEventListener(Event.ENTER_FRAME, progressDrawingEventHandler); - stage.addEventListener(Event.RESIZE, progressDrawingEventHandler); - loaderInfo.addEventListener(ProgressEvent.PROGRESS, progressDrawingEventHandler); - loaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete); - - progressDrawingEventHandler(); - - CONFIG::DEBUG - { - _debugger = new Debugger(loaderInfo.parameters["id"]); - } - } - - public function get debugger():Debugger - { - return _debugger; - } - - // Internals - // - - private var _debugger:Debugger; - - private static const WIDTH:Number = 150; - private static const HEIGHT:Number = 12; - - public const configuration:Configuration = new Configuration(); - - private function progressDrawingEventHandler(event:Event = null):void - { - graphics.clear(); - graphics.lineStyle(1, 0x000000, 0.5); - var x:Number = stage.stageWidth / 2 - WIDTH / 2; - var y:Number = stage.stageHeight / 2 - HEIGHT / 2 - var p:Number = loaderInfo.bytesLoaded / loaderInfo.bytesTotal; - graphics.drawRect(x, y, WIDTH, HEIGHT); - graphics.lineStyle(1, 0xFFFFFF, 1); - graphics.drawRect(x + 1, y + 1, WIDTH - 2, HEIGHT - 2); - graphics.beginFill(0xFFFFFF, 1); - graphics.drawRect(x + 1, y + 1, (WIDTH - 2) * p, HEIGHT - 2); - graphics.endFill(); - } - - private function onLoaderComplete(event:Event):void - { - removeEventListener(Event.ENTER_FRAME, progressDrawingEventHandler); - stage.removeEventListener(Event.RESIZE, progressDrawingEventHandler); - loaderInfo.removeEventListener(ProgressEvent.PROGRESS, progressDrawingEventHandler); - loaderInfo.removeEventListener(Event.COMPLETE, onLoaderComplete); - - configuration.addEventListener(Event.COMPLETE, onConfigurationComplete); - var configurationFileURL:String = loaderInfo.parameters.configuration; - if (configurationFileURL != null) - { - configuration.loadFromFile(configurationFileURL, true); - } - else - { - trace("WARNING: configuration file not specified in SWF parameters"); - onConfigurationComplete(null); - } - } - - private function onConfigurationComplete(event:Event):void - { - graphics.clear(); - nextFrame(); - - var player:Class = getDefinitionByName("OSMFPlayer") as Class; - addChild(new player(this)); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.player.preloader +{ + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.events.Event; + import flash.events.ProgressEvent; + import flash.utils.getDefinitionByName; + + import org.osmf.chrome.configuration.Configuration; + import org.osmf.player.debug.Debugger; + + public class Preloader extends MovieClip + { + public function Preloader() + { + super(); + + // Set the SWF scale mode, and listen to the stage change + // dimensions: + stage.align = StageAlign.TOP_LEFT; + + addEventListener(Event.ENTER_FRAME, progressDrawingEventHandler); + stage.addEventListener(Event.RESIZE, progressDrawingEventHandler); + loaderInfo.addEventListener(ProgressEvent.PROGRESS, progressDrawingEventHandler); + loaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete); + + progressDrawingEventHandler(); + + CONFIG::DEBUG + { + _debugger = new Debugger(loaderInfo.parameters["id"]); + } + } + + public function get debugger():Debugger + { + return _debugger; + } + + // Internals + // + + private var _debugger:Debugger; + + private static const WIDTH:Number = 150; + private static const HEIGHT:Number = 12; + + public const configuration:Configuration = new Configuration(); + + private function progressDrawingEventHandler(event:Event = null):void + { + graphics.clear(); + graphics.lineStyle(1, 0x000000, 0.5); + var x:Number = stage.stageWidth / 2 - WIDTH / 2; + var y:Number = stage.stageHeight / 2 - HEIGHT / 2 + var p:Number = loaderInfo.bytesLoaded / loaderInfo.bytesTotal; + graphics.drawRect(x, y, WIDTH, HEIGHT); + graphics.lineStyle(1, 0xFFFFFF, 1); + graphics.drawRect(x + 1, y + 1, WIDTH - 2, HEIGHT - 2); + graphics.beginFill(0xFFFFFF, 1); + graphics.drawRect(x + 1, y + 1, (WIDTH - 2) * p, HEIGHT - 2); + graphics.endFill(); + } + + private function onLoaderComplete(event:Event):void + { + removeEventListener(Event.ENTER_FRAME, progressDrawingEventHandler); + stage.removeEventListener(Event.RESIZE, progressDrawingEventHandler); + loaderInfo.removeEventListener(ProgressEvent.PROGRESS, progressDrawingEventHandler); + loaderInfo.removeEventListener(Event.COMPLETE, onLoaderComplete); + + configuration.addEventListener(Event.COMPLETE, onConfigurationComplete); + var configurationFileURL:String = loaderInfo.parameters.configuration; + if (configurationFileURL != null) + { + configuration.loadFromFile(configurationFileURL, true); + } + else + { + trace("WARNING: configuration file not specified in SWF parameters"); + onConfigurationComplete(null); + } + } + + private function onConfigurationComplete(event:Event):void + { + graphics.clear(); + nextFrame(); + + var player:Class = getDefinitionByName("OSMFPlayer") as Class; + addChild(new player(this)); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/OSMFPlayerDebugConsole/.actionScriptProperties b/lib/osmf/samples/OSMFPlayerDebugConsole/.actionScriptProperties index b36cadc..16459bf 100644 --- a/lib/osmf/samples/OSMFPlayerDebugConsole/.actionScriptProperties +++ b/lib/osmf/samples/OSMFPlayerDebugConsole/.actionScriptProperties @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/OSMFPlayerDebugConsole/.flexProperties b/lib/osmf/samples/OSMFPlayerDebugConsole/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/OSMFPlayerDebugConsole/.flexProperties +++ b/lib/osmf/samples/OSMFPlayerDebugConsole/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/OSMFPlayerDebugConsole/src/OSMFPlayerDebugConsole-app.xml b/lib/osmf/samples/OSMFPlayerDebugConsole/src/OSMFPlayerDebugConsole-app.xml index 9efe323..0ad7c42 100644 --- a/lib/osmf/samples/OSMFPlayerDebugConsole/src/OSMFPlayerDebugConsole-app.xml +++ b/lib/osmf/samples/OSMFPlayerDebugConsole/src/OSMFPlayerDebugConsole-app.xml @@ -1,135 +1,135 @@ - - - - - - - OSMFPlayerDebugConsole - - - OSMFPlayerDebugConsole - - - OSMFPlayerDebugConsole - - - v1 - - - - - - - - - - - - [This value will be overwritten by Flex Builder in the output app.xml] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + OSMFPlayerDebugConsole + + + OSMFPlayerDebugConsole + + + OSMFPlayerDebugConsole + + + v1 + + + + + + + + + + + + [This value will be overwritten by Flex Builder in the output app.xml] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/OSMFPlayerDebugConsole/src/OSMFPlayerDebugConsole.mxml b/lib/osmf/samples/OSMFPlayerDebugConsole/src/OSMFPlayerDebugConsole.mxml index f07f229..26813cd 100644 --- a/lib/osmf/samples/OSMFPlayerDebugConsole/src/OSMFPlayerDebugConsole.mxml +++ b/lib/osmf/samples/OSMFPlayerDebugConsole/src/OSMFPlayerDebugConsole.mxml @@ -1,120 +1,120 @@ - - - - - - - - - - - - - - - - - - - - - - - - 4) - { - var params:Array = args.slice(4) - args = args.slice(0,4); - args[4] = params.toString(); - } - log.addItemAt(args, 0); - } - } - } - - private function messageFilterChange():void - { - regExp = new RegExp(messageFilter.text || ""); - log.refresh(); - } - - private function filterFunction(value:Array):Boolean - { - var result:Boolean = true; - if (regExp) - { - result = !regExp.test(value[3].toString()); - } - return result; - } - - private var receiver:LocalConnection; - private var log:ArrayCollection; - private var regExp:RegExp; - - [Bindable] - private var paused:Boolean; - ]]> - - - + + + + + + + + + + + + + + + + + + + + + + + + 4) + { + var params:Array = args.slice(4) + args = args.slice(0,4); + args[4] = params.toString(); + } + log.addItemAt(args, 0); + } + } + } + + private function messageFilterChange():void + { + regExp = new RegExp(messageFilter.text || ""); + log.refresh(); + } + + private function filterFunction(value:Array):Boolean + { + var result:Boolean = true; + if (regExp) + { + result = !regExp.test(value[3].toString()); + } + return result; + } + + private var receiver:LocalConnection; + private var log:ArrayCollection; + private var regExp:RegExp; + + [Bindable] + private var paused:Boolean; + ]]> + + + diff --git a/lib/osmf/samples/SMILPlugin/.actionScriptProperties b/lib/osmf/samples/SMILPlugin/.actionScriptProperties index f731207..212dc8d 100644 --- a/lib/osmf/samples/SMILPlugin/.actionScriptProperties +++ b/lib/osmf/samples/SMILPlugin/.actionScriptProperties @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/SMILPlugin/SMILPlugin-build-config.xml b/lib/osmf/samples/SMILPlugin/SMILPlugin-build-config.xml index 23acde6..4d5f63e 100644 --- a/lib/osmf/samples/SMILPlugin/SMILPlugin-build-config.xml +++ b/lib/osmf/samples/SMILPlugin/SMILPlugin-build-config.xml @@ -33,8 +33,8 @@ - @@ -48,10 +48,10 @@ false - @@ -109,11 +109,11 @@ - @@ -121,8 +121,8 @@ - @@ -141,13 +141,13 @@ - @@ -157,12 +157,12 @@ flash.fonts.BatikFontManager - @@ -282,19 +282,19 @@ - - - @@ -308,10 +308,10 @@ true - - true diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/SMILPluginInfo.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/SMILPluginInfo.as index aa7ba24..963ce1f 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/SMILPluginInfo.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/SMILPluginInfo.as @@ -1,65 +1,65 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil -{ - import __AS3__.vec.Vector; - - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.PluginInfo; - import org.osmf.smil.elements.SMILElement; - import org.osmf.smil.loader.SMILLoader; - - /** - * Encapsulation of the SMIL plugin. - */ - public class SMILPluginInfo extends PluginInfo - { - /** - * Constructor. - */ - public function SMILPluginInfo() - { - var items:Vector. = new Vector.(); - - var item:MediaFactoryItem = new MediaFactoryItem("org.osmf.smil.SMILPluginInfo", new SMILLoader().canHandleResource, createSMILProxyElement); - items.push(item); - - super(items); - } - - private function createSMILProxyElement():MediaElement - { - return new SMILElement(null, new SMILLoader(mediaFactory)); - } - - override public function initializePlugin(resource:MediaResourceBase):void - { - // We'll use the player-supplied MediaFactory for creating all MediaElements. - mediaFactory = resource.getMetadataValue(PluginInfo.PLUGIN_MEDIAFACTORY_NAMESPACE) as MediaFactory; - } - - private var mediaFactory:MediaFactory; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil +{ + import __AS3__.vec.Vector; + + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.PluginInfo; + import org.osmf.smil.elements.SMILElement; + import org.osmf.smil.loader.SMILLoader; + + /** + * Encapsulation of the SMIL plugin. + */ + public class SMILPluginInfo extends PluginInfo + { + /** + * Constructor. + */ + public function SMILPluginInfo() + { + var items:Vector. = new Vector.(); + + var item:MediaFactoryItem = new MediaFactoryItem("org.osmf.smil.SMILPluginInfo", new SMILLoader().canHandleResource, createSMILProxyElement); + items.push(item); + + super(items); + } + + private function createSMILProxyElement():MediaElement + { + return new SMILElement(null, new SMILLoader(mediaFactory)); + } + + override public function initializePlugin(resource:MediaResourceBase):void + { + // We'll use the player-supplied MediaFactory for creating all MediaElements. + mediaFactory = resource.getMetadataValue(PluginInfo.PLUGIN_MEDIAFACTORY_NAMESPACE) as MediaFactory; + } + + private var mediaFactory:MediaFactory; + } +} diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/elements/SMILElement.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/elements/SMILElement.as index a3308c2..60fb72c 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/elements/SMILElement.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/elements/SMILElement.as @@ -1,40 +1,40 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.elements -{ - import org.osmf.elements.LoadFromDocumentElement; - import org.osmf.media.MediaResourceBase; - import org.osmf.smil.loader.SMILLoader; - - public class SMILElement extends LoadFromDocumentElement - { - public function SMILElement(resource:MediaResourceBase = null, loader:SMILLoader = null) - { - if (loader == null) - { - loader = new SMILLoader(); - } - super(resource, loader); - } - - } +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.elements +{ + import org.osmf.elements.LoadFromDocumentElement; + import org.osmf.media.MediaResourceBase; + import org.osmf.smil.loader.SMILLoader; + + public class SMILElement extends LoadFromDocumentElement + { + public function SMILElement(resource:MediaResourceBase = null, loader:SMILLoader = null) + { + if (loader == null) + { + loader = new SMILLoader(); + } + super(resource, loader); + } + + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/loader/SMILLoader.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/loader/SMILLoader.as index fed040f..44cf2c1 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/loader/SMILLoader.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/loader/SMILLoader.as @@ -1,222 +1,222 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.loader -{ - import __AS3__.vec.Vector; - - import flash.events.ErrorEvent; - import flash.events.Event; - import flash.events.IOErrorEvent; - import flash.events.SecurityErrorEvent; - import flash.net.URLLoader; - import flash.net.URLRequest; - - import org.osmf.elements.proxyClasses.LoadFromDocumentLoadTrait; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorEvent; - import org.osmf.events.MediaFactoryEvent; - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.metadata.MetadataNamespaces; - import org.osmf.smil.media.SMILMediaGenerator; - import org.osmf.smil.model.SMILDocument; - import org.osmf.smil.parser.SMILParser; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.utils.URL; - - /** - * The SMILLoader class will load a SMIL (Synchronized - * Multimedia Integration Language) file and generate - * a loaded context. - */ - public class SMILLoader extends LoaderBase - { - /** - * The SMIL mime type as of SMIL 3.0. - */ - public static const SMIL_MIME_TYPE:String = "application/smil+xml"; - - /** - * Constructor. - * - * @param factory The factory that is used to create MediaElements based on the - * media specified in the SMIL file. A default factory is created for the base - * OSMF media types: Video, Audio, Image, and SWF. - */ - public function SMILLoader(mediaFactory:MediaFactory = null) - { - super(); - - supportedMimeTypes.push(SMIL_MIME_TYPE); - - factory = mediaFactory; - if (factory == null) - { - factory = new DefaultMediaFactory(); - } - } - - /** - * @private - */ - override public function canHandleResource(resource:MediaResourceBase):Boolean - { - var canHandle:Boolean = false; - - // We should bypass the rest of this method if a MIME type - // is explicitly specified (whether it matches or not). - if (resource && resource.mimeType != null) - { - canHandle = resource.mimeType == SMIL_MIME_TYPE; - } - else if (resource is URLResource) - { - var urlResource:URLResource = URLResource(resource); - var url:URL = new URL(urlResource.url); - canHandle = (url.path.search(/\.smi$|\.smil$/i) != -1); - } - - return canHandle; - } - - /** - * @private - */ - override protected function executeLoad(loadTrait:LoadTrait):void - { - updateLoadTrait(loadTrait, LoadState.LOADING); - - var urlLoader:URLLoader = new URLLoader(new URLRequest(URLResource(loadTrait.resource).url)); - setupListeners(); - - function setupListeners(add:Boolean=true):void - { - if (add) - { - urlLoader.addEventListener(Event.COMPLETE, onComplete); - urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onError); - urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError); - } - else - { - urlLoader.removeEventListener(Event.COMPLETE, onComplete); - urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, onError); - urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError); - } - } - - function onError(event:ErrorEvent):void - { - setupListeners(false); - updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(0, event.text))); - } - - function onComplete(event:Event):void - { - setupListeners(false); - - try - { - var parser:SMILParser = createParser(); - var smilDocument:SMILDocument = parser.parse(event.target.data); - finishLoad(loadTrait, smilDocument); - } - catch (parseError:Error) - { - updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(parseError.errorID, parseError.message))); - } - } - } - - /** - * @private - */ - override protected function executeUnload(loadTrait:LoadTrait):void - { - updateLoadTrait(loadTrait, LoadState.UNLOADING); - updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); - } - - /** - * Override to provide a custom media generator. - */ - protected function createMediaGenerator():SMILMediaGenerator - { - return new SMILMediaGenerator(); - } - - /** - * Override to provide a custom SMIL parser. - */ - protected function createParser():SMILParser - { - return new SMILParser(); - } - - private function finishLoad(loadTrait:LoadTrait, smilDocument:SMILDocument):void - { - var mediaGenerator:SMILMediaGenerator = createMediaGenerator(); - - // Listen for created elements so that we can add the "derived" resource metadata - // to them. Use a high priority so that we can add the metadata before clients - // get the event. - factory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate, false, int.MAX_VALUE); - var loadedElement:MediaElement = mediaGenerator.createMediaElement(loadTrait.resource, smilDocument, factory); - factory.removeEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate); - - if (loadedElement == null) - { - updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); - } - else - { - var elementLoadTrait:LoadFromDocumentLoadTrait = loadTrait as LoadFromDocumentLoadTrait; - if (elementLoadTrait) - { - elementLoadTrait.mediaElement = loadedElement; - } - - updateLoadTrait(loadTrait, LoadState.READY); - } - - function onMediaElementCreate(event:MediaFactoryEvent):void - { - var derivedResource:MediaResourceBase = event.mediaElement.resource; - if (derivedResource != null) - { - derivedResource.addMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA, loadTrait.resource); - } - } - } - - private var supportedMimeTypes:Vector. = new Vector.(); - private var mediaTypesSupported:Vector. = new Vector.(); - private var factory:MediaFactory; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.loader +{ + import __AS3__.vec.Vector; + + import flash.events.ErrorEvent; + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.SecurityErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + + import org.osmf.elements.proxyClasses.LoadFromDocumentLoadTrait; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorEvent; + import org.osmf.events.MediaFactoryEvent; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.metadata.MetadataNamespaces; + import org.osmf.smil.media.SMILMediaGenerator; + import org.osmf.smil.model.SMILDocument; + import org.osmf.smil.parser.SMILParser; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.utils.URL; + + /** + * The SMILLoader class will load a SMIL (Synchronized + * Multimedia Integration Language) file and generate + * a loaded context. + */ + public class SMILLoader extends LoaderBase + { + /** + * The SMIL mime type as of SMIL 3.0. + */ + public static const SMIL_MIME_TYPE:String = "application/smil+xml"; + + /** + * Constructor. + * + * @param factory The factory that is used to create MediaElements based on the + * media specified in the SMIL file. A default factory is created for the base + * OSMF media types: Video, Audio, Image, and SWF. + */ + public function SMILLoader(mediaFactory:MediaFactory = null) + { + super(); + + supportedMimeTypes.push(SMIL_MIME_TYPE); + + factory = mediaFactory; + if (factory == null) + { + factory = new DefaultMediaFactory(); + } + } + + /** + * @private + */ + override public function canHandleResource(resource:MediaResourceBase):Boolean + { + var canHandle:Boolean = false; + + // We should bypass the rest of this method if a MIME type + // is explicitly specified (whether it matches or not). + if (resource && resource.mimeType != null) + { + canHandle = resource.mimeType == SMIL_MIME_TYPE; + } + else if (resource is URLResource) + { + var urlResource:URLResource = URLResource(resource); + var url:URL = new URL(urlResource.url); + canHandle = (url.path.search(/\.smi$|\.smil$/i) != -1); + } + + return canHandle; + } + + /** + * @private + */ + override protected function executeLoad(loadTrait:LoadTrait):void + { + updateLoadTrait(loadTrait, LoadState.LOADING); + + var urlLoader:URLLoader = new URLLoader(new URLRequest(URLResource(loadTrait.resource).url)); + setupListeners(); + + function setupListeners(add:Boolean=true):void + { + if (add) + { + urlLoader.addEventListener(Event.COMPLETE, onComplete); + urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onError); + urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError); + } + else + { + urlLoader.removeEventListener(Event.COMPLETE, onComplete); + urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, onError); + urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError); + } + } + + function onError(event:ErrorEvent):void + { + setupListeners(false); + updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(0, event.text))); + } + + function onComplete(event:Event):void + { + setupListeners(false); + + try + { + var parser:SMILParser = createParser(); + var smilDocument:SMILDocument = parser.parse(event.target.data); + finishLoad(loadTrait, smilDocument); + } + catch (parseError:Error) + { + updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(parseError.errorID, parseError.message))); + } + } + } + + /** + * @private + */ + override protected function executeUnload(loadTrait:LoadTrait):void + { + updateLoadTrait(loadTrait, LoadState.UNLOADING); + updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); + } + + /** + * Override to provide a custom media generator. + */ + protected function createMediaGenerator():SMILMediaGenerator + { + return new SMILMediaGenerator(); + } + + /** + * Override to provide a custom SMIL parser. + */ + protected function createParser():SMILParser + { + return new SMILParser(); + } + + private function finishLoad(loadTrait:LoadTrait, smilDocument:SMILDocument):void + { + var mediaGenerator:SMILMediaGenerator = createMediaGenerator(); + + // Listen for created elements so that we can add the "derived" resource metadata + // to them. Use a high priority so that we can add the metadata before clients + // get the event. + factory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate, false, int.MAX_VALUE); + var loadedElement:MediaElement = mediaGenerator.createMediaElement(loadTrait.resource, smilDocument, factory); + factory.removeEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate); + + if (loadedElement == null) + { + updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); + } + else + { + var elementLoadTrait:LoadFromDocumentLoadTrait = loadTrait as LoadFromDocumentLoadTrait; + if (elementLoadTrait) + { + elementLoadTrait.mediaElement = loadedElement; + } + + updateLoadTrait(loadTrait, LoadState.READY); + } + + function onMediaElementCreate(event:MediaFactoryEvent):void + { + var derivedResource:MediaResourceBase = event.mediaElement.resource; + if (derivedResource != null) + { + derivedResource.addMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA, loadTrait.resource); + } + } + } + + private var supportedMimeTypes:Vector. = new Vector.(); + private var mediaTypesSupported:Vector. = new Vector.(); + private var factory:MediaFactory; + } +} diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/media/SMILMediaGenerator.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/media/SMILMediaGenerator.as index 5c9759a..9883e5a 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/media/SMILMediaGenerator.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/media/SMILMediaGenerator.as @@ -1,300 +1,300 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.media -{ - import org.osmf.elements.CompositeElement; - import org.osmf.elements.DurationElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.ProxyElement; - import org.osmf.elements.SerialElement; - import org.osmf.elements.VideoElement; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.MediaType; - import org.osmf.media.URLResource; - import org.osmf.net.DynamicStreamingItem; - import org.osmf.net.DynamicStreamingResource; - import org.osmf.net.StreamType; - import org.osmf.net.StreamingURLResource; - import org.osmf.smil.model.SMILDocument; - import org.osmf.smil.model.SMILElement; - import org.osmf.smil.model.SMILElementType; - import org.osmf.smil.model.SMILMediaElement; - import org.osmf.smil.model.SMILMetaElement; - - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } - - /** - * A utility class for creating MediaElements from a SMILDocument. - */ - public class SMILMediaGenerator - { - /** - * Creates the relevant MediaElement from the SMILDocument. - * - * @param resource The original resource that was given to the load trait. - * This resource might be a URLto a SMIL document, for example, and may - * contain metadata we need to retain. - * @param smilDocument The SMILDocument to use for media creation. - * @returns A new MediaElement based on the information found in the SMILDocument. - */ - public function createMediaElement(resource:MediaResourceBase, smilDocument:SMILDocument, factory:MediaFactory):MediaElement - { - this.factory = factory; - - CONFIG::LOGGING - { - traceElements(smilDocument); - } - - var mediaElement:MediaElement; - - for (var i:int = 0; i < smilDocument.numElements; i++) - { - var smilElement:SMILElement = smilDocument.getElementAt(i); - mediaElement = internalCreateMediaElement(resource, null, smilDocument, smilElement); - } - - return mediaElement; - } - - /** - * Recursive function to create a media element and all of it's children. - */ - private function internalCreateMediaElement(originalResource:MediaResourceBase, parentMediaElement:MediaElement, - smilDocument:SMILDocument, smilElement:SMILElement):MediaElement - { - var mediaResource:MediaResourceBase = null; - - var mediaElement:MediaElement; - - switch (smilElement.type) - { - case SMILElementType.SWITCH: - mediaResource = createDynamicStreamingResource(smilElement, smilDocument); - break; - case SMILElementType.PARALLEL: - var parallelElement:ParallelElement = new ParallelElement(); - mediaElement = parallelElement; - break; - case SMILElementType.SEQUENCE: - var serialElement:SerialElement = new SerialElement(); - mediaElement = serialElement; - break; - case SMILElementType.VIDEO: - var resource:StreamingURLResource = new StreamingURLResource((smilElement as SMILMediaElement).src); - resource.mediaType = MediaType.VIDEO; - var videoElement:MediaElement = factory.createMediaElement(resource); - var smilVideoElement:SMILMediaElement = smilElement as SMILMediaElement; - - if (!isNaN(smilVideoElement.clipBegin) && smilVideoElement.clipBegin > 0 && - !isNaN(smilVideoElement.clipEnd) && smilVideoElement.clipEnd > 0) - { - resource.clipStartTime = smilVideoElement.clipBegin; - resource.clipEndTime = smilVideoElement.clipEnd; - } - - var duration:Number = (smilElement as SMILMediaElement).duration; - if (!isNaN(duration) && duration > 0) - { - if (videoElement is VideoElement) - { - (videoElement as VideoElement).defaultDuration = duration; - } - else if (videoElement is ProxyElement) - { - // Try to find the proxied video element (fix for FM-1020) - var tempMediaElement:MediaElement = videoElement; - while (tempMediaElement is ProxyElement) - { - tempMediaElement = (tempMediaElement as ProxyElement).proxiedElement; - } - - if (tempMediaElement != null && tempMediaElement is VideoElement) - { - (tempMediaElement as VideoElement).defaultDuration = duration; - } - } - } - (parentMediaElement as CompositeElement).addChild(videoElement); - break; - case SMILElementType.IMAGE: - var imageResource:URLResource = new URLResource((smilElement as SMILMediaElement).src); - imageResource.mediaType = MediaType.IMAGE; - var imageElement:MediaElement = factory.createMediaElement(imageResource); - var dur:Number = (smilElement as SMILMediaElement).duration; - var durationElement:DurationElement = new DurationElement(dur, imageElement); - (parentMediaElement as CompositeElement).addChild(durationElement); - break; - case SMILElementType.AUDIO: - var audioResource:URLResource = new URLResource((smilElement as SMILMediaElement).src); - audioResource.mediaType = MediaType.AUDIO; - var audioElement:MediaElement = factory.createMediaElement(audioResource); - (parentMediaElement as CompositeElement).addChild(audioElement); - break; - } - - if (mediaElement != null) - { - for (var i:int = 0; i < smilElement.numChildren; i++) - { - var childElement:SMILElement = smilElement.getChildAt(i); - internalCreateMediaElement(originalResource, mediaElement, smilDocument, childElement); - } - - // Fix for FM-931, make sure we support nested elements - if (parentMediaElement is CompositeElement) - { - (parentMediaElement as CompositeElement).addChild(mediaElement); - } - } - else if (mediaResource != null) - { - // Make sure we transfer any resource metadata from the original resource - for each (var metadataNS:String in originalResource.metadataNamespaceURLs) - { - var metadata:Object = originalResource.getMetadataValue(metadataNS); - mediaResource.addMetadataValue(metadataNS, metadata); - } - - mediaElement = factory.createMediaElement(mediaResource); - - if (parentMediaElement is CompositeElement) - { - (parentMediaElement as CompositeElement).addChild(mediaElement); - } - } - - return mediaElement; - } - - private function createDynamicStreamingResource(switchElement:SMILElement, smilDocument:SMILDocument):MediaResourceBase - { - var dsr:DynamicStreamingResource = null; - var hostURL:String; - - for (var i:int = 0; i < smilDocument.numElements; i++) - { - var smilElement:SMILElement = smilDocument.getElementAt(i); - switch (smilElement.type) - { - case SMILElementType.META: - hostURL = (smilElement as SMILMetaElement).base; - if (hostURL != null) - { - dsr = createDynamicStreamingItems(switchElement, hostURL); - } - break; - } - } - - return dsr; - } - - private function createDynamicStreamingItems(switchElement:SMILElement, hostURL:String):DynamicStreamingResource - { - var dsr:DynamicStreamingResource = null; - var streamItems:Vector. = new Vector.(); - - for (var i:int = 0; i < switchElement.numChildren; i++) - { - var smilElement:SMILElement = switchElement.getChildAt(i); - if (smilElement.type == SMILElementType.VIDEO) - { - var videoElement:SMILMediaElement = smilElement as SMILMediaElement; - - // We need to divide the bitrate by 1000 because the DynamicStreamingItem class - // requires the bitrate in kilobits per second. - var dsi:DynamicStreamingItem = new DynamicStreamingItem(videoElement.src, videoElement.bitrate/1000); - streamItems.push(dsi); - } - } - - if (streamItems.length) - { - dsr = new DynamicStreamingResource(hostURL); - dsr.streamItems = streamItems; - dsr.streamType = StreamType.LIVE_OR_RECORDED; - } - - return dsr; - } - - - private function traceElements(smilDocument:SMILDocument):void - { - CONFIG::LOGGING - { - debugLog(">>> SMILMediaGenerator.traceElements() "); - - for (var i:int = 0; i < smilDocument.numElements; i++) - { - var smilElement:SMILElement = smilDocument.getElementAt(i); - traceElement(smilElement) - } - - function traceElement(e:SMILElement, level:int=0):void - { - var levelMarker:String = "*"; - - for (var j:int = 0; j < level; j++) - { - levelMarker += "*"; - } - - debugLog(levelMarker + e.type); - level++; - - for (var k:int = 0; k < e.numChildren; k++) - { - traceElement(e.getChildAt(k), level); - } - - level--; - } - } - } - - private function debugLog(msg:String):void - { - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug(msg); - } - } - } - - CONFIG::LOGGING - { - private static const logger:Logger = org.osmf.logging.Log.getLogger("org.osmf.smil.media.SMILMediaGenerator"); - } - - private var factory:MediaFactory; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.media +{ + import org.osmf.elements.CompositeElement; + import org.osmf.elements.DurationElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.ProxyElement; + import org.osmf.elements.SerialElement; + import org.osmf.elements.VideoElement; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.MediaType; + import org.osmf.media.URLResource; + import org.osmf.net.DynamicStreamingItem; + import org.osmf.net.DynamicStreamingResource; + import org.osmf.net.StreamType; + import org.osmf.net.StreamingURLResource; + import org.osmf.smil.model.SMILDocument; + import org.osmf.smil.model.SMILElement; + import org.osmf.smil.model.SMILElementType; + import org.osmf.smil.model.SMILMediaElement; + import org.osmf.smil.model.SMILMetaElement; + + CONFIG::LOGGING + { + import org.osmf.logging.Logger; + import org.osmf.logging.Log; + } + + /** + * A utility class for creating MediaElements from a SMILDocument. + */ + public class SMILMediaGenerator + { + /** + * Creates the relevant MediaElement from the SMILDocument. + * + * @param resource The original resource that was given to the load trait. + * This resource might be a URLto a SMIL document, for example, and may + * contain metadata we need to retain. + * @param smilDocument The SMILDocument to use for media creation. + * @returns A new MediaElement based on the information found in the SMILDocument. + */ + public function createMediaElement(resource:MediaResourceBase, smilDocument:SMILDocument, factory:MediaFactory):MediaElement + { + this.factory = factory; + + CONFIG::LOGGING + { + traceElements(smilDocument); + } + + var mediaElement:MediaElement; + + for (var i:int = 0; i < smilDocument.numElements; i++) + { + var smilElement:SMILElement = smilDocument.getElementAt(i); + mediaElement = internalCreateMediaElement(resource, null, smilDocument, smilElement); + } + + return mediaElement; + } + + /** + * Recursive function to create a media element and all of it's children. + */ + private function internalCreateMediaElement(originalResource:MediaResourceBase, parentMediaElement:MediaElement, + smilDocument:SMILDocument, smilElement:SMILElement):MediaElement + { + var mediaResource:MediaResourceBase = null; + + var mediaElement:MediaElement; + + switch (smilElement.type) + { + case SMILElementType.SWITCH: + mediaResource = createDynamicStreamingResource(smilElement, smilDocument); + break; + case SMILElementType.PARALLEL: + var parallelElement:ParallelElement = new ParallelElement(); + mediaElement = parallelElement; + break; + case SMILElementType.SEQUENCE: + var serialElement:SerialElement = new SerialElement(); + mediaElement = serialElement; + break; + case SMILElementType.VIDEO: + var resource:StreamingURLResource = new StreamingURLResource((smilElement as SMILMediaElement).src); + resource.mediaType = MediaType.VIDEO; + var videoElement:MediaElement = factory.createMediaElement(resource); + var smilVideoElement:SMILMediaElement = smilElement as SMILMediaElement; + + if (!isNaN(smilVideoElement.clipBegin) && smilVideoElement.clipBegin > 0 && + !isNaN(smilVideoElement.clipEnd) && smilVideoElement.clipEnd > 0) + { + resource.clipStartTime = smilVideoElement.clipBegin; + resource.clipEndTime = smilVideoElement.clipEnd; + } + + var duration:Number = (smilElement as SMILMediaElement).duration; + if (!isNaN(duration) && duration > 0) + { + if (videoElement is VideoElement) + { + (videoElement as VideoElement).defaultDuration = duration; + } + else if (videoElement is ProxyElement) + { + // Try to find the proxied video element (fix for FM-1020) + var tempMediaElement:MediaElement = videoElement; + while (tempMediaElement is ProxyElement) + { + tempMediaElement = (tempMediaElement as ProxyElement).proxiedElement; + } + + if (tempMediaElement != null && tempMediaElement is VideoElement) + { + (tempMediaElement as VideoElement).defaultDuration = duration; + } + } + } + (parentMediaElement as CompositeElement).addChild(videoElement); + break; + case SMILElementType.IMAGE: + var imageResource:URLResource = new URLResource((smilElement as SMILMediaElement).src); + imageResource.mediaType = MediaType.IMAGE; + var imageElement:MediaElement = factory.createMediaElement(imageResource); + var dur:Number = (smilElement as SMILMediaElement).duration; + var durationElement:DurationElement = new DurationElement(dur, imageElement); + (parentMediaElement as CompositeElement).addChild(durationElement); + break; + case SMILElementType.AUDIO: + var audioResource:URLResource = new URLResource((smilElement as SMILMediaElement).src); + audioResource.mediaType = MediaType.AUDIO; + var audioElement:MediaElement = factory.createMediaElement(audioResource); + (parentMediaElement as CompositeElement).addChild(audioElement); + break; + } + + if (mediaElement != null) + { + for (var i:int = 0; i < smilElement.numChildren; i++) + { + var childElement:SMILElement = smilElement.getChildAt(i); + internalCreateMediaElement(originalResource, mediaElement, smilDocument, childElement); + } + + // Fix for FM-931, make sure we support nested elements + if (parentMediaElement is CompositeElement) + { + (parentMediaElement as CompositeElement).addChild(mediaElement); + } + } + else if (mediaResource != null) + { + // Make sure we transfer any resource metadata from the original resource + for each (var metadataNS:String in originalResource.metadataNamespaceURLs) + { + var metadata:Object = originalResource.getMetadataValue(metadataNS); + mediaResource.addMetadataValue(metadataNS, metadata); + } + + mediaElement = factory.createMediaElement(mediaResource); + + if (parentMediaElement is CompositeElement) + { + (parentMediaElement as CompositeElement).addChild(mediaElement); + } + } + + return mediaElement; + } + + private function createDynamicStreamingResource(switchElement:SMILElement, smilDocument:SMILDocument):MediaResourceBase + { + var dsr:DynamicStreamingResource = null; + var hostURL:String; + + for (var i:int = 0; i < smilDocument.numElements; i++) + { + var smilElement:SMILElement = smilDocument.getElementAt(i); + switch (smilElement.type) + { + case SMILElementType.META: + hostURL = (smilElement as SMILMetaElement).base; + if (hostURL != null) + { + dsr = createDynamicStreamingItems(switchElement, hostURL); + } + break; + } + } + + return dsr; + } + + private function createDynamicStreamingItems(switchElement:SMILElement, hostURL:String):DynamicStreamingResource + { + var dsr:DynamicStreamingResource = null; + var streamItems:Vector. = new Vector.(); + + for (var i:int = 0; i < switchElement.numChildren; i++) + { + var smilElement:SMILElement = switchElement.getChildAt(i); + if (smilElement.type == SMILElementType.VIDEO) + { + var videoElement:SMILMediaElement = smilElement as SMILMediaElement; + + // We need to divide the bitrate by 1000 because the DynamicStreamingItem class + // requires the bitrate in kilobits per second. + var dsi:DynamicStreamingItem = new DynamicStreamingItem(videoElement.src, videoElement.bitrate/1000); + streamItems.push(dsi); + } + } + + if (streamItems.length) + { + dsr = new DynamicStreamingResource(hostURL); + dsr.streamItems = streamItems; + dsr.streamType = StreamType.LIVE_OR_RECORDED; + } + + return dsr; + } + + + private function traceElements(smilDocument:SMILDocument):void + { + CONFIG::LOGGING + { + debugLog(">>> SMILMediaGenerator.traceElements() "); + + for (var i:int = 0; i < smilDocument.numElements; i++) + { + var smilElement:SMILElement = smilDocument.getElementAt(i); + traceElement(smilElement) + } + + function traceElement(e:SMILElement, level:int=0):void + { + var levelMarker:String = "*"; + + for (var j:int = 0; j < level; j++) + { + levelMarker += "*"; + } + + debugLog(levelMarker + e.type); + level++; + + for (var k:int = 0; k < e.numChildren; k++) + { + traceElement(e.getChildAt(k), level); + } + + level--; + } + } + } + + private function debugLog(msg:String):void + { + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug(msg); + } + } + } + + CONFIG::LOGGING + { + private static const logger:Logger = org.osmf.logging.Log.getLogger("org.osmf.smil.media.SMILMediaGenerator"); + } + + private var factory:MediaFactory; + } +} diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILDocument.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILDocument.as index 8fbd4d0..dda19ec 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILDocument.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILDocument.as @@ -1,80 +1,80 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.model -{ - import __AS3__.vec.Vector; - - import org.osmf.utils.OSMFStrings; - - /** - * Represents the root level elements of a SMIL document. - */ - public class SMILDocument - { - /** - * Adds a root level element to the collection of - * elements. - */ - public function addElement(value:SMILElement):void - { - if (elements == null) - { - elements = new Vector.(); - } - - elements.push(value); - } - - /** - * The number of root level elements. - */ - public function get numElements():int - { - var num:int = 0; - - if (elements != null) - { - num = elements.length; - } - - return num; - } - - /** - * Returns the SMILElement at the specified index - * in the collection. - * - * @throws RangeError if the index is out of range. - */ - public function getElementAt(index:int):SMILElement - { - if (elements != null && index < elements.length) - { - return elements[index]; - } - - throw new RangeError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); - } - - private var elements:Vector.; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.model +{ + import __AS3__.vec.Vector; + + import org.osmf.utils.OSMFStrings; + + /** + * Represents the root level elements of a SMIL document. + */ + public class SMILDocument + { + /** + * Adds a root level element to the collection of + * elements. + */ + public function addElement(value:SMILElement):void + { + if (elements == null) + { + elements = new Vector.(); + } + + elements.push(value); + } + + /** + * The number of root level elements. + */ + public function get numElements():int + { + var num:int = 0; + + if (elements != null) + { + num = elements.length; + } + + return num; + } + + /** + * Returns the SMILElement at the specified index + * in the collection. + * + * @throws RangeError if the index is out of range. + */ + public function getElementAt(index:int):SMILElement + { + if (elements != null && index < elements.length) + { + return elements[index]; + } + + throw new RangeError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); + } + + private var elements:Vector.; + } +} diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILElement.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILElement.as index d14caa9..493388e 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILElement.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILElement.as @@ -1,99 +1,99 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.model -{ - import __AS3__.vec.Vector; - - import org.osmf.utils.OSMFStrings; - - /** - * Represents an element in a SMIL document. - */ - public class SMILElement - { - /** - * Constructor. - * - * @param type Should be one of the constants defined in SMILElementType. - * @see SMILElementType - */ - public function SMILElement(type:String) - { - _type = type; - } - - /** - * The type of element. Value will be one of the - * constants defined in SMILElementType. - */ - public function get type():String - { - return _type; - } - - /** - * Adds a child element. - */ - public function addChild(child:SMILElement):void - { - if (children == null) - { - children = new Vector.(); - } - - children.push(child); - } - - /** - * Returns the number of child elements. - */ - public function get numChildren():int - { - var num:int = 0; - - if (children != null) - { - num = children.length; - } - - return num; - } - - /** - * Returns the child element at the specified index. - * - * @throws RangeError is the index specified is out of range. - */ - public function getChildAt(index:int):SMILElement - { - if (children != null && index < children.length) - { - return children[index]; - } - - throw new RangeError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); - } - - private var _type:String; - private var children:Vector.; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.model +{ + import __AS3__.vec.Vector; + + import org.osmf.utils.OSMFStrings; + + /** + * Represents an element in a SMIL document. + */ + public class SMILElement + { + /** + * Constructor. + * + * @param type Should be one of the constants defined in SMILElementType. + * @see SMILElementType + */ + public function SMILElement(type:String) + { + _type = type; + } + + /** + * The type of element. Value will be one of the + * constants defined in SMILElementType. + */ + public function get type():String + { + return _type; + } + + /** + * Adds a child element. + */ + public function addChild(child:SMILElement):void + { + if (children == null) + { + children = new Vector.(); + } + + children.push(child); + } + + /** + * Returns the number of child elements. + */ + public function get numChildren():int + { + var num:int = 0; + + if (children != null) + { + num = children.length; + } + + return num; + } + + /** + * Returns the child element at the specified index. + * + * @throws RangeError is the index specified is out of range. + */ + public function getChildAt(index:int):SMILElement + { + if (children != null && index < children.length) + { + return children[index]; + } + + throw new RangeError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); + } + + private var _type:String; + private var children:Vector.; + } +} diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILElementType.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILElementType.as index ca487e9..c7b3997 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILElementType.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILElementType.as @@ -1,79 +1,79 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.model -{ - import __AS3__.vec.Vector; - - /** - * Enumeration of different SMIL element types. - */ - public class SMILElementType - { - /** - * The sequence type. - */ - public static const SEQUENCE:String = "seq"; - - /** - * The parallel type. - */ - public static const PARALLEL:String = "par"; - - /** - * The switch type. - */ - public static const SWITCH:String = "switch"; - - /** - * The video type. - */ - public static const VIDEO:String = "video"; - - /** - * The image type. - */ - public static const IMAGE:String = "img"; - - /** - * The audio type. - */ - public static const AUDIO:String = "audio"; - - /** - * The meta tag. - */ - public static const META:String = "meta"; - - /** - * @private - * - * Collection of all SMIL types. - */ - public static const ALL_TYPES:Vector. = Vector.( [ SEQUENCE, - PARALLEL, - SWITCH, - VIDEO, - IMAGE, - AUDIO, - META ] ); - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.model +{ + import __AS3__.vec.Vector; + + /** + * Enumeration of different SMIL element types. + */ + public class SMILElementType + { + /** + * The sequence type. + */ + public static const SEQUENCE:String = "seq"; + + /** + * The parallel type. + */ + public static const PARALLEL:String = "par"; + + /** + * The switch type. + */ + public static const SWITCH:String = "switch"; + + /** + * The video type. + */ + public static const VIDEO:String = "video"; + + /** + * The image type. + */ + public static const IMAGE:String = "img"; + + /** + * The audio type. + */ + public static const AUDIO:String = "audio"; + + /** + * The meta tag. + */ + public static const META:String = "meta"; + + /** + * @private + * + * Collection of all SMIL types. + */ + public static const ALL_TYPES:Vector. = Vector.( [ SEQUENCE, + PARALLEL, + SWITCH, + VIDEO, + IMAGE, + AUDIO, + META ] ); + } +} diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILMediaElement.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILMediaElement.as index 3409b8e..e3d1cfa 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILMediaElement.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILMediaElement.as @@ -1,114 +1,114 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.model -{ - /** - * This class represents a SMIL media element, such - * as a video element or an image element. - */ - public class SMILMediaElement extends SMILElement - { - /** - * Constructor. - * - * @param type Should be one of the constants defined - * in the SMILElementType class. - */ - public function SMILMediaElement(type:String) - { - super(type); - } - - /** - * The media element source. This is typically - * a URI/URL pointing to the media. - */ - public function get src():String - { - return _src; - } - - public function set src(value:String):void - { - _src = value; - } - - /** - * The media elements's bitrate if applicable, - * specified in kilobits per second (kbps). - */ - public function get bitrate():Number - { - return _bitrate; - } - - public function set bitrate(value:Number):void - { - _bitrate = value; - } - - /** - * The duration of the media in seconds if applicable. - */ - public function get duration():Number - { - return _duration; - } - - public function set duration(value:Number):void - { - _duration = value; - } - - /** - * Specifies the beginning of a sub-clip in seconds. - */ - public function get clipBegin():Number - { - return _clipBegin; - } - - public function set clipBegin(value:Number):void - { - _clipBegin = value; - } - - /** - * Specifies the end of a sub-clip in seconds. - */ - public function get clipEnd():Number - { - return _clipEnd; - } - - public function set clipEnd(value:Number):void - { - _clipEnd = value; - } - - private var _src:String; - private var _bitrate:Number; - private var _duration:Number; - private var _clipBegin:Number; - private var _clipEnd:Number; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.model +{ + /** + * This class represents a SMIL media element, such + * as a video element or an image element. + */ + public class SMILMediaElement extends SMILElement + { + /** + * Constructor. + * + * @param type Should be one of the constants defined + * in the SMILElementType class. + */ + public function SMILMediaElement(type:String) + { + super(type); + } + + /** + * The media element source. This is typically + * a URI/URL pointing to the media. + */ + public function get src():String + { + return _src; + } + + public function set src(value:String):void + { + _src = value; + } + + /** + * The media elements's bitrate if applicable, + * specified in kilobits per second (kbps). + */ + public function get bitrate():Number + { + return _bitrate; + } + + public function set bitrate(value:Number):void + { + _bitrate = value; + } + + /** + * The duration of the media in seconds if applicable. + */ + public function get duration():Number + { + return _duration; + } + + public function set duration(value:Number):void + { + _duration = value; + } + + /** + * Specifies the beginning of a sub-clip in seconds. + */ + public function get clipBegin():Number + { + return _clipBegin; + } + + public function set clipBegin(value:Number):void + { + _clipBegin = value; + } + + /** + * Specifies the end of a sub-clip in seconds. + */ + public function get clipEnd():Number + { + return _clipEnd; + } + + public function set clipEnd(value:Number):void + { + _clipEnd = value; + } + + private var _src:String; + private var _bitrate:Number; + private var _duration:Number; + private var _clipBegin:Number; + private var _clipEnd:Number; + } +} diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILMetaElement.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILMetaElement.as index fb707fd..0206b46 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILMetaElement.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/model/SMILMetaElement.as @@ -1,53 +1,53 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.model -{ - /** - * Represents a meta tag in a SMIL document. - */ - public class SMILMetaElement extends SMILElement - { - /** - * Constructor. - */ - public function SMILMetaElement() - { - super(SMILElementType.META); - } - - /** - * The base attribute value if - * found with the tag in the SMIL file. - */ - public function get base():String - { - return _base; - } - - public function set base(value:String):void - { - _base = value; - } - - private var _base:String; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.model +{ + /** + * Represents a meta tag in a SMIL document. + */ + public class SMILMetaElement extends SMILElement + { + /** + * Constructor. + */ + public function SMILMetaElement() + { + super(SMILElementType.META); + } + + /** + * The base attribute value if + * found with the tag in the SMIL file. + */ + public function get base():String + { + return _base; + } + + public function set base(value:String):void + { + _base = value; + } + + private var _base:String; + } +} diff --git a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/parser/SMILParser.as b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/parser/SMILParser.as index f82f42c..0fafeae 100644 --- a/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/parser/SMILParser.as +++ b/lib/osmf/samples/SMILPlugin/src/org/osmf/smil/parser/SMILParser.as @@ -1,251 +1,251 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.smil.parser -{ - import flash.errors.IllegalOperationError; - - import org.osmf.smil.model.SMILDocument; - import org.osmf.smil.model.SMILElement; - import org.osmf.smil.model.SMILElementType; - import org.osmf.smil.model.SMILMediaElement; - import org.osmf.smil.model.SMILMetaElement; - import org.osmf.utils.TimeUtil; - - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } - - /** - * Parses a SMIL file and creates a document object - * model. - */ - public class SMILParser - { - /** - * Parses a SMIL file and returns a SMILDocument. - */ - public function parse(rawData:String):SMILDocument - { - if (rawData == null || rawData == "") - { - throw new ArgumentError(); - } - - var smilDocument:SMILDocument = new SMILDocument(); - - try - { - var xml:XML = new XML(rawData); - - parseHead(smilDocument, xml); - parseBody(smilDocument, xml); - } - catch (err:Error) - { - debugLog("Unhandled exception in SMILParser : "+err.message); - throw err; - } - - return smilDocument; - } - - private function parseHead(doc:SMILDocument, xml:XML):void - { - var ns:Namespace = xml.namespace(); - var head:XMLList = xml..ns::head; - - if (head.length() > 0) - { - parseElement(doc, head.children()); - } - } - - private function parseBody(doc:SMILDocument, xml:XML):void - { - var ns:Namespace = xml.namespace(); - var body:XMLList = xml..ns::body; - - // The tag is required - if (body.length() <= 0) - { - debugLog(INVALID_FILE_MISSING_BODY_TAG); - throw new IllegalOperationError(INVALID_FILE_MISSING_BODY_TAG); - } - else - { - parseElement(doc, body.children()); - } - } - - /** - * Recursive function that parses all elements in a SMIL file. - */ - private function parseElement(doc:SMILDocument, children:XMLList, parent:SMILElement=null):void - { - for (var i:uint = 0; i < children.length(); i++) - { - var childNode:XML = children[i]; - var element:SMILElement; - - switch (childNode.nodeKind()) - { - case "element": - switch (childNode.localName()) - { - case SMILElementType.SEQUENCE: - element = new SMILElement(SMILElementType.SEQUENCE); - break; - case SMILElementType.PARALLEL: - element = new SMILElement(SMILElementType.PARALLEL); - break; - case SMILElementType.SWITCH: - element = new SMILElement(SMILElementType.SWITCH); - break; - case SMILElementType.IMAGE: - case SMILElementType.VIDEO: - case SMILElementType.AUDIO: - element = parseMediaElement(childNode); - break; - case SMILElementType.META: - element = parseMetaElement(childNode); - break; - } - break; - } - - parseElement(doc, childNode.children(), element); - - if (element != null) - { - if (parent != null) - { - parent.addChild(element); - } - else - { - doc.addElement(element); - } - } - } - } - - private function parseMediaElement(node:XML):SMILMediaElement - { - var element:SMILMediaElement; - - switch (node.nodeKind()) - { - case "element": - switch (node.localName()) - { - case SMILElementType.VIDEO: - element = new SMILMediaElement(SMILElementType.VIDEO); - break; - case SMILElementType.IMAGE: - element = new SMILMediaElement(SMILElementType.IMAGE); - break; - case SMILElementType.AUDIO: - element = new SMILMediaElement(SMILElementType.AUDIO); - break; - } - break; - } - - if (element != null) - { - element.src = node.@[ATTRIB_SOURCE]; - - if (node.@[ATTRIB_BITRATE] != null) - { - element.bitrate = node.@[ATTRIB_BITRATE]; - } - - if (node.@[ATTRIB_DURATION] != null) - { - element.duration = TimeUtil.parseTime(node.@[ATTRIB_DURATION]); - } - - if (node.@[ATTRIB_CLIP_BEGIN] != null) - { - element.clipBegin = TimeUtil.parseTime(node.@[ATTRIB_CLIP_BEGIN]); - } - - if (node.@[ATTRIB_CLIP_END] != null) - { - element.clipEnd = TimeUtil.parseTime(node.@[ATTRIB_CLIP_END]); - } - - } - - return element; - } - - private function parseMetaElement(node:XML):SMILMetaElement - { - var element:SMILMetaElement; - - switch (node.nodeKind()) - { - case "element": - switch (node.localName()) - { - case SMILElementType.META: - element = new SMILMetaElement(); - element.base = node.@[ATTRIB_META_BASE]; - break; - } - break; - } - - return element; - } - - private function debugLog(msg:String):void - { - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug(msg); - } - } - } - - CONFIG::LOGGING - { - private static const logger:Logger = org.osmf.logging.Log.getLogger("org.osmf.smil.parser.SMILParser"); - } - - // SMIL tag attributes - private static const ATTRIB_SOURCE:String = "src"; - private static const ATTRIB_BITRATE:String = "system-bitrate"; - private static const ATTRIB_DURATION:String = "dur"; - private static const ATTRIB_META_BASE:String = "base"; - private static const ATTRIB_CLIP_BEGIN:String = "clipBegin"; - private static const ATTRIB_CLIP_END:String = "clipEnd"; - - // Error messages - private static const INVALID_FILE_MISSING_BODY_TAG:String = "Invalid SMIL file: tag is missing."; - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.smil.parser +{ + import flash.errors.IllegalOperationError; + + import org.osmf.smil.model.SMILDocument; + import org.osmf.smil.model.SMILElement; + import org.osmf.smil.model.SMILElementType; + import org.osmf.smil.model.SMILMediaElement; + import org.osmf.smil.model.SMILMetaElement; + import org.osmf.utils.TimeUtil; + + CONFIG::LOGGING + { + import org.osmf.logging.Logger; + import org.osmf.logging.Log; + } + + /** + * Parses a SMIL file and creates a document object + * model. + */ + public class SMILParser + { + /** + * Parses a SMIL file and returns a SMILDocument. + */ + public function parse(rawData:String):SMILDocument + { + if (rawData == null || rawData == "") + { + throw new ArgumentError(); + } + + var smilDocument:SMILDocument = new SMILDocument(); + + try + { + var xml:XML = new XML(rawData); + + parseHead(smilDocument, xml); + parseBody(smilDocument, xml); + } + catch (err:Error) + { + debugLog("Unhandled exception in SMILParser : "+err.message); + throw err; + } + + return smilDocument; + } + + private function parseHead(doc:SMILDocument, xml:XML):void + { + var ns:Namespace = xml.namespace(); + var head:XMLList = xml..ns::head; + + if (head.length() > 0) + { + parseElement(doc, head.children()); + } + } + + private function parseBody(doc:SMILDocument, xml:XML):void + { + var ns:Namespace = xml.namespace(); + var body:XMLList = xml..ns::body; + + // The tag is required + if (body.length() <= 0) + { + debugLog(INVALID_FILE_MISSING_BODY_TAG); + throw new IllegalOperationError(INVALID_FILE_MISSING_BODY_TAG); + } + else + { + parseElement(doc, body.children()); + } + } + + /** + * Recursive function that parses all elements in a SMIL file. + */ + private function parseElement(doc:SMILDocument, children:XMLList, parent:SMILElement=null):void + { + for (var i:uint = 0; i < children.length(); i++) + { + var childNode:XML = children[i]; + var element:SMILElement; + + switch (childNode.nodeKind()) + { + case "element": + switch (childNode.localName()) + { + case SMILElementType.SEQUENCE: + element = new SMILElement(SMILElementType.SEQUENCE); + break; + case SMILElementType.PARALLEL: + element = new SMILElement(SMILElementType.PARALLEL); + break; + case SMILElementType.SWITCH: + element = new SMILElement(SMILElementType.SWITCH); + break; + case SMILElementType.IMAGE: + case SMILElementType.VIDEO: + case SMILElementType.AUDIO: + element = parseMediaElement(childNode); + break; + case SMILElementType.META: + element = parseMetaElement(childNode); + break; + } + break; + } + + parseElement(doc, childNode.children(), element); + + if (element != null) + { + if (parent != null) + { + parent.addChild(element); + } + else + { + doc.addElement(element); + } + } + } + } + + private function parseMediaElement(node:XML):SMILMediaElement + { + var element:SMILMediaElement; + + switch (node.nodeKind()) + { + case "element": + switch (node.localName()) + { + case SMILElementType.VIDEO: + element = new SMILMediaElement(SMILElementType.VIDEO); + break; + case SMILElementType.IMAGE: + element = new SMILMediaElement(SMILElementType.IMAGE); + break; + case SMILElementType.AUDIO: + element = new SMILMediaElement(SMILElementType.AUDIO); + break; + } + break; + } + + if (element != null) + { + element.src = node.@[ATTRIB_SOURCE]; + + if (node.@[ATTRIB_BITRATE] != null) + { + element.bitrate = node.@[ATTRIB_BITRATE]; + } + + if (node.@[ATTRIB_DURATION] != null) + { + element.duration = TimeUtil.parseTime(node.@[ATTRIB_DURATION]); + } + + if (node.@[ATTRIB_CLIP_BEGIN] != null) + { + element.clipBegin = TimeUtil.parseTime(node.@[ATTRIB_CLIP_BEGIN]); + } + + if (node.@[ATTRIB_CLIP_END] != null) + { + element.clipEnd = TimeUtil.parseTime(node.@[ATTRIB_CLIP_END]); + } + + } + + return element; + } + + private function parseMetaElement(node:XML):SMILMetaElement + { + var element:SMILMetaElement; + + switch (node.nodeKind()) + { + case "element": + switch (node.localName()) + { + case SMILElementType.META: + element = new SMILMetaElement(); + element.base = node.@[ATTRIB_META_BASE]; + break; + } + break; + } + + return element; + } + + private function debugLog(msg:String):void + { + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug(msg); + } + } + } + + CONFIG::LOGGING + { + private static const logger:Logger = org.osmf.logging.Log.getLogger("org.osmf.smil.parser.SMILParser"); + } + + // SMIL tag attributes + private static const ATTRIB_SOURCE:String = "src"; + private static const ATTRIB_BITRATE:String = "system-bitrate"; + private static const ATTRIB_DURATION:String = "dur"; + private static const ATTRIB_META_BASE:String = "base"; + private static const ATTRIB_CLIP_BEGIN:String = "clipBegin"; + private static const ATTRIB_CLIP_END:String = "clipEnd"; + + // Error messages + private static const INVALID_FILE_MISSING_BODY_TAG:String = "Invalid SMIL file: tag is missing."; + } +} diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/.actionScriptProperties b/lib/osmf/samples/SMILPluginIntegrationTest/.actionScriptProperties index 86980ed..3ac1f07 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/.actionScriptProperties +++ b/lib/osmf/samples/SMILPluginIntegrationTest/.actionScriptProperties @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/.flexProperties b/lib/osmf/samples/SMILPluginIntegrationTest/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/.flexProperties +++ b/lib/osmf/samples/SMILPluginIntegrationTest/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/SMILPluginIntegrationTest.mxml b/lib/osmf/samples/SMILPluginIntegrationTest/src/SMILPluginIntegrationTest.mxml index 604ad54..05655d7 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/SMILPluginIntegrationTest.mxml +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/SMILPluginIntegrationTest.mxml @@ -1,48 +1,48 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/SMILPluginIntegrationTests.as b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/SMILPluginIntegrationTests.as index ff639fb..63260de 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/SMILPluginIntegrationTests.as +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/SMILPluginIntegrationTests.as @@ -1,43 +1,43 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf -{ - import flexunit.framework.TestSuite; - - import org.osmf.test.smil.TestSMILPluginInfo; - import org.osmf.test.smil.loader.TestSMILLoader; - import org.osmf.test.smil.parser.TestSMILParser; - - - public class SMILPluginIntegrationTests extends TestSuite - { - public function SMILPluginIntegrationTests(param:Object=null) - { - super(param); - - addTestSuite(TestSMILPluginInfo); - addTestSuite(TestSMILLoader); - addTestSuite(TestSMILParser); - } - - } +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf +{ + import flexunit.framework.TestSuite; + + import org.osmf.test.smil.TestSMILPluginInfo; + import org.osmf.test.smil.loader.TestSMILLoader; + import org.osmf.test.smil.parser.TestSMILParser; + + + public class SMILPluginIntegrationTests extends TestSuite + { + public function SMILPluginIntegrationTests(param:Object=null) + { + super(param); + + addTestSuite(TestSMILPluginInfo); + addTestSuite(TestSMILLoader); + addTestSuite(TestSMILParser); + } + + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/media/TestMediaElement.as b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/media/TestMediaElement.as index 7e25f2e..ea9c02a 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/media/TestMediaElement.as +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/media/TestMediaElement.as @@ -1,649 +1,649 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.media -{ - import flash.events.Event; - import flash.events.EventDispatcher; - - import org.osmf.containers.MediaContainer; - import org.osmf.events.ContainerChangeEvent; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorCodes; - import org.osmf.events.MediaErrorEvent; - import org.osmf.flexunit.TestCaseEx; - import org.osmf.metadata.Metadata; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.utils.OSMFStrings; - - public class TestMediaElement extends TestCaseEx - { - override public function setUp():void - { - super.setUp(); - - _eventDispatcher = new EventDispatcher(); - } - - override public function tearDown():void - { - super.tearDown(); - - _eventDispatcher = null; - } - - public function testGetTraitTypes():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyGetTraitTypes(mediaElement, existentTraitTypesOnInitialization); - } - - public function testGetTraitTypesAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyGetTraitTypes); - } - } - - public function testGetTraitTypesAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyGetTraitTypes, mediaElement); - } - } - - public function testHasTrait():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyHasTrait(mediaElement, existentTraitTypesOnInitialization); - } - - public function testHasTraitWhenParamIsNull():void - { - var mediaElement:MediaElement = createMediaElement(); - - try - { - mediaElement.hasTrait(null); - - fail(); - } - catch (error:ArgumentError) - { - } - } - - public function testHasTraitAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyHasTrait); - } - } - - public function testHasTraitAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyHasTrait, mediaElement); - } - } - - public function testGetTrait():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyGetTrait(mediaElement, existentTraitTypesOnInitialization); - } - - public function testGetTraitWhenParamIsNull():void - { - var mediaElement:MediaElement = createMediaElement(); - - try - { - mediaElement.getTrait(null); - - fail(); - } - catch (error:ArgumentError) - { - } - } - - public function testGetTraitAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyGetTrait); - } - } - - public function testGetTraitAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyGetTrait, mediaElement); - } - } - - public function testGetResource():void - { - var mediaElement:MediaElement = createMediaElement(); - - assertTrue(mediaElement.resource == null); - } - - public function testSetResource():void - { - var mediaElement:MediaElement = createMediaElement(); - - mediaElement.resource = resourceForMediaElement; - assertTrue(mediaElement.resource != null); - - mediaElement.resource = null; - assertTrue(mediaElement.resource == null); - } - - public function testAddMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaElementEvent.METADATA_ADD, onAdd); - var addCalled:Boolean = false; - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - assertTrue(addCalled); - - mediaElement.addMetadata(nsurl2, meta2); - - assertEquals(mediaElement.getMetadata(nsurl1), meta1); - assertEquals(mediaElement.getMetadata(nsurl2), meta2); - - // Test addition through the undocumented API results in - // an event. (This is how we simulate metadata being added - // internally.) - addCalled = false; - mediaElement.metadata.addValue("foo", meta1); - assertEquals(mediaElement.getMetadata("foo"), meta1); - assertTrue(addCalled); - - // Test the Catching of Errors - try - { - mediaElement.addMetadata(null, meta1); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - try - { - mediaElement.addMetadata(nsurl1, null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - - function onAdd(event:MediaElementEvent):void - { - addCalled = true; - assertNotNull(event.metadata); - } - } - - public function testRemoveMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onRemove); - var removeCalled:Boolean = false; - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertFalse(removeCalled); - assertEquals(mediaElement.removeMetadata(nsurl2), meta2); - assertTrue(removeCalled); - assertEquals(mediaElement.removeMetadata(nsurl2), null); - assertEquals(mediaElement.removeMetadata(nsurl1), meta1); - - // Test removal through the undocumented API results in - // an event. (This is how we simulate metadata being removed - // internally.) - removeCalled = false; - mediaElement.addMetadata("foo", meta1); - assertEquals(mediaElement.metadata.removeValue("foo"), meta1); - assertTrue(removeCalled); - - // Test the Catching of Errors - try - { - mediaElement.removeMetadata(null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - - function onRemove(event:MediaElementEvent):void - { - removeCalled = true; - assertNotNull(event.metadata); - } - } - - public function testGetMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertEquals(mediaElement.getMetadata(nsurl2), meta2); - assertEquals(mediaElement.getMetadata(nsurl1), meta1); - assertEquals(mediaElement.getMetadata("foo"), null); - - // Test the Catching of Errors - try - { - mediaElement.getMetadata(null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - } - - public function testGetMetadataNamespaceURLs():void - { - var mediaElement:MediaElement = createMediaElement(); - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertTrue(mediaElement.metadataNamespaceURLs.length == 2); - assertTrue( ( mediaElement.metadataNamespaceURLs[0] == "nsurl1" - && mediaElement.metadataNamespaceURLs[1] == "nsurl2" - ) - || ( mediaElement.metadataNamespaceURLs[0] == "nsurl2" - && mediaElement.metadataNamespaceURLs[1] == "nsurl1" - ) - ); - } - - public function testMediaErrorEventDispatch():void - { - if (hasLoadTrait) - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, 1000)); - - var eventCtr:int = 0; - - // Make sure error events dispatched on the trait are redispatched - // on the MediaElement. - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(99))); - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID))); - - function onMediaError(event:MediaErrorEvent):void - { - eventCtr++; - - if (eventCtr == 1) - { - assertTrue(event.error.errorID == 99); - assertTrue(event.error.message == ""); - assertTrue(event.target == mediaElement); - } - else if (eventCtr == 2) - { - assertTrue(event.error.errorID == MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID); - assertTrue(event.error.message == "File has invalid structure"); - assertTrue(event.target == mediaElement); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - else fail(); - } - } - } - - public function testContainer():void - { - var mediaElement:MediaElement = createMediaElement(); - var containerA:MediaContainer = new MediaContainer(); - var containerB:MediaContainer = new MediaContainer(); - - assertNull(mediaElement.container); - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerA.addMediaElement(mediaElement);} - ); - - assertEquals(containerA, mediaElement.container); - - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerB.addMediaElement(mediaElement);} - ); - - assertEquals(containerB, mediaElement.container); - - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerB.removeMediaElement(mediaElement);} - ); - - assertNull(mediaElement.container); - } - - // Protected - // - - protected function createMediaElement():MediaElement - { - // Subclasses can override to specify the MediaElement subclass - // to test. - return new MediaElement(); - } - - protected function get hasLoadTrait():Boolean - { - // Subclasses can override to specify that they start with the - // LoadTrait. - return false; - } - - protected function get resourceForMediaElement():MediaResourceBase - { - // Subclasses can override to specify a resource that the - // MediaElement can work with. - return new URLResource("http://www.example.com"); - } - - protected function get existentTraitTypesOnInitialization():Array - { - // Subclasses can override to specify the trait types which are - // expected upon initialization. - return []; - } - - protected function get existentTraitTypesAfterLoad():Array - { - // Subclasses can override to specify the trait types which are - // expected after a load. Ignored if the MediaElement - // lacks the LoadTrait. - return []; - } - - final protected function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - final protected function mustNotReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is NOT received. - fail(); - } - - final protected function get eventDispatcher():EventDispatcher - { - return _eventDispatcher; - } - - // Internals - // - - private function verifyGetTraitTypes(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - assertTrue(mediaElement.traitTypes != null); - assertTrue(mediaElement.traitTypes.length == expectedTraitTypes.length); - - // Verify all expected traits are in traitTypes. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.traitTypes.indexOf(traitType) >= 0); - } - - // Verify all other traits are not in traitTypes. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.traitTypes.indexOf(traitType) == -1); - } - } - - private function verifyHasTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - // Verify hasTrait returns true for all expected traits. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.hasTrait(traitType) == true); - } - - // Verify hasTrait returns false for all unexpected traits. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.hasTrait(traitType) == false); - } - } - - private function verifyGetTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - // Verify getTrait returns a result for all expected traits. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.getTrait(traitType) != null); - } - - // Verify getTrait returns false for all unexpected traits. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.getTrait(traitType) == null); - } - } - - private function callAfterLoad(func:Function, triggerTestCompleteEvent:Boolean=true):MediaElement - { - assertTrue(hasLoadTrait); - - if (triggerTestCompleteEvent) - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); - } - - var mediaElement:MediaElement = createMediaElement(); - mediaElement.resource = resourceForMediaElement; - - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCallAfterLoad - ); - loadTrait.load(); - - function onTestCallAfterLoad(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterLoad); - - if (func != null) - { - func(mediaElement, existentTraitTypesAfterLoad); - } - - if (triggerTestCompleteEvent) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - return mediaElement; - } - - private function callAfterUnload(func:Function, mediaElement:MediaElement):void - { - assertTrue(hasLoadTrait); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); - - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - - // If the MediaElement is not yet loaded, wait until it is. - if (loadTrait.loadState == LoadState.READY) - { - completeCallAfterUnload(func, mediaElement); - } - else - { - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCallAfterUnload - ); - - function onTestCallAfterUnload(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterUnload); - - completeCallAfterUnload(func, mediaElement); - } - } - } - } - - private function completeCallAfterUnload(func:Function, mediaElement:MediaElement):void - { - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCompleteCallAfterUnload - ); - loadTrait.unload(); - - function onTestCompleteCallAfterUnload(event:LoadEvent):void - { - if (event.loadState == LoadState.UNINITIALIZED) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCompleteCallAfterUnload); - - func(mediaElement, existentTraitTypesOnInitialization); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - private function inverseOf(traitTypes:Array):Array - { - var inverseTraitTypes:Array = []; - - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.AUDIO); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.BUFFER); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DRM); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DYNAMIC_STREAM); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.LOAD); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.PLAY); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.SEEK); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.TIME); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DISPLAY_OBJECT); - - return inverseTraitTypes; - } - - private function addIfNotPresent(traitTypes:Array, results:Array, traitType:String):void - { - if (traitTypes.indexOf(traitType) == -1) - { - results.push(traitType); - } - } - - private static const ASYNC_DELAY:Number = 8000; - - private var _eventDispatcher:EventDispatcher; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.media +{ + import flash.events.Event; + import flash.events.EventDispatcher; + + import org.osmf.containers.MediaContainer; + import org.osmf.events.ContainerChangeEvent; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorCodes; + import org.osmf.events.MediaErrorEvent; + import org.osmf.flexunit.TestCaseEx; + import org.osmf.metadata.Metadata; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.utils.OSMFStrings; + + public class TestMediaElement extends TestCaseEx + { + override public function setUp():void + { + super.setUp(); + + _eventDispatcher = new EventDispatcher(); + } + + override public function tearDown():void + { + super.tearDown(); + + _eventDispatcher = null; + } + + public function testGetTraitTypes():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyGetTraitTypes(mediaElement, existentTraitTypesOnInitialization); + } + + public function testGetTraitTypesAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyGetTraitTypes); + } + } + + public function testGetTraitTypesAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyGetTraitTypes, mediaElement); + } + } + + public function testHasTrait():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyHasTrait(mediaElement, existentTraitTypesOnInitialization); + } + + public function testHasTraitWhenParamIsNull():void + { + var mediaElement:MediaElement = createMediaElement(); + + try + { + mediaElement.hasTrait(null); + + fail(); + } + catch (error:ArgumentError) + { + } + } + + public function testHasTraitAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyHasTrait); + } + } + + public function testHasTraitAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyHasTrait, mediaElement); + } + } + + public function testGetTrait():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyGetTrait(mediaElement, existentTraitTypesOnInitialization); + } + + public function testGetTraitWhenParamIsNull():void + { + var mediaElement:MediaElement = createMediaElement(); + + try + { + mediaElement.getTrait(null); + + fail(); + } + catch (error:ArgumentError) + { + } + } + + public function testGetTraitAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyGetTrait); + } + } + + public function testGetTraitAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyGetTrait, mediaElement); + } + } + + public function testGetResource():void + { + var mediaElement:MediaElement = createMediaElement(); + + assertTrue(mediaElement.resource == null); + } + + public function testSetResource():void + { + var mediaElement:MediaElement = createMediaElement(); + + mediaElement.resource = resourceForMediaElement; + assertTrue(mediaElement.resource != null); + + mediaElement.resource = null; + assertTrue(mediaElement.resource == null); + } + + public function testAddMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaElementEvent.METADATA_ADD, onAdd); + var addCalled:Boolean = false; + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + assertTrue(addCalled); + + mediaElement.addMetadata(nsurl2, meta2); + + assertEquals(mediaElement.getMetadata(nsurl1), meta1); + assertEquals(mediaElement.getMetadata(nsurl2), meta2); + + // Test addition through the undocumented API results in + // an event. (This is how we simulate metadata being added + // internally.) + addCalled = false; + mediaElement.metadata.addValue("foo", meta1); + assertEquals(mediaElement.getMetadata("foo"), meta1); + assertTrue(addCalled); + + // Test the Catching of Errors + try + { + mediaElement.addMetadata(null, meta1); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + try + { + mediaElement.addMetadata(nsurl1, null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + + function onAdd(event:MediaElementEvent):void + { + addCalled = true; + assertNotNull(event.metadata); + } + } + + public function testRemoveMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onRemove); + var removeCalled:Boolean = false; + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertFalse(removeCalled); + assertEquals(mediaElement.removeMetadata(nsurl2), meta2); + assertTrue(removeCalled); + assertEquals(mediaElement.removeMetadata(nsurl2), null); + assertEquals(mediaElement.removeMetadata(nsurl1), meta1); + + // Test removal through the undocumented API results in + // an event. (This is how we simulate metadata being removed + // internally.) + removeCalled = false; + mediaElement.addMetadata("foo", meta1); + assertEquals(mediaElement.metadata.removeValue("foo"), meta1); + assertTrue(removeCalled); + + // Test the Catching of Errors + try + { + mediaElement.removeMetadata(null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + + function onRemove(event:MediaElementEvent):void + { + removeCalled = true; + assertNotNull(event.metadata); + } + } + + public function testGetMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertEquals(mediaElement.getMetadata(nsurl2), meta2); + assertEquals(mediaElement.getMetadata(nsurl1), meta1); + assertEquals(mediaElement.getMetadata("foo"), null); + + // Test the Catching of Errors + try + { + mediaElement.getMetadata(null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + } + + public function testGetMetadataNamespaceURLs():void + { + var mediaElement:MediaElement = createMediaElement(); + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertTrue(mediaElement.metadataNamespaceURLs.length == 2); + assertTrue( ( mediaElement.metadataNamespaceURLs[0] == "nsurl1" + && mediaElement.metadataNamespaceURLs[1] == "nsurl2" + ) + || ( mediaElement.metadataNamespaceURLs[0] == "nsurl2" + && mediaElement.metadataNamespaceURLs[1] == "nsurl1" + ) + ); + } + + public function testMediaErrorEventDispatch():void + { + if (hasLoadTrait) + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, 1000)); + + var eventCtr:int = 0; + + // Make sure error events dispatched on the trait are redispatched + // on the MediaElement. + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(99))); + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID))); + + function onMediaError(event:MediaErrorEvent):void + { + eventCtr++; + + if (eventCtr == 1) + { + assertTrue(event.error.errorID == 99); + assertTrue(event.error.message == ""); + assertTrue(event.target == mediaElement); + } + else if (eventCtr == 2) + { + assertTrue(event.error.errorID == MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID); + assertTrue(event.error.message == "File has invalid structure"); + assertTrue(event.target == mediaElement); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + else fail(); + } + } + } + + public function testContainer():void + { + var mediaElement:MediaElement = createMediaElement(); + var containerA:MediaContainer = new MediaContainer(); + var containerB:MediaContainer = new MediaContainer(); + + assertNull(mediaElement.container); + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerA.addMediaElement(mediaElement);} + ); + + assertEquals(containerA, mediaElement.container); + + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerB.addMediaElement(mediaElement);} + ); + + assertEquals(containerB, mediaElement.container); + + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerB.removeMediaElement(mediaElement);} + ); + + assertNull(mediaElement.container); + } + + // Protected + // + + protected function createMediaElement():MediaElement + { + // Subclasses can override to specify the MediaElement subclass + // to test. + return new MediaElement(); + } + + protected function get hasLoadTrait():Boolean + { + // Subclasses can override to specify that they start with the + // LoadTrait. + return false; + } + + protected function get resourceForMediaElement():MediaResourceBase + { + // Subclasses can override to specify a resource that the + // MediaElement can work with. + return new URLResource("http://www.example.com"); + } + + protected function get existentTraitTypesOnInitialization():Array + { + // Subclasses can override to specify the trait types which are + // expected upon initialization. + return []; + } + + protected function get existentTraitTypesAfterLoad():Array + { + // Subclasses can override to specify the trait types which are + // expected after a load. Ignored if the MediaElement + // lacks the LoadTrait. + return []; + } + + final protected function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + final protected function mustNotReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is NOT received. + fail(); + } + + final protected function get eventDispatcher():EventDispatcher + { + return _eventDispatcher; + } + + // Internals + // + + private function verifyGetTraitTypes(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + assertTrue(mediaElement.traitTypes != null); + assertTrue(mediaElement.traitTypes.length == expectedTraitTypes.length); + + // Verify all expected traits are in traitTypes. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.traitTypes.indexOf(traitType) >= 0); + } + + // Verify all other traits are not in traitTypes. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.traitTypes.indexOf(traitType) == -1); + } + } + + private function verifyHasTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + // Verify hasTrait returns true for all expected traits. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.hasTrait(traitType) == true); + } + + // Verify hasTrait returns false for all unexpected traits. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.hasTrait(traitType) == false); + } + } + + private function verifyGetTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + // Verify getTrait returns a result for all expected traits. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.getTrait(traitType) != null); + } + + // Verify getTrait returns false for all unexpected traits. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.getTrait(traitType) == null); + } + } + + private function callAfterLoad(func:Function, triggerTestCompleteEvent:Boolean=true):MediaElement + { + assertTrue(hasLoadTrait); + + if (triggerTestCompleteEvent) + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); + } + + var mediaElement:MediaElement = createMediaElement(); + mediaElement.resource = resourceForMediaElement; + + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCallAfterLoad + ); + loadTrait.load(); + + function onTestCallAfterLoad(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterLoad); + + if (func != null) + { + func(mediaElement, existentTraitTypesAfterLoad); + } + + if (triggerTestCompleteEvent) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + return mediaElement; + } + + private function callAfterUnload(func:Function, mediaElement:MediaElement):void + { + assertTrue(hasLoadTrait); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); + + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + + // If the MediaElement is not yet loaded, wait until it is. + if (loadTrait.loadState == LoadState.READY) + { + completeCallAfterUnload(func, mediaElement); + } + else + { + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCallAfterUnload + ); + + function onTestCallAfterUnload(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterUnload); + + completeCallAfterUnload(func, mediaElement); + } + } + } + } + + private function completeCallAfterUnload(func:Function, mediaElement:MediaElement):void + { + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCompleteCallAfterUnload + ); + loadTrait.unload(); + + function onTestCompleteCallAfterUnload(event:LoadEvent):void + { + if (event.loadState == LoadState.UNINITIALIZED) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCompleteCallAfterUnload); + + func(mediaElement, existentTraitTypesOnInitialization); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + private function inverseOf(traitTypes:Array):Array + { + var inverseTraitTypes:Array = []; + + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.AUDIO); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.BUFFER); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DRM); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DYNAMIC_STREAM); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.LOAD); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.PLAY); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.SEEK); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.TIME); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DISPLAY_OBJECT); + + return inverseTraitTypes; + } + + private function addIfNotPresent(traitTypes:Array, results:Array, traitType:String):void + { + if (traitTypes.indexOf(traitType) == -1) + { + results.push(traitType); + } + } + + private static const ASYNC_DELAY:Number = 8000; + + private var _eventDispatcher:EventDispatcher; + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/TestSMILPluginInfo.as b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/TestSMILPluginInfo.as index 720c628..e889b46 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/TestSMILPluginInfo.as +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/TestSMILPluginInfo.as @@ -1,91 +1,91 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.test.smil -{ - import flexunit.framework.TestCase; - - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.PluginInfo; - import org.osmf.media.URLResource; - import org.osmf.smil.SMILPluginInfo; - - public class TestSMILPluginInfo extends TestCase - { - public function testGetMediaFactoryItemAt():void - { - var pluginInfo:PluginInfo = new SMILPluginInfo(); - - assertNotNull(pluginInfo); - - var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(0); - assertNotNull(item); - - var mediaFactory:MediaFactory = new MediaFactory(); - mediaFactory.addItem(item); - var mediaElement:MediaElement = mediaFactory.createMediaElement(new URLResource(SMILTestConstants.SMIL_DOCUMENT_SEQ_URL)); - assertNotNull(mediaElement); - } - - public function testGetMediaFactoryItemAtWithBadIndex():void - { - var pluginInfo:PluginInfo = new SMILPluginInfo(); - - assertNotNull(pluginInfo); - - try - { - var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(10); - fail(); - } - catch(error:RangeError) - { - } - } - - public function testIsFrameworkVersionSupported():void - { - var pluginInfo:PluginInfo = new SMILPluginInfo(); - assertNotNull(pluginInfo); - - assertEquals(true, pluginInfo.isFrameworkVersionSupported("1.0.0")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.0.1")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.5.1")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.7.0")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.4.9")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported(null)); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("abc")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("foo.bar")); - assertEquals(false, pluginInfo.isFrameworkVersionSupported("foobar.")); - } - - public function testNumMediaInfos():void - { - var pluginInfo:PluginInfo = new SMILPluginInfo(); - assertNotNull(pluginInfo); - - assertTrue(pluginInfo.numMediaFactoryItems > 0); - } - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.test.smil +{ + import flexunit.framework.TestCase; + + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.PluginInfo; + import org.osmf.media.URLResource; + import org.osmf.smil.SMILPluginInfo; + + public class TestSMILPluginInfo extends TestCase + { + public function testGetMediaFactoryItemAt():void + { + var pluginInfo:PluginInfo = new SMILPluginInfo(); + + assertNotNull(pluginInfo); + + var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(0); + assertNotNull(item); + + var mediaFactory:MediaFactory = new MediaFactory(); + mediaFactory.addItem(item); + var mediaElement:MediaElement = mediaFactory.createMediaElement(new URLResource(SMILTestConstants.SMIL_DOCUMENT_SEQ_URL)); + assertNotNull(mediaElement); + } + + public function testGetMediaFactoryItemAtWithBadIndex():void + { + var pluginInfo:PluginInfo = new SMILPluginInfo(); + + assertNotNull(pluginInfo); + + try + { + var item:MediaFactoryItem = pluginInfo.getMediaFactoryItemAt(10); + fail(); + } + catch(error:RangeError) + { + } + } + + public function testIsFrameworkVersionSupported():void + { + var pluginInfo:PluginInfo = new SMILPluginInfo(); + assertNotNull(pluginInfo); + + assertEquals(true, pluginInfo.isFrameworkVersionSupported("1.0.0")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.0.1")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.5.1")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.7.0")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("0.4.9")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported(null)); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("abc")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("foo.bar")); + assertEquals(false, pluginInfo.isFrameworkVersionSupported("foobar.")); + } + + public function testNumMediaInfos():void + { + var pluginInfo:PluginInfo = new SMILPluginInfo(); + assertNotNull(pluginInfo); + + assertTrue(pluginInfo.numMediaFactoryItems > 0); + } + } +} diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/loader/TestSMILLoader.as b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/loader/TestSMILLoader.as index 28c8f36..0cee908 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/loader/TestSMILLoader.as +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/loader/TestSMILLoader.as @@ -1,215 +1,215 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.test.smil.loader -{ - import flash.events.*; - - import org.osmf.elements.ImageElement; - import org.osmf.elements.VideoElement; - import org.osmf.elements.proxyClasses.LoadFromDocumentLoadTrait; - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaFactoryEvent; - import org.osmf.media.DefaultMediaFactory; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.metadata.MetadataNamespaces; - import org.osmf.net.DynamicStreamingResource; - import org.osmf.smil.loader.*; - import org.osmf.smil.model.*; - import org.osmf.test.smil.SMILTestConstants; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.traits.TestLoaderBase; - import org.osmf.utils.NullResource; - - public class TestSMILLoader extends TestLoaderBase - { - override public function setUp():void - { - eventDispatcher = new EventDispatcher(); - factory = new DefaultMediaFactory(); - createdElements = []; - - super.setUp(); - } - - override public function tearDown():void - { - super.tearDown(); - - createdElements = null; - factory = null; - eventDispatcher = null; - } - - - override protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - return new LoadFromDocumentLoadTrait(loader, resource); - } - - public function testLoadWithValidSMILDocument():void - { - eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); - factory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate); - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidSMILDocument); - loader.load(createLoadTrait(loader, SUCCESSFUL_MBR_RESOURCE)); - } - - public function testLoadWithValidSMILDocument2():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - factory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate); - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidSMILDocument); - loader.load(createLoadTrait(loader, SUCCESSFUL_PAR_RESOURCE)); - } - - public function testLoadWithValidSMILDocument3():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - factory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate); - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidSMILDocument); - loader.load(createLoadTrait(loader, SUCCESSFUL_SEQ_RESOURCE)); - } - - - private function onTestLoadWithValidSMILDocument(event:LoaderEvent):void - { - if (event.newState == LoadState.READY) - { - var trait:LoadFromDocumentLoadTrait = event.loadTrait as LoadFromDocumentLoadTrait; - assertTrue(trait != null); - - // Check that we got a valid MediaElement. - var element:MediaElement = trait.mediaElement; - assertTrue(element != null); - - // Also check that we got the expected created elements. - if (trait.resource == SUCCESSFUL_SEQ_RESOURCE) - { - assertTrue(createdElements.length == 3); - assertTrue(createdElements[0] is VideoElement); - assertTrue(createdElements[0].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); - assertTrue(createdElements[1] is VideoElement); - assertTrue(createdElements[1].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); - assertTrue(createdElements[2] is VideoElement); - assertTrue(createdElements[2].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); - } - else if (trait.resource == SUCCESSFUL_PAR_RESOURCE) - { - assertTrue(createdElements.length == 3); - assertTrue(createdElements[0] is VideoElement); - assertTrue(createdElements[0].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); - assertTrue(createdElements[1] is ImageElement); - assertTrue(createdElements[1].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); - assertTrue(createdElements[2] is VideoElement); - assertTrue(createdElements[2].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); - } - else if (trait.resource == SUCCESSFUL_MBR_RESOURCE) - { - assertTrue(createdElements.length == 1); - assertTrue(createdElements[0] is VideoElement); - assertTrue(createdElements[0].resource is DynamicStreamingResource); - assertTrue(createdElements[0].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); - } - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - - private function onMediaElementCreate(event:MediaFactoryEvent):void - { - assertTrue(event.mediaElement.resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) != null); - - createdElements.push(event.mediaElement); - } - - //--------------------------------------------------------------------- - - override protected function createInterfaceObject(... args):Object - { - return new SMILLoader(factory); - } - - override protected function get successfulResource():MediaResourceBase - { - return SUCCESSFUL_SEQ_RESOURCE; - } - - override protected function get failedResource():MediaResourceBase - { - return FAILED_RESOURCE; - } - - override protected function get unhandledResource():MediaResourceBase - { - return UNHANDLED_RESOURCE; - } - - override protected function verifyMediaErrorOnLoadFailure(error:MediaError):void - { - } - - override public function testCanHandleResource():void - { - super.testCanHandleResource(); - - // Verify some valid resources. - assertTrue(loader.canHandleResource(new URLResource("http://example.com/myfile.smil"))); - assertTrue(loader.canHandleResource(new URLResource("http://example.com/playlist.smi"))); - assertTrue(loader.canHandleResource(new URLResource("http://example.com/script.smil?param=value"))); - - // And some invalid ones. - assertFalse(loader.canHandleResource(new URLResource("file:///audio.mp3"))); - assertFalse(loader.canHandleResource(new URLResource("assets/audio.mp3"))); - assertFalse(loader.canHandleResource(new URLResource("audio.mp3"))); - assertFalse(loader.canHandleResource(new URLResource("httpt://example.com"))); - assertFalse(loader.canHandleResource(new URLResource("foo"))); - assertFalse(loader.canHandleResource(new URLResource(""))); - assertFalse(loader.canHandleResource(new URLResource(null))); - assertFalse(loader.canHandleResource(new NullResource())); - assertFalse(loader.canHandleResource(null)); - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder - } - - private static const TEST_TIME:int = 8000; - - private var factory:MediaFactory; - private var createdElements:Array; - private var eventDispatcher:EventDispatcher; - - private static const SUCCESSFUL_SEQ_RESOURCE:URLResource = new URLResource(SMILTestConstants.SMIL_DOCUMENT_SEQ_URL); - private static const SUCCESSFUL_PAR_RESOURCE:URLResource = new URLResource(SMILTestConstants.SMIL_DOCUMENT_PAR_URL); - private static const SUCCESSFUL_MBR_RESOURCE:URLResource = new URLResource(SMILTestConstants.SMIL_DOCUMENT_MBR_URL); - private static const FAILED_RESOURCE:URLResource = new URLResource(SMILTestConstants.MISSING_SMIL_DOCUMENT_URL); - private static const UNHANDLED_RESOURCE:URLResource = new URLResource("ftp://example.com"); - - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.test.smil.loader +{ + import flash.events.*; + + import org.osmf.elements.ImageElement; + import org.osmf.elements.VideoElement; + import org.osmf.elements.proxyClasses.LoadFromDocumentLoadTrait; + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaFactoryEvent; + import org.osmf.media.DefaultMediaFactory; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.metadata.MetadataNamespaces; + import org.osmf.net.DynamicStreamingResource; + import org.osmf.smil.loader.*; + import org.osmf.smil.model.*; + import org.osmf.test.smil.SMILTestConstants; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.traits.TestLoaderBase; + import org.osmf.utils.NullResource; + + public class TestSMILLoader extends TestLoaderBase + { + override public function setUp():void + { + eventDispatcher = new EventDispatcher(); + factory = new DefaultMediaFactory(); + createdElements = []; + + super.setUp(); + } + + override public function tearDown():void + { + super.tearDown(); + + createdElements = null; + factory = null; + eventDispatcher = null; + } + + + override protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait + { + return new LoadFromDocumentLoadTrait(loader, resource); + } + + public function testLoadWithValidSMILDocument():void + { + eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); + factory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate); + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidSMILDocument); + loader.load(createLoadTrait(loader, SUCCESSFUL_MBR_RESOURCE)); + } + + public function testLoadWithValidSMILDocument2():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + factory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate); + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidSMILDocument); + loader.load(createLoadTrait(loader, SUCCESSFUL_PAR_RESOURCE)); + } + + public function testLoadWithValidSMILDocument3():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + factory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate); + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithValidSMILDocument); + loader.load(createLoadTrait(loader, SUCCESSFUL_SEQ_RESOURCE)); + } + + + private function onTestLoadWithValidSMILDocument(event:LoaderEvent):void + { + if (event.newState == LoadState.READY) + { + var trait:LoadFromDocumentLoadTrait = event.loadTrait as LoadFromDocumentLoadTrait; + assertTrue(trait != null); + + // Check that we got a valid MediaElement. + var element:MediaElement = trait.mediaElement; + assertTrue(element != null); + + // Also check that we got the expected created elements. + if (trait.resource == SUCCESSFUL_SEQ_RESOURCE) + { + assertTrue(createdElements.length == 3); + assertTrue(createdElements[0] is VideoElement); + assertTrue(createdElements[0].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); + assertTrue(createdElements[1] is VideoElement); + assertTrue(createdElements[1].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); + assertTrue(createdElements[2] is VideoElement); + assertTrue(createdElements[2].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); + } + else if (trait.resource == SUCCESSFUL_PAR_RESOURCE) + { + assertTrue(createdElements.length == 3); + assertTrue(createdElements[0] is VideoElement); + assertTrue(createdElements[0].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); + assertTrue(createdElements[1] is ImageElement); + assertTrue(createdElements[1].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); + assertTrue(createdElements[2] is VideoElement); + assertTrue(createdElements[2].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); + } + else if (trait.resource == SUCCESSFUL_MBR_RESOURCE) + { + assertTrue(createdElements.length == 1); + assertTrue(createdElements[0] is VideoElement); + assertTrue(createdElements[0].resource is DynamicStreamingResource); + assertTrue(createdElements[0].resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) == trait.resource); + } + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + + private function onMediaElementCreate(event:MediaFactoryEvent):void + { + assertTrue(event.mediaElement.resource.getMetadataValue(MetadataNamespaces.DERIVED_RESOURCE_METADATA) != null); + + createdElements.push(event.mediaElement); + } + + //--------------------------------------------------------------------- + + override protected function createInterfaceObject(... args):Object + { + return new SMILLoader(factory); + } + + override protected function get successfulResource():MediaResourceBase + { + return SUCCESSFUL_SEQ_RESOURCE; + } + + override protected function get failedResource():MediaResourceBase + { + return FAILED_RESOURCE; + } + + override protected function get unhandledResource():MediaResourceBase + { + return UNHANDLED_RESOURCE; + } + + override protected function verifyMediaErrorOnLoadFailure(error:MediaError):void + { + } + + override public function testCanHandleResource():void + { + super.testCanHandleResource(); + + // Verify some valid resources. + assertTrue(loader.canHandleResource(new URLResource("http://example.com/myfile.smil"))); + assertTrue(loader.canHandleResource(new URLResource("http://example.com/playlist.smi"))); + assertTrue(loader.canHandleResource(new URLResource("http://example.com/script.smil?param=value"))); + + // And some invalid ones. + assertFalse(loader.canHandleResource(new URLResource("file:///audio.mp3"))); + assertFalse(loader.canHandleResource(new URLResource("assets/audio.mp3"))); + assertFalse(loader.canHandleResource(new URLResource("audio.mp3"))); + assertFalse(loader.canHandleResource(new URLResource("httpt://example.com"))); + assertFalse(loader.canHandleResource(new URLResource("foo"))); + assertFalse(loader.canHandleResource(new URLResource(""))); + assertFalse(loader.canHandleResource(new URLResource(null))); + assertFalse(loader.canHandleResource(new NullResource())); + assertFalse(loader.canHandleResource(null)); + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder + } + + private static const TEST_TIME:int = 8000; + + private var factory:MediaFactory; + private var createdElements:Array; + private var eventDispatcher:EventDispatcher; + + private static const SUCCESSFUL_SEQ_RESOURCE:URLResource = new URLResource(SMILTestConstants.SMIL_DOCUMENT_SEQ_URL); + private static const SUCCESSFUL_PAR_RESOURCE:URLResource = new URLResource(SMILTestConstants.SMIL_DOCUMENT_PAR_URL); + private static const SUCCESSFUL_MBR_RESOURCE:URLResource = new URLResource(SMILTestConstants.SMIL_DOCUMENT_MBR_URL); + private static const FAILED_RESOURCE:URLResource = new URLResource(SMILTestConstants.MISSING_SMIL_DOCUMENT_URL); + private static const UNHANDLED_RESOURCE:URLResource = new URLResource("ftp://example.com"); + + } +} diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/parser/TestSMILParser.as b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/parser/TestSMILParser.as index b85e189..191fd4e 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/parser/TestSMILParser.as +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/test/smil/parser/TestSMILParser.as @@ -1,120 +1,120 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.test.smil.parser -{ - import flash.errors.IllegalOperationError; - - import flexunit.framework.TestCase; - - import org.osmf.smil.model.SMILDocument; - import org.osmf.smil.model.SMILElement; - import org.osmf.smil.model.SMILElementType; - import org.osmf.smil.model.SMILMediaElement; - import org.osmf.smil.parser.SMILParser; - import org.osmf.test.smil.SMILTestConstants; - import org.osmf.utils.URL; - - public class TestSMILParser extends TestCase - { - public function TestSMILParser(methodName:String=null) - { - super(methodName); - } - - public function testParser():void - { - // A valid file - internalTestParser(SMILTestConstants.SMIL_DOCUMENT_CONTENTS_FULL); - - // A file with no tag - try - { - internalTestParser(SMILTestConstants.SMIL_DOCUMENT_CONTENTS_NO_BODY); - fail(); - } - catch (e:IllegalOperationError) - { - } - - // null data - try - { - var parser:SMILParser = new SMILParser(); - var document:SMILDocument = parser.parse(null); - fail(); - } - catch (e:ArgumentError) - { - } - - // empty data - try - { - parser = new SMILParser(); - document = parser.parse(""); - fail(); - } - catch (e:ArgumentError) - { - } - - // An rtmp dynamic streaming file - internalTestParser(SMILTestConstants.SMIL_DOCUMENT_CONTENTS_MBR); - - } - - private function internalTestParser(rawData:XML):void - { - var parser:SMILParser = new SMILParser(); - var document:SMILDocument = parser.parse(rawData.toXMLString()); - - assertTrue(document.numElements > 0); - for (var i:int = 0; i < document.numElements; i++) - { - var element:SMILElement = document.getElementAt(i); - testChildren(element); - } - - function testChildren(element:SMILElement):void - { - assertTrue(element.type != null); - if (element.type == SMILElementType.VIDEO) - { - validateVideoElement(element); - } - - for (var j:int = 0; j < element.numChildren; j++) - { - testChildren(element.getChildAt(j)); - } - } - - function validateVideoElement(element:SMILMediaElement):void - { - assertTrue(element.type == SMILElementType.VIDEO); - // Use the URL class to validate it's a valid URL - var uri:URL = new URL(element.src); - assertTrue(uri.path.length > 0); - } - } - } -} +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.test.smil.parser +{ + import flash.errors.IllegalOperationError; + + import flexunit.framework.TestCase; + + import org.osmf.smil.model.SMILDocument; + import org.osmf.smil.model.SMILElement; + import org.osmf.smil.model.SMILElementType; + import org.osmf.smil.model.SMILMediaElement; + import org.osmf.smil.parser.SMILParser; + import org.osmf.test.smil.SMILTestConstants; + import org.osmf.utils.URL; + + public class TestSMILParser extends TestCase + { + public function TestSMILParser(methodName:String=null) + { + super(methodName); + } + + public function testParser():void + { + // A valid file + internalTestParser(SMILTestConstants.SMIL_DOCUMENT_CONTENTS_FULL); + + // A file with no tag + try + { + internalTestParser(SMILTestConstants.SMIL_DOCUMENT_CONTENTS_NO_BODY); + fail(); + } + catch (e:IllegalOperationError) + { + } + + // null data + try + { + var parser:SMILParser = new SMILParser(); + var document:SMILDocument = parser.parse(null); + fail(); + } + catch (e:ArgumentError) + { + } + + // empty data + try + { + parser = new SMILParser(); + document = parser.parse(""); + fail(); + } + catch (e:ArgumentError) + { + } + + // An rtmp dynamic streaming file + internalTestParser(SMILTestConstants.SMIL_DOCUMENT_CONTENTS_MBR); + + } + + private function internalTestParser(rawData:XML):void + { + var parser:SMILParser = new SMILParser(); + var document:SMILDocument = parser.parse(rawData.toXMLString()); + + assertTrue(document.numElements > 0); + for (var i:int = 0; i < document.numElements; i++) + { + var element:SMILElement = document.getElementAt(i); + testChildren(element); + } + + function testChildren(element:SMILElement):void + { + assertTrue(element.type != null); + if (element.type == SMILElementType.VIDEO) + { + validateVideoElement(element); + } + + for (var j:int = 0; j < element.numChildren; j++) + { + testChildren(element.getChildAt(j)); + } + } + + function validateVideoElement(element:SMILMediaElement):void + { + assertTrue(element.type == SMILElementType.VIDEO); + // Use the URL class to validate it's a valid URL + var uri:URL = new URL(element.src); + assertTrue(uri.path.length > 0); + } + } + } +} diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as index 5435969..7f2c694 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/traits/TestLoaderBase.as @@ -1,415 +1,415 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.traits -{ - import flash.errors.IllegalOperationError; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.TimerEvent; - import flash.utils.Timer; - - import flexunit.framework.TestCase; - - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.utils.SimpleResource; - - public class TestLoaderBase extends TestCase - { - override public function setUp():void - { - super.setUp(); - - _loader = createLoader(); - - eventDispatcher = new EventDispatcher(); - eventCount = 0; - mediaErrors = []; - doTwice = false; - } - - override public function tearDown():void - { - super.tearDown(); - - _loader = null; - eventDispatcher = null; - } - - protected function createInterfaceObject(... args):Object - { - return new LoaderBase(); - } - - //--------------------------------------------------------------------- - - public function testCanHandleResource():void - { - assertTrue(loader.canHandleResource(successfulResource) == true); - assertTrue(loader.canHandleResource(failedResource) == true); - assertTrue(loader.canHandleResource(unhandledResource) == false); - } - - public function testLoad():void - { - doTestLoad(); - } - - public function testLoadTwice():void - { - doTwice = true; - doTestLoad(); - } - - private function doTestLoad():void - { - eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestLoad(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - if (doTwice) - { - reload = true; - } - else - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Calling load a second time should throw an exception. - try - { - event.loader.load(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - public function testLoadWithFailure():void - { - doTestLoadWithFailure(); - } - - public function testLoadWithFailureThenReload():void - { - doTwice = true; - doTestLoadWithFailure(); - } - - private function doTestLoadWithFailure():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); - var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); - loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - loader.load(loadTrait); - } - - private function onTestLoadWithFailure(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - if (eventCount == 1 && doTwice) - { - reload = true; - } - else - { - markCompleteOnMediaError(1); - } - break; - case 2: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOAD_ERROR); - assertTrue(event.newState == LoadState.LOADING); - break; - case 3: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - markCompleteOnMediaError(2); - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Reloading should repeat the failure. - event.loader.load(event.loadTrait); - } - } - - private function markCompleteOnMediaError(numExpected:int):void - { - if (numExpected == mediaErrors.length) - { - // Just verify one of them. - verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - else - { - // Wait a bit, then check again. - var timer:Timer = new Timer(400); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(event:TimerEvent):void - { - timer.stop(); - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - markCompleteOnMediaError(numExpected); - } - } - } - - public function testLoadWithInvalidResource():void - { - try - { - loader.load(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - public function testUnload():void - { - doTestUnload(); - } - - public function testUnloadTwice():void - { - doTwice = true; - doTestUnload(); - } - - private function doTestUnload():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestUnload(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var doUnload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - // Now unload. - doUnload = true; - - break; - case 2: - assertTrue(event.oldState == LoadState.READY); - assertTrue(event.newState == LoadState.UNLOADING); - break; - case 3: - assertTrue(event.oldState == LoadState.UNLOADING); - assertTrue(event.newState == LoadState.UNINITIALIZED); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - break; - - default: - fail(); - } - - eventCount++; - - if (doUnload) - { - event.loader.unload(event.loadTrait); - - if (doTwice) - { - // Unloading a second time should throw an exception - // (but the first unload will complete). - try - { - event.loader.unload(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - } - } - - public function testUnloadWithInvalidResource():void - { - try - { - loader.unload(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - //--------------------------------------------------------------------- - - protected final function createLoader():LoaderBase - { - return createInterfaceObject() as LoaderBase; - } - - protected function setOverriddenLoader(value:LoaderBase):void - { - _loader = value; - } - - protected final function get loader():LoaderBase - { - return _loader; - } - - protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - return new LoadTrait(loader, resource); - } - - - protected function get successfulResource():MediaResourceBase - { - throw new Error("Subclass must override get successfulResource!"); - } - - protected function get failedResource():MediaResourceBase - { - throw new Error("Subclass must override get failedResource!"); - } - - protected function get unhandledResource():MediaResourceBase - { - throw new Error("Subclass must override get unhandledResource!"); - } - - protected function verifyMediaErrorOnLoadFailure(error:MediaError):void - { - // Subclasses can override to check the error's properties. - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - private function mustNotReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is NOT received. - fail(); - } - - private function onMediaError(event:MediaErrorEvent):void - { - mediaErrors.push(event.error); - } - - private static const TEST_TIME:int = 8000; - - private var eventDispatcher:EventDispatcher; - private var eventCount:int = 0; - private var mediaErrors:Array; - private var _loader:LoaderBase; - private var doTwice:Boolean; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.traits +{ + import flash.errors.IllegalOperationError; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.TimerEvent; + import flash.utils.Timer; + + import flexunit.framework.TestCase; + + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.MediaResourceBase; + import org.osmf.utils.SimpleResource; + + public class TestLoaderBase extends TestCase + { + override public function setUp():void + { + super.setUp(); + + _loader = createLoader(); + + eventDispatcher = new EventDispatcher(); + eventCount = 0; + mediaErrors = []; + doTwice = false; + } + + override public function tearDown():void + { + super.tearDown(); + + _loader = null; + eventDispatcher = null; + } + + protected function createInterfaceObject(... args):Object + { + return new LoaderBase(); + } + + //--------------------------------------------------------------------- + + public function testCanHandleResource():void + { + assertTrue(loader.canHandleResource(successfulResource) == true); + assertTrue(loader.canHandleResource(failedResource) == true); + assertTrue(loader.canHandleResource(unhandledResource) == false); + } + + public function testLoad():void + { + doTestLoad(); + } + + public function testLoadTwice():void + { + doTwice = true; + doTestLoad(); + } + + private function doTestLoad():void + { + eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); + loader.load(createLoadTrait(loader, successfulResource)); + } + + private function onTestLoad(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var reload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.READY); + + if (doTwice) + { + reload = true; + } + else + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + break; + default: + fail(); + } + + eventCount++; + + if (reload) + { + // Calling load a second time should throw an exception. + try + { + event.loader.load(event.loadTrait); + + fail(); + } + catch (error:IllegalOperationError) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + public function testLoadWithFailure():void + { + doTestLoadWithFailure(); + } + + public function testLoadWithFailureThenReload():void + { + doTwice = true; + doTestLoadWithFailure(); + } + + private function doTestLoadWithFailure():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); + var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); + loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + loader.load(loadTrait); + } + + private function onTestLoadWithFailure(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var reload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.LOAD_ERROR); + + if (eventCount == 1 && doTwice) + { + reload = true; + } + else + { + markCompleteOnMediaError(1); + } + break; + case 2: + assertTrue(doTwice); + + assertTrue(event.oldState == LoadState.LOAD_ERROR); + assertTrue(event.newState == LoadState.LOADING); + break; + case 3: + assertTrue(doTwice); + + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.LOAD_ERROR); + + markCompleteOnMediaError(2); + break; + default: + fail(); + } + + eventCount++; + + if (reload) + { + // Reloading should repeat the failure. + event.loader.load(event.loadTrait); + } + } + + private function markCompleteOnMediaError(numExpected:int):void + { + if (numExpected == mediaErrors.length) + { + // Just verify one of them. + verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + else + { + // Wait a bit, then check again. + var timer:Timer = new Timer(400); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + + function onTimer(event:TimerEvent):void + { + timer.stop(); + timer.removeEventListener(TimerEvent.TIMER, onTimer); + + markCompleteOnMediaError(numExpected); + } + } + } + + public function testLoadWithInvalidResource():void + { + try + { + loader.load(createLoadTrait(loader, unhandledResource)); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + + public function testUnload():void + { + doTestUnload(); + } + + public function testUnloadTwice():void + { + doTwice = true; + doTestUnload(); + } + + private function doTestUnload():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); + loader.load(createLoadTrait(loader, successfulResource)); + } + + private function onTestUnload(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var doUnload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.READY); + + // Now unload. + doUnload = true; + + break; + case 2: + assertTrue(event.oldState == LoadState.READY); + assertTrue(event.newState == LoadState.UNLOADING); + break; + case 3: + assertTrue(event.oldState == LoadState.UNLOADING); + assertTrue(event.newState == LoadState.UNINITIALIZED); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + break; + + default: + fail(); + } + + eventCount++; + + if (doUnload) + { + event.loader.unload(event.loadTrait); + + if (doTwice) + { + // Unloading a second time should throw an exception + // (but the first unload will complete). + try + { + event.loader.unload(event.loadTrait); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + } + } + + public function testUnloadWithInvalidResource():void + { + try + { + loader.unload(createLoadTrait(loader, unhandledResource)); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + + //--------------------------------------------------------------------- + + protected final function createLoader():LoaderBase + { + return createInterfaceObject() as LoaderBase; + } + + protected function setOverriddenLoader(value:LoaderBase):void + { + _loader = value; + } + + protected final function get loader():LoaderBase + { + return _loader; + } + + protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait + { + return new LoadTrait(loader, resource); + } + + + protected function get successfulResource():MediaResourceBase + { + throw new Error("Subclass must override get successfulResource!"); + } + + protected function get failedResource():MediaResourceBase + { + throw new Error("Subclass must override get failedResource!"); + } + + protected function get unhandledResource():MediaResourceBase + { + throw new Error("Subclass must override get unhandledResource!"); + } + + protected function verifyMediaErrorOnLoadFailure(error:MediaError):void + { + // Subclasses can override to check the error's properties. + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + private function mustNotReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is NOT received. + fail(); + } + + private function onMediaError(event:MediaErrorEvent):void + { + mediaErrors.push(event.error); + } + + private static const TEST_TIME:int = 8000; + + private var eventDispatcher:EventDispatcher; + private var eventCount:int = 0; + private var mediaErrors:Array; + private var _loader:LoaderBase; + private var doTwice:Boolean; + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/utils/NullResource.as b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/utils/NullResource.as index b8b27cc..775b8e1 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/utils/NullResource.as +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/utils/NullResource.as @@ -1,29 +1,29 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.media.MediaResourceBase; - - public class NullResource extends MediaResourceBase - { - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.media.MediaResourceBase; + + public class NullResource extends MediaResourceBase + { + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as index 2e0ea2f..038567c 100644 --- a/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as +++ b/lib/osmf/samples/SMILPluginIntegrationTest/src/org/osmf/utils/SimpleResource.as @@ -1,44 +1,44 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.media.MediaResourceBase; - - public class SimpleResource extends MediaResourceBase - { - public static const SUCCESSFUL:String = "successful"; - public static const FAILED:String = "failed"; - public static const UNHANDLED:String = "unhandled"; - - public function SimpleResource(type:String) - { - _type = type; - } - - public function get type():String - { - return _type; - } - - private var _type:String; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.media.MediaResourceBase; + + public class SimpleResource extends MediaResourceBase + { + public static const SUCCESSFUL:String = "successful"; + public static const FAILED:String = "failed"; + public static const UNHANDLED:String = "unhandled"; + + public function SimpleResource(type:String) + { + _type = type; + } + + public function get type():String + { + return _type; + } + + private var _type:String; + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/.actionScriptProperties b/lib/osmf/samples/SMPTETTPlugin/.actionScriptProperties old mode 100755 new mode 100644 index 163754a..ed600f8 --- a/lib/osmf/samples/SMPTETTPlugin/.actionScriptProperties +++ b/lib/osmf/samples/SMPTETTPlugin/.actionScriptProperties @@ -1,10 +1,10 @@ - + - + diff --git a/lib/osmf/samples/SMPTETTPlugin/BSD-License.txt b/lib/osmf/samples/SMPTETTPlugin/BSD-License.txt old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/libs/OSMF1_6_FP10.swc b/lib/osmf/samples/SMPTETTPlugin/libs/OSMF1_6_FP10.swc old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/libs/playerglobal10_3.swc b/lib/osmf/samples/SMPTETTPlugin/libs/playerglobal10_3.swc old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/libs/textLayout.swc b/lib/osmf/samples/SMPTETTPlugin/libs/textLayout.swc old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/license.txt b/lib/osmf/samples/SMPTETTPlugin/license.txt old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/SMPTETTPlugin.as b/lib/osmf/samples/SMPTETTPlugin/src/SMPTETTPlugin.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/SMPTETTPluginInfo.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/SMPTETTPluginInfo.as old mode 100755 new mode 100644 index da6d79e..05dbd1d --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/SMPTETTPluginInfo.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/SMPTETTPluginInfo.as @@ -1,116 +1,117 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt -{ - import org.osmf.elements.VideoElement; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.MediaFactoryItemType; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.PluginInfo; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.net.NetLoader; +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt +{ + import org.osmf.elements.VideoElement; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.MediaFactoryItemType; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.PluginInfo; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.net.NetLoader; + import org.osmf.smpte.tt.architecture.creation.SMPTETTFactoryFacade; import org.osmf.smpte.tt.media.SMPTETTProxyElement; - - /** - * Encapsulation of a SMPTE-TT plugin. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public class SMPTETTPluginInfo extends PluginInfo - { - // Constants for specifying the Timed Text document URL on the resource metadata - public static const SMPTETT_METADATA_NAMESPACE:String = "http://www.osmf.org/smpte-tt/1.0"; - public static const SMPTETT_METADATA_KEY_URI:String = "uri"; - public static const SMPTETT_METADATA_KEY_MEDIAFACTORY:String = "MediaFactory"; - public static const SMPTETT_METADATA_KEY_MEDIAPLAYER:String = "MediaPlayer"; - public static const SMPTETT_METADATA_KEY_MEDIACONTAINER:String = "MediaContainer"; - public static const SMPTETT_METADATA_KEY_SHOWCAPTIONS:String = "showCaptions"; - - // Constants for the temporal metadata (captions) - public static const SMPTETT_TEMPORAL_METADATA_NAMESPACE:String = "http://www.osmf.org/temporal/smpte-tt"; - - /** - * Constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function SMPTETTPluginInfo() - { - var items:Vector. = new Vector.(); - - var item:MediaFactoryItem = new MediaFactoryItem - ("org.osmf.smpte.tt.SMPTETTPluginInfo" - ,canHandleResourceCallback - ,createSMPTETTProxyElement - ,MediaFactoryItemType.PROXY); - - - - - items.push(item); - - super(items, creationNotificationFunction); - } - - private function canHandleResourceCallback(resource:MediaResourceBase):Boolean - { - var result:Boolean = true; - /* - if (resource != null) - { - - var settings:Metadata - = resource.getMetadataValue(SMPTETT_METADATA_NAMESPACE) as Metadata; - - result = settings != null; - - } - */ - return result; - } - - private function createSMPTETTProxyElement():MediaElement - { - return new SMPTETTProxyElement(); - } - - // OSMF will invoke this function for any MediaElement returned by - // MediaFactory.createMediaElement. Note that this function will - // even be invoked for MediaElements created prior to the loading - // of this plug-in, so as to isolate the plug-in from load order - // dependencies. - private function creationNotificationFunction(media:MediaElement):void - { - trace("creationNotificationFunction( "+media+" )"); - if (media is VideoElement) - { - VideoElement( media ).smoothing = true; - } - } - } + + /** + * Encapsulation of a SMPTE-TT plugin. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public class SMPTETTPluginInfo extends PluginInfo + { + // Constants for specifying the Timed Text document URL on the resource metadata + public static const SMPTETT_METADATA_NAMESPACE:String = "http://www.osmf.org/smpte-tt/1.0"; + public static const SMPTETT_METADATA_KEY_URI:String = "uri"; + public static const SMPTETT_METADATA_KEY_MEDIAFACTORY:String = "MediaFactory"; + public static const SMPTETT_METADATA_KEY_MEDIAPLAYER:String = "MediaPlayer"; + public static const SMPTETT_METADATA_KEY_MEDIACONTAINER:String = "MediaContainer"; + public static const SMPTETT_METADATA_KEY_SHOWCAPTIONS:String = "showCaptions"; + + // Constants for the temporal metadata (captions) + public static const SMPTETT_TEMPORAL_METADATA_NAMESPACE:String = "http://www.osmf.org/temporal/smpte-tt"; + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function SMPTETTPluginInfo() + { + var items:Vector. = new Vector.(); + + var item:MediaFactoryItem = new MediaFactoryItem + ("org.osmf.smpte.tt.SMPTETTPluginInfo" + ,canHandleResourceCallback + ,createSMPTETTProxyElement + ,MediaFactoryItemType.PROXY); + + + + + items.push(item); + + super(items, creationNotificationFunction); + } + + private function canHandleResourceCallback(resource:MediaResourceBase):Boolean + { + var result:Boolean = true; + /* + if (resource != null) + { + + var settings:Metadata + = resource.getMetadataValue(SMPTETT_METADATA_NAMESPACE) as Metadata; + + result = settings != null; + + } + */ + return result; + } + + private function createSMPTETTProxyElement():MediaElement + { + //return new SMPTETTProxyElement(); + return SMPTETTFactoryFacade.getSMPTETTProxyElement(); + } + + // OSMF will invoke this function for any MediaElement returned by + // MediaFactory.createMediaElement. Note that this function will + // even be invoked for MediaElements created prior to the loading + // of this plug-in, so as to isolate the plug-in from load order + // dependencies. + private function creationNotificationFunction(media:MediaElement):void + { + if (media is VideoElement) + { + VideoElement( media ).smoothing = true; + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/architecture/creation/SMPTETTFactoryFacade.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/architecture/creation/SMPTETTFactoryFacade.as new file mode 100644 index 0000000..558a612 --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/architecture/creation/SMPTETTFactoryFacade.as @@ -0,0 +1,48 @@ +package org.osmf.smpte.tt.architecture.creation +{ + import org.osmf.smpte.tt.loader.SMPTETTLoader; + import org.osmf.smpte.tt.media.SMPTETTProxyElement; + import org.osmf.smpte.tt.media.SMPTETTProxyElementAsync; + import org.osmf.smpte.tt.parsing.SMPTETTParser; + import org.osmf.smpte.tt.parsing.SMPTETTParserAsync; + + + public class SMPTETTFactoryFacade + { + private static var _loaderClz:Class = SMPTETTLoader; + private static var _proxyClz:Class = SMPTETTProxyElementAsync; + private static var _parserClz:Class = SMPTETTParserAsync; + + //private static var _loaderClz:Class = SMPTETTLoader; + //private static var _proxyClz:Class = SMPTETTProxyElement; + //private static var _parserClz:Class = SMPTETTParser; + + public static function getSMPTETTLoader():SMPTETTLoader + { + return new _loaderClz(); + } + public static function setSMPTETTLoader(v:Class):void + { + _loaderClz = v; + + } + + public static function getSMPTETTProxyElement():SMPTETTProxyElement + { + return new _proxyClz() + } + public static function setSMPTETTProxyElement(v:Class):void + { + _proxyClz = v; + } + + public static function getSMPTETTParser():SMPTETTParser + { + return new _parserClz() + } + public static function setSMPTETTParser(v:Class):void + { + _parserClz = v; + } + } +} \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptionElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptionElement.as old mode 100755 new mode 100644 index 05ade70..22e0d58 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptionElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptionElement.as @@ -1,83 +1,92 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.captions -{ - /** - * - * @author mjordan - * - */ - public class CaptionElement extends TimedTextElement - { - /** - * - * @param start - * @param end - * @param id - * - */ - public function CaptionElement(start:Number, end:Number, id:String=null) - { - super(start, end, id); - this.captionElementType = TimedTextElementType.Text; - } - - private var _index:int; - /** - * - * @return - * - */ - public function get index():int - { - return _index; - } - /** - * - * @param value - * - */ - public function set index(value:int):void - { - _index = value; - } - - private var _regionId:String; - /** - * - * @return - * - */ - public function get regionId():String - { - return _regionId; - } - /** - * - * @param value - * - */ - public function set regionId(value:String):void - { - _regionId = value; - } - - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.captions +{ + import flash.utils.getQualifiedClassName; + + import org.osmf.smpte.tt.timing.TimeExpression; + + /** + * + * @author mjordan + * + */ + public class CaptionElement extends TimedTextElement + { + /** + * + * @param start + * @param end + * @param id + * + */ + public function CaptionElement(start:Number, end:Number, id:String=null) + { + super(start, end, id); + this.captionElementType = TimedTextElementType.Text; + } + + private var _index:int; + /** + * + * @return + * + */ + public function get index():int + { + return _index; + } + /** + * + * @param value + * + */ + public function set index(value:int):void + { + _index = value; + } + + private var _regionId:String; + /** + * + * @return + * + */ + public function get regionId():String + { + return _regionId; + } + /** + * + * @param value + * + */ + public function set regionId(value:String):void + { + _regionId = value; + } + + public function toString():String + { + return "["+getQualifiedClassName(this).split("::")[1]+" captionElementType=\""+captionElementType+"\" index=\""+_index+"\" id=\""+id+"\" regionID=\""+_regionId+"\" begin=\""+TimeExpression.parse(begin+"s")+"\" end=\""+TimeExpression.parse(end+"s")+"\""+( (content is String) ? " content=\""+content+"\"" : "" )+"]"; + } + + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptionRegion.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptionRegion.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptioningDocument.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptioningDocument.as old mode 100755 new mode 100644 index 7d6ff20..53bca67 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptioningDocument.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/CaptioningDocument.as @@ -1,288 +1,287 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.captions -{ - import flash.utils.Dictionary; - - import org.osmf.smpte.tt.timing.TimeExpression; - import org.osmf.smpte.tt.timing.TreeType; - import org.osmf.smpte.tt.utilities.DictionaryUtils; - - public class CaptioningDocument - { - import flash.errors.IllegalOperationError; - - import org.osmf.utils.OSMFStrings; - - /** - * The title, if it was found in the metadata in the header. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function get title():String - { - return _title; - } - - public function set title(value:String):void - { - _title = value; - } - - /** - * The description, if it was found in the metadata in the header. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function get description():String - { - return _desc; - } - - public function set description(value:String):void - { - _desc = value; - } - - /** - * The copyright, if it was found in the metadata in the header. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function get copyright():String - { - return _copyright; - } - - public function set copyright(value:String):void - { - _copyright = value; - } - - /** - * Returns a vector of CaptionElements, one for each unique timeline event in the file. - *

      Additional CaptionsElements that occur at the same TimelineMarker are stored in each CaptionElements siblings Vector..

      - * - * @return - * - */ - public function get captionElements():Vector. - { - return _captionElements; - } - - /** - * Returns a dictionary of CaptionElements indexed by a TimeCode string in the format "00:00:00:00", one for each unique timeline event in the file. - *

      Additional CaptionsElements that occur at the same TimelineMarker are stored in each CaptionElements siblings Vector..

      - * - * @return - * - */ - public function get captionElementsHash():Dictionary - { - return _captionElementsHash; - } - - /** - * Add a caption object. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function addCaptionElement(caption:CaptionElement):void - { - if (_captionElements == null) - { - _captionElements = new Vector.(); - _captionElementsHash = new Dictionary(); - } - var timeString:String = TimeExpression.parse(caption.begin+"s").toString(); - if(!_captionElementsHash[timeString]){ - _captionElementsHash[timeString] = caption; - _captionElements.push(caption); - } else if(_captionElementsHash[timeString].siblings.indexOf(caption as TimedTextElement)==-1){ - _captionElementsHash[timeString].siblings.push(caption); - } - } - - /** - * Returns the caption object at the index specified. - * - * @throws IllegalOperationError If index argument is out of range. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function getCaptionElementAt(index:int):CaptionElement - { - if (_captionElements == null || index >= _captionElements.length) - { - throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); - } - - return _captionElements[index]; - } - - /** - * Returns the number of root TimelineMarker events in this class' - * internal collection. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function get numTimelineMarkerEvents():int - { - var num:int = 0; - - if (_captionElements != null) - { - num = _captionElements.length; - } - - return num; - } - - /** - * Returns the total number of root CaptionElements from the internal collection, - * including captions that are triggered by the same TimelineMarker event. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function get totalCaptionElements():int - { - var num:int = 0; - - if (_captionElements != null) - { - for each(var c:CaptionElement in _captionElements){ - num += 1+c.siblings.length; - } - } - - return num; - } - - /** - * Returns a flattened Vector. of root CaptionElements active at a given time. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function getActiveCaptionsElements(time:Number):Vector. - { - var i:uint, - j:uint, - c:CaptionElement, - s:CaptionElement, - cc:Vector. = new Vector.(); - for(i=0; itime) - { - cc.push(c); - for each(s in c.siblings) - { - if(s.begin<=time && (s.end)>time) - { - cc.push(s); - } - } - } - } - return cc; - } - - /** - * Returns a vector of CaptionRegions indexed by integer. - * - * @return - * - */ - public function get captionRegions():Vector. - { - return _captionRegions; - } - - /** - * Returns a dictionary of CaptionRegions indexed by region id. - * - * @return - * - */ - public function get captionRegionsHash():Dictionary - { - return _captionRegionsHash; - } - - /** - * Add a region object. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function addCaptionRegion(region:CaptionRegion):void - { - if (_captionRegions == null) - { - _captionRegions = new Vector.(); - _captionRegionsHash = new Dictionary(); - } - if(!_captionRegionsHash[region.id]){ - _captionRegionsHash[region.id] = region; - _captionRegions.push(region); - } - } - - public function CaptioningDocument() - { - } - - private var _title:String; - private var _desc:String; - private var _copyright:String; - private var _captionElements:Vector.; - private var _captionElementsHash:Dictionary; - private var _captionRegions:Vector.; - private var _captionRegionsHash:Dictionary; - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.captions +{ + import flash.errors.IllegalOperationError; + import flash.utils.Dictionary; + + import org.osmf.utils.OSMFStrings; + + public class CaptioningDocument + { + + /** + * The title, if it was found in the metadata in the header. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function get title():String + { + return _title; + } + + public function set title(value:String):void + { + _title = value; + } + + /** + * The description, if it was found in the metadata in the header. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function get description():String + { + return _desc; + } + + public function set description(value:String):void + { + _desc = value; + } + + /** + * The copyright, if it was found in the metadata in the header. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function get copyright():String + { + return _copyright; + } + + public function set copyright(value:String):void + { + _copyright = value; + } + + /** + * Returns a vector of CaptionElements, one for each unique timeline event in the file. + *

      Additional CaptionsElements that occur at the same TimelineMarker are stored in each CaptionElements siblings Vector..

      + * + * @return + * + */ + public function get captionElements():Vector. + { + return _captionElements; + } + + /** + * Returns a dictionary of CaptionElements indexed by a TimeCode string in the format "00:00:00:00", one for each unique timeline event in the file. + *

      Additional CaptionsElements that occur at the same TimelineMarker are stored in each CaptionElements siblings Vector..

      + * + * @return + * + */ + public function get captionElementsHash():Dictionary + { + return _captionElementsHash; + } + + /** + * Add a caption object. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function addCaptionElement(caption:CaptionElement):void + { + if (_captionElements == null) + { + _captionElements = new Vector.(); + _captionElementsHash = new Dictionary(); + } + var timeString:String = caption.begin+"s"; + if(!_captionElementsHash[timeString]) + { + _captionElementsHash[timeString] = caption; + _captionElements.push(caption); + } + else if(_captionElementsHash[timeString].siblings.indexOf(caption as TimedTextElement)==-1) + { + _captionElementsHash[timeString].siblings.push(caption); + } + } + + /** + * Returns the caption object at the index specified. + * + * @throws IllegalOperationError If index argument is out of range. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function getCaptionElementAt(index:int):CaptionElement + { + if (_captionElements == null || index >= _captionElements.length) + { + throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); + } + + return _captionElements[index]; + } + + /** + * Returns the number of root TimelineMarker events in this class' + * internal collection. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function get numTimelineMarkerEvents():int + { + var num:int = 0; + + if (_captionElements != null) + { + num = _captionElements.length; + } + + return num; + } + + /** + * Returns the total number of root CaptionElements from the internal collection, + * including captions that are triggered by the same TimelineMarker event. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function get totalCaptionElements():int + { + var num:int = 0; + + if (_captionElements != null) + { + for each(var c:CaptionElement in _captionElements){ + num += (c.siblings.length+1); + } + } + + return num; + } + + /** + * Returns a flattened Vector. of root CaptionElements active at a given time. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function getActiveCaptionsElements(time:Number):Vector. + { + var i:uint, + j:uint, + c:CaptionElement, + s:CaptionElement, + cc:Vector. = new Vector.(); + for(i=0; itime) + { + cc.push(c); + for each(s in c.siblings) + { + if(s.begin<=time && (s.end)>time) + { + cc.push(s); + } + } + } + } + return cc; + } + + /** + * Returns a vector of CaptionRegions indexed by integer. + * + * @return + * + */ + public function get captionRegions():Vector. + { + return _captionRegions; + } + + /** + * Returns a dictionary of CaptionRegions indexed by region id. + * + * @return + * + */ + public function get captionRegionsHash():Dictionary + { + return _captionRegionsHash; + } + + /** + * Add a region object. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function addCaptionRegion(region:CaptionRegion):void + { + if (_captionRegions == null) + { + _captionRegions = new Vector.(); + _captionRegionsHash = new Dictionary(); + } + if(!_captionRegionsHash[region.id]){ + _captionRegionsHash[region.id] = region; + _captionRegions.push(region); + } + } + + public function CaptioningDocument() + { + } + + private var _title:String; + private var _desc:String; + private var _copyright:String; + private var _captionElements:Vector.; + private var _captionElementsHash:Dictionary; + private var _captionRegions:Vector.; + private var _captionRegionsHash:Dictionary; + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/DisplayAlign.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/DisplayAlign.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/Length.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/Length.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/Overflow.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/Overflow.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/ShowBackground.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/ShowBackground.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TextAlignment.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TextAlignment.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextAnimation.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextAnimation.as old mode 100755 new mode 100644 index f6f45b0..ae17bc2 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextAnimation.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextAnimation.as @@ -68,10 +68,9 @@ package org.osmf.smpte.tt.captions s.fontFamily = style.fontFamily; break; case "fontSize": - s.fontSize = style.fontSize; - break; case "ttFontSize": s.ttFontSize = style.ttFontSize; + s.fontSize = style.fontSize; break; case "fontStyle": s.fontStyle = style.fontStyle; @@ -80,10 +79,9 @@ package org.osmf.smpte.tt.captions s.fontWeight = style.fontWeight; break; case "lineHeight": - s.lineHeight = style.lineHeight; - break; case "ttLineHeight": s.ttLineHeight = style.ttLineHeight; + s.lineHeight = style.lineHeight; break; case "opacity": s.opacity = style.opacity; @@ -103,6 +101,14 @@ package org.osmf.smpte.tt.captions case "textAlign": s.textAlign = style.textAlign; break; + case "lineThrough": + case "textDecoration": + s.textDecoration = style.textDecoration; + s.lineThrough = style.lineThrough; + break; + case "textOutline": + s.textOutline = style.textOutline; + break; case "visibility": s.visibility = style.visibility; break; diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextElement.as old mode 100755 new mode 100644 index 2b3af76..5c8b116 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextElement.as @@ -19,13 +19,9 @@ **********************************************************/ package org.osmf.smpte.tt.captions { - import flash.utils.Timer; import flash.utils.getTimer; import org.osmf.metadata.TimelineMarker; - import org.osmf.smpte.tt.events.PropertyChangedEvent; - import org.osmf.smpte.tt.timing.TimeCode; - import org.osmf.smpte.tt.timing.TimeSpan; import org.osmf.smpte.tt.utilities.VectorUtils; /** @@ -37,12 +33,14 @@ package org.osmf.smpte.tt.captions private var _type:String; private var _end:Number; private var _content:*; + private var _parentElement:TimedTextElement; private var _currentStyle:TimedTextStyle; private var _style:TimedTextStyle; private var _captionElementType:TimedTextElementType; - private var _animations:Vector.; + private var _animations:Vector.; private var _children:Vector.; private var _siblings:Vector.; + private static const TOLERANCE:Number = 0.25; /** * Gets or sets a unique identifier for the marker. @@ -60,8 +58,21 @@ package org.osmf.smpte.tt.captions _id = value; } } - + /** + * Gets or sets the text associated with this marker. + */ + public function get parentElement():* + { + return _parentElement; + } + + public function set parentElement(value:*):void + { + if (_parentElement!=value) + _parentElement = value; + } + /** * Gets or sets the text associated with this marker. */ @@ -72,10 +83,8 @@ package org.osmf.smpte.tt.captions public function set content(value:*):void { - if(_content!=value){ - var oldContent:* = _content; + if (_content!=value) _content = value; - } } /** @@ -87,10 +96,8 @@ package org.osmf.smpte.tt.captions } public function set type(value:String):void { - if(_type!=value){ - var oldValue:* = _type; + if (_type!=value) _type = value; - } } public function get children():Vector. @@ -112,7 +119,8 @@ package org.osmf.smpte.tt.captions } public function set style(value:TimedTextStyle):void { - if(_style!=value){ + if (_style!=value) + { var oldValue:* = _style; _style = value; _currentStyle = value; @@ -124,13 +132,12 @@ package org.osmf.smpte.tt.captions */ public function get currentStyle():TimedTextStyle { - return _currentStyle; + return (_currentStyle) ? _currentStyle : _style; } - protected function set currentStyle(value:TimedTextStyle):void + public function set currentStyle(value:TimedTextStyle):void { if (_currentStyle != value) { - var oldValue:* = _currentStyle; _currentStyle = value; } } @@ -177,7 +184,7 @@ package org.osmf.smpte.tt.captions /** * Gets or sets the list of animations to be applied to this element. */ - public function get animations():Vector. + public function get animations():Vector. { return _animations; } @@ -190,7 +197,7 @@ package org.osmf.smpte.tt.captions _type = "captionelement"; _style = new TimedTextStyle(); - _animations = new Vector.(); + _animations = new Vector.(); _children = new Vector.(); _siblings = new Vector.(); _end = end; @@ -209,17 +216,23 @@ package org.osmf.smpte.tt.captions public function calculateCurrentStyle(position:Number):void { var func:Function; - var activeAnimations:Vector. = TimedTextElement.whereActiveAtPosition(animations as Vector.,position); - + var activeAnimations:Vector. = TimedTextElement.whereActiveAtPosition(animations,position); if (activeAnimations.length>0) - { + { var animatedStyle:TimedTextStyle = style.clone(); func = function(item:*, index:int, array:Array):void { - if(item is TimedTextAnimation) (item as TimedTextAnimation).mergeStyle(this); + if (item is TimedTextAnimation) + { + TimedTextAnimation(item).mergeStyle(this); + // trace("\t"+TimedTextAnimation(item).propertyName+" "+TimedTextAnimation(item).style[TimedTextAnimation(item).propertyName]); + } } VectorUtils.toArray(activeAnimations).map(func, animatedStyle); _currentStyle = animatedStyle; + } else + { + _currentStyle = style; } var i:Vector. = TimedTextElement.whereActiveAtPosition(children,position); func = function(item:*, index:int, array:Array):void @@ -229,7 +242,6 @@ package org.osmf.smpte.tt.captions VectorUtils.toArray(i).map(func,position); } - public function isActiveAtPosition(position:Number, round:Boolean = false):Boolean { return TimedTextElement.IsActiveAtPosition(this,position,round); @@ -250,34 +262,12 @@ package org.osmf.smpte.tt.captions if (round) { - var bFloor:Number = Math.floor(tte.begin*100)/100; - var pRound:Number = Math.round(position*100)/100; - var eCeil:Number = Math.ceil(tte.end*100)/100; + var bFloor:Number = Math.floor(tte.begin*500)/500; + var pRound:Number = Math.round(position*500)/500; + var eCeil:Number = Math.ceil(tte.end*500)/500; var beginRange:Number = Math.abs(position-tte.begin); var endRange:Number = Math.abs(tte.end-position); - var closeEnough:Boolean = (bFloor <= pRound || beginRange <= 0.25) && (eCeil > pRound && endRange>0.1); - /* - var label:String = ""; - - if (tte.content) - label += tte.content; - - getContent(tte, label); - - function getContent(ce:TimedTextElement, label:String):void - { - if (ce.content) - { - label += ce.content; - } - for each (var c:TimedTextElement in ce.children) - { - getContent(c, label); - } - } - if(label.length) - trace(closeEnough+" : \n\t" + label +"\n\t" + bFloor +" <= "+ pRound + " ("+beginRange+") && " + eCeil +" > "+ pRound+ " ("+endRange+")"); - */ + var closeEnough:Boolean = (bFloor <= pRound || beginRange <= TOLERANCE) && (eCeil > pRound && endRange>0.05); return closeEnough; } return tte.begin <= position && position < tte.end; @@ -300,10 +290,9 @@ package org.osmf.smpte.tt.captions { var func:Function = function(item:*, index:int, vector:Array):Boolean { - return (item as TimedTextElement).isActiveAtPosition(this); + return TimedTextElement(item).isActiveAtPosition(this,true); } return Vector.( VectorUtils.toArray(vector).filter(func,position) ); } - } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextElementType.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextElementType.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextStyle.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextStyle.as old mode 100755 new mode 100644 index 3c3ec65..71eb609 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextStyle.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/captions/TimedTextStyle.as @@ -19,8 +19,8 @@ **********************************************************/ package org.osmf.smpte.tt.captions { - import flashx.textLayout.property.Property; - import flashx.textLayout.tlf_internal; + import flash.utils.getTimer; + import flashx.textLayout.formats.BlockProgression; import flashx.textLayout.formats.Category; import flashx.textLayout.formats.Direction; @@ -28,24 +28,18 @@ package org.osmf.smpte.tt.captions import flashx.textLayout.formats.ITextLayoutFormat; import flashx.textLayout.formats.LineBreak; import flashx.textLayout.formats.TextLayoutFormat; + import flashx.textLayout.property.Property; + import flashx.textLayout.tlf_internal; - import org.osmf.smpte.tt.styling.TextOutline; - import org.osmf.smpte.tt.styling.Visibility; - import org.osmf.smpte.tt.styling.WritingMode; - import org.osmf.smpte.tt.styling.WrapOption; - import flashx.textLayout.formats.WhiteSpaceCollapse; - import flashx.textLayout.formats.TextAlign; - import flash.utils.getTimer; - import flashx.textLayout.formats.VerticalAlign; - import flashx.textLayout.formats.BackgroundColor; - import org.osmf.smpte.tt.enums.Unit; import org.osmf.smpte.tt.styling.Extent; - import org.osmf.smpte.tt.styling.Origin; - import org.osmf.smpte.tt.styling.PaddingThickness; - import flash.text.engine.FontPosture; - import flash.text.engine.FontWeight; import org.osmf.smpte.tt.styling.FontSize; import org.osmf.smpte.tt.styling.LineHeight; + import org.osmf.smpte.tt.styling.Origin; + import org.osmf.smpte.tt.styling.PaddingThickness; + import org.osmf.smpte.tt.styling.TextOutline; + import org.osmf.smpte.tt.styling.Visibility; + import org.osmf.smpte.tt.styling.WrapOption; + import org.osmf.smpte.tt.styling.WritingMode; use namespace tlf_internal; @@ -394,25 +388,30 @@ package org.osmf.smpte.tt.captions case "lrtb": case "lr": blockProgression = BlockProgression.TB; - direction =Direction.LTR; + if (!direction) + direction = Direction.LTR; break; case "rltb": case "rl": blockProgression = BlockProgression.TB; - direction = Direction.RTL; + if (!direction) + direction = Direction.RTL; break; case "tbrl": case "tb": blockProgression = BlockProgression.RL; - direction = Direction.RTL; + if (!direction) + direction = Direction.RTL; break; case "tblr": blockProgression = BlockProgression.RL; - direction = Direction.LTR; + if (!direction) + direction = Direction.LTR; break; default: blockProgression = BlockProgression.TB; - direction =Direction.LTR; + if (!direction) + direction = Direction.LTR; break; } } @@ -432,25 +431,28 @@ package org.osmf.smpte.tt.captions super(initialValues); id = flash.utils.getTimer().toString(); - /**/ - backgroundColor = 0x000000; - backgroundAlpha = 0; - color = 0xFFFFFF; - textAlpha = TextLayoutFormat.textAlphaProperty.defaultValue; - displayAlign = TimedTextStyle.displayAlignProperty.defaultValue; - display = TimedTextStyle.displayProperty.defaultValue; - extent = new org.osmf.smpte.tt.styling.Extent("80% 10%"); - fontFamily = TextLayoutFormat.fontFamilyProperty.defaultValue; - fontStyle = FontPosture.NORMAL; - fontWeight = FontWeight.NORMAL; - ttFontSize = new FontSize("1c"); - opacity = 1; - origin = new org.osmf.smpte.tt.styling.Origin("10% 80%"); - padding = new org.osmf.smpte.tt.styling.PaddingThickness("2px"); - showBackground = ShowBackground.Always.value; - textAlign = TextAlign.CENTER; - visibility = Visibility.VISIBLE.value; - wrapOption = WrapOption.WRAP.value; + + /* + if (!initialValues) + { + displayAlign = TimedTextStyle.displayAlignProperty.defaultValue; + display = TimedTextStyle.displayProperty.defaultValue; + opacity = TimedTextStyle.opacityProperty.defaultValue; + showBackground = TimedTextStyle.showBackgroundProperty.defaultValue; + visibility = TimedTextStyle.visibilityProperty.defaultValue; + wrapOption = TimedTextStyle.wrapOptionProperty.defaultValue; + + backgroundColor = TextLayoutFormat.backgroundColorProperty.defaultValue; + backgroundAlpha = TextLayoutFormat.backgroundAlphaProperty.defaultValue; + color = TextLayoutFormat.colorProperty.defaultValue; + textAlpha = TextLayoutFormat.textAlphaProperty.defaultValue; + fontFamily = TextLayoutFormat.fontFamilyProperty.defaultValue; + fontStyle = TextLayoutFormat.fontStyleProperty.defaultValue; + fontWeight = TextLayoutFormat.fontWeightProperty.defaultValue; + ttFontSize = new FontSize("1c"); + textAlign = TextLayoutFormat.textAlignProperty.defaultValue; + } + */ } public function clone():TimedTextStyle diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/enums/Enum.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/enums/Enum.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/enums/NumberType.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/enums/NumberType.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/enums/Unit.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/enums/Unit.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/errors/SMPTETTException.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/errors/SMPTETTException.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/events/ParseEvent.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/events/ParseEvent.as old mode 100755 new mode 100644 index e0243d3..b9374be --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/events/ParseEvent.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/events/ParseEvent.as @@ -1,49 +1,64 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.events -{ - import flash.events.Event; - - public class ParseEvent extends Event - { - public static const BEGIN:String = "begin"; - public static const PROGRESS:String = "progress"; - public static const COMPLETE:String = "complete"; - - private var _data:Object; - - public function get data():Object - { - return _data; - } - - public function set data(value:Object):void - { - _data = value; - } - - - public function ParseEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false, data:Object=null) - { - _data = data; - super(type, bubbles, cancelable); - } - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.events +{ + import flash.events.Event; + + public class ParseEvent extends Event + { + public static const BEGIN:String = "begin"; + public static const PROGRESS:String = "progress"; + public static const COMPLETE:String = "complete"; + public static const PARTIAL:String = "partial"; + + private var _data:Object; + + public function get data():Object + { + return _data; + } + + public function set data(value:Object):void + { + _data = value; + } + + + public override function clone():Event + { + return new ParseEvent(type,bubbles,cancelable,data); + } + + + public override function toString():String + { + return formatToString("ParseEvent","type","data"); + } + + + public function ParseEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false, data:Object=null) + { + _data = data; + super(type, bubbles, cancelable); + } + + + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/events/PropertyChangedEvent.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/events/PropertyChangedEvent.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Animation.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Animation.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Block.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Block.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/BlockContainer.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/BlockContainer.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Flow.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Flow.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/FormattingObject.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/FormattingObject.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Inline.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Inline.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/InlineContent.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/InlineContent.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Paragraph.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Paragraph.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Root.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/Root.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/ZOrdering.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/formatting/ZOrdering.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/informatics/MetadataInformation.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/informatics/MetadataInformation.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoadTrait.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoadTrait.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoader.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoader.as old mode 100755 new mode 100644 index d0e8684..7292e60 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoader.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoader.as @@ -20,6 +20,7 @@ package org.osmf.smpte.tt.loader { import flash.events.IEventDispatcher; + import flash.utils.getTimer; import org.osmf.events.LoaderEvent; import org.osmf.events.MediaErrorEvent; @@ -30,6 +31,7 @@ package org.osmf.smpte.tt.loader import org.osmf.smpte.tt.model.TtElement; import org.osmf.smpte.tt.parsing.ISMPTETTParser; import org.osmf.smpte.tt.parsing.SMPTETTParser; + import org.osmf.smpte.tt.timing.TimeCode; import org.osmf.smpte.tt.timing.TimeExpression; import org.osmf.traits.LoadState; import org.osmf.traits.LoadTrait; @@ -95,100 +97,16 @@ package org.osmf.smpte.tt.loader */ override protected function executeLoad(loadTrait:LoadTrait):void { - updateLoadTrait(loadTrait, LoadState.LOADING); - - httpLoader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - - // Create a temporary LoadTrait for this purpose, so that our main - // LoadTrait doesn't reflect any of the state changes from the - // loading of the URL, and so that we can catch any errors. - var httpLoadTrait:HTTPLoadTrait = new HTTPLoadTrait(httpLoader, loadTrait.resource); - - httpLoadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug("Downloading document at " + URLResource(httpLoadTrait.resource).url); - } - } - - httpLoader.load(httpLoadTrait); - - function onHTTPLoaderStateChange(event:LoaderEvent):void - { - if (event.newState == LoadState.READY) - { - // This is a terminal state, so remove all listeners. - httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - var parser:ISMPTETTParser = createSMPTETTParser(); - var captioningDocument:CaptioningDocument; - - try - { - TimeExpression.initializeParameters(); - var p:SMPTETTParser = parser as SMPTETTParser; - if (p) - { - p.addEventListener(ParseEvent.BEGIN, onParseEvent); - p.addEventListener(ParseEvent.PROGRESS, onParseEvent); - p.addEventListener(ParseEvent.COMPLETE, onParseEvent); - } - parser.parse(httpLoadTrait.urlLoader.data.toString()); - } - catch(e:Error) - { - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug("Error parsing captioning document: " + e.errorID + "-" + e.message); - } - } - updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); - } - - function onParseEvent(event:ParseEvent):void - { - // trace(event); - if(event.type == ParseEvent.COMPLETE){ - captioningDocument = event.data as CaptioningDocument; - SMPTETTLoadTrait(loadTrait).document = captioningDocument; - updateLoadTrait(loadTrait, LoadState.READY); - } - } - } - else if (event.newState == LoadState.LOAD_ERROR) - { - // This is a terminal state, so remove the listener. But - // don't remove the error event listener, as that will be - // removed when the error event for this failure is - // dispatched. - httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); - - CONFIG::LOGGING - { - if (logger != null) - { - logger.debug("Error loading SMPTE-TT document");; - } - } - - updateLoadTrait(loadTrait, event.newState); - } - } - - function onLoadError(event:MediaErrorEvent):void - { - // Only remove this listener, as there will be a corresponding - // event for the load failure. - httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); - - loadTrait.dispatchEvent(event.clone()); - } + var helper:SMPTETTLoader_LoadTrait_Helper = SMPTETTLoader_LoadTrait_Helper.create(this,httpLoader); + helper.executeLoad(loadTrait); + } + + + + //Referenced from the LoadTrait_Helper + public function updateLoadTraitAccessor(loadTrait:LoadTrait, newState:String):void + { + updateLoadTrait(loadTrait, newState); } /** @@ -212,14 +130,29 @@ package org.osmf.smpte.tt.loader updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); } - /** - * Override to create your own parser. - */ - protected function createSMPTETTParser():ISMPTETTParser + private var _startTime:TimeCode = null; + public function get startTime():TimeCode { - return new SMPTETTParser(); + return _startTime; } - + + public function set startTime(value:TimeCode):void + { + _startTime = value; + } + + private var _endTime:TimeCode = null; + public function get endTime():TimeCode + { + return _endTime; + } + + public function set endTime(value:TimeCode):void + { + _endTime = value; + } + + private var httpLoader:HTTPLoader; CONFIG::LOGGING diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoader_LoadTrait_Helper.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoader_LoadTrait_Helper.as new file mode 100644 index 0000000..949c86e --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/loader/SMPTETTLoader_LoadTrait_Helper.as @@ -0,0 +1,196 @@ +package org.osmf.smpte.tt.loader +{ + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.URLResource; + import org.osmf.smpte.tt.architecture.creation.SMPTETTFactoryFacade; + import org.osmf.smpte.tt.captions.CaptioningDocument; + import org.osmf.smpte.tt.events.ParseEvent; + import org.osmf.smpte.tt.parsing.ISMPTETTParser; + import org.osmf.smpte.tt.parsing.SMPTETTParser; + import org.osmf.smpte.tt.timing.TimeCode; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.utils.HTTPLoadTrait; + import org.osmf.utils.HTTPLoader; + + CONFIG::LOGGING + { + import org.osmf.logging.*; + } + + /* + This whole class was represented by a single method before refactoring. + The intent is to listen for some events to some short lived variables. + Eventually, there are a couple of callbacks into the SMPTETTLoader to update the properties + + One of the callbacks was a protected final method : updateLoadTrait(), + so SMPTETTLoader had to add a public delegate method to access it: updateLoadTraitAccessor() + */ + public class SMPTETTLoader_LoadTrait_Helper + { + public static var creationType:Class = SMPTETTLoader_LoadTrait_Helper; + + //Reference via this static method, so that it can be swapped out if needed + public static function create(loader:SMPTETTLoader, p_httpLoader:HTTPLoader):SMPTETTLoader_LoadTrait_Helper + { + return new creationType(loader, p_httpLoader); + } + + private var _loader:SMPTETTLoader + private var httpLoadTrait:HTTPLoadTrait; + private var _httpLoader:HTTPLoader; + private var _loadTrait:LoadTrait + private var captioningDocument:CaptioningDocument; + + public function SMPTETTLoader_LoadTrait_Helper(loader:SMPTETTLoader, p_httpLoader:HTTPLoader) + { + _loader = loader; + _httpLoader = p_httpLoader + } + + + protected function get loadTrait():LoadTrait + { + return _loadTrait; + } + + public function executeLoad(p_loadTrait:LoadTrait):void + { + _loadTrait = p_loadTrait; + updateLoadTrait(loadTrait, LoadState.LOADING); + + httpLoader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + + // Create a temporary LoadTrait for this purpose, so that our main + // LoadTrait doesn't reflect any of the state changes from the + // loading of the URL, and so that we can catch any errors. + httpLoadTrait = new HTTPLoadTrait(httpLoader, loadTrait.resource); + + httpLoadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug("Downloading document at " + URLResource(httpLoadTrait.resource).url); + } + } + + httpLoader.load(httpLoadTrait); + + } + + protected function onHTTPLoaderStateChange(event:LoaderEvent):void + { + if (event.newState == LoadState.READY) + { + prepReadyState(); + } + else if (event.newState == LoadState.LOAD_ERROR) + { + prepLoadErrorState(event); + } + } + + private function prepReadyState():void + { + // trace(smptettLoader+" onHTTPLoaderStateChange: "+event.newState+" "+(getTimer()-loadTime)/1000+"s"); + // loadTime = getTimer(); + + // This is a terminal state, so remove all listeners. + httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + var parser:ISMPTETTParser = SMPTETTFactoryFacade.getSMPTETTParser(); + + try + { + var p:SMPTETTParser = parser as SMPTETTParser; + if (p) + { + p.startTime = startTime; + p.endTime = endTime; + p.addEventListener(ParseEvent.BEGIN, onParseEvent); + p.addEventListener(ParseEvent.PROGRESS, onParseEvent); + p.addEventListener(ParseEvent.COMPLETE, onParseEvent); + p.addEventListener(ParseEvent.PARTIAL, onParseEvent); + } + parser.parse(httpLoadTrait.urlLoader.data.toString()); + } + catch(e:Error) + { + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug("Error parsing captioning document: " + e.errorID + "-" + e.message); + } + } + updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); + } + } + + + protected function onParseEvent(event:ParseEvent):void + { + captioningDocument = event.data as CaptioningDocument; + SMPTETTLoadTrait(loadTrait).document = captioningDocument; + switch (event.type) + { + case ParseEvent.COMPLETE: + updateLoadTrait(loadTrait, LoadState.READY); + break; + } + loadTrait.dispatchEvent(event); + } + + private function prepLoadErrorState(event:LoaderEvent):void + { + // This is a terminal state, so remove the listener. But + // don't remove the error event listener, as that will be + // removed when the error event for this failure is + // dispatched. + httpLoader.removeEventListener(LoaderEvent.LOAD_STATE_CHANGE, onHTTPLoaderStateChange); + + CONFIG::LOGGING + { + if (logger != null) + { + logger.debug("Error loading SMPTE-TT document");; + } + } + + updateLoadTrait(loadTrait, event.newState); + } + + + protected function onLoadError(event:MediaErrorEvent):void + { + // Only remove this listener, as there will be a corresponding + // event for the load failure. + httpLoadTrait.removeEventListener(MediaErrorEvent.MEDIA_ERROR, onLoadError); + + loadTrait.dispatchEvent(event.clone()); + } + + private function get httpLoader(): HTTPLoader + { + return _httpLoader; + } + + private function updateLoadTrait(loadTrait:LoadTrait, newState:String):void + { + _loader.updateLoadTraitAccessor(loadTrait, newState) + } + + + private function get startTime():TimeCode {return _loader.startTime;} + private function get endTime():TimeCode {return _loader.endTime;} + + CONFIG::LOGGING + { + private static const logger:org.osmf.logging.Logger = org.osmf.logging.Log.getLogger("org.osmf.captioning.loader.SMPTETTLoader"); + } + } +} \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/logging/SMPTETTLogging.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/logging/SMPTETTLogging.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/CaptioningMediaElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/CaptioningMediaElement.as old mode 100755 new mode 100644 index 654c58a..f64646f --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/CaptioningMediaElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/CaptioningMediaElement.as @@ -1,297 +1,301 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.media -{ - import flash.display.DisplayObjectContainer; - import flash.display.Sprite; - import flash.events.Event; - import flash.sampler.NewObjectSample; - import flash.utils.Dictionary; - - import flashx.textLayout.events.DamageEvent; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.F4MElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.ProxyElement; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.layout.HorizontalAlign; - import org.osmf.layout.ILayoutTarget; - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutMode; - import org.osmf.layout.LayoutRenderer; - import org.osmf.layout.LayoutTargetSprite; - import org.osmf.layout.ScaleMode; - import org.osmf.layout.VerticalAlign; - import org.osmf.media.MediaElement; - import org.osmf.smpte.tt.captions.CaptionElement; - import org.osmf.smpte.tt.captions.CaptionRegion; - import org.osmf.traits.DisplayObjectTrait; +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.media +{ + import flash.events.Event; + import flash.utils.Dictionary; + + import org.osmf.events.DisplayObjectEvent; + import org.osmf.layout.LayoutMetadata; + import org.osmf.media.MediaElement; + import org.osmf.smpte.tt.captions.CaptionElement; + import org.osmf.smpte.tt.captions.CaptionRegion; + import org.osmf.traits.DisplayObjectTrait; import org.osmf.traits.MediaTraitType; - - public class CaptioningMediaElement extends MediaElement - { - public function CaptioningMediaElement() - { - super(); - } - - private var _showCaptions:Boolean = true; - - public function get showCaptions():Boolean + import org.osmf.traits.TimeTrait; + + public class CaptioningMediaElement extends MediaElement + { + public function CaptioningMediaElement() + { + super(); + } + + private var _showCaptions:Boolean = true; + + public function get showCaptions():Boolean { return _showCaptions; - } - - public function set showCaptions(value:Boolean):void + } + + public function set showCaptions(value:Boolean):void + { + _showCaptions = value; + + if (_rootContainer) + { + _rootContainer.visible = _showCaptions; + } + } + + public function get mediaElement():MediaElement + { + return _mediaElement; + } + + public function set mediaElement(value:MediaElement):void { - _showCaptions = value; - - if (_rootContainer) - { - _rootContainer.visible = _showCaptions; + _mediaElement = value; + + if (!_rootContainer) buildRootContainer(); + + var dot:DisplayObjectTrait = _mediaElement.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; + if (dot + && dot.mediaWidth + && dot.mediaHeight) + { + trace("setMediaElement {mediaHeight:"+ dot.mediaWidth +", mediaWidth:"+dot.mediaHeight+"}"); + + setIntrinsicDimensions(dot.mediaWidth, dot.mediaHeight); + } + } + + private function buildRootContainer(width:Number=NaN, height:Number=NaN):void + { + + _rootContainer = new RootLayoutTargetSprite(); + + _displayObjectTrait = new LayoutTargetSpriteDisplayObjectTrait(_rootContainer, width, height); + addTrait(MediaTraitType.DISPLAY_OBJECT, _displayObjectTrait); + + _rootContainer.addEventListener(Event.RESIZE, rootContainer_resizeHandler); + + // set visibility of the _rootContainer based on showCaptions + _rootContainer.visible = showCaptions; + } + + public function addRegion(value:CaptionRegion):RegionLayoutTargetSprite + { + + if (!_regionsHash) + { + _regionsHash = new Dictionary(); + } + var region:RegionLayoutTargetSprite; + if (!_regionsHash[value.id]) + { + region = new RegionLayoutTargetSprite(value); + _regionsHash[value.id] = region; + if (_rootContainer) _rootContainer.layoutRenderer.addTarget(region); + } + else + { + region = _regionsHash[value.id] + } + return region; + } + + public function getRegionById(id:String):RegionLayoutTargetSprite + { + if (!_regionsHash) return null; + return _regionsHash[id] as RegionLayoutTargetSprite; + } + + public function removeRegionById(id:String):void + { + if (_regionsHash && _regionsHash[id]) + { + var region:RegionLayoutTargetSprite = _regionsHash[id]; + if (_rootContainer) _rootContainer.layoutRenderer.removeTarget(region); + delete _regionsHash[id]; + } + } + + public function addCaption(value:CaptionElement):void + { + if (_rootContainer) + { + var timeTrait:TimeTrait; + var testTime:Number = value.begin; + if (mediaElement) + { + timeTrait = mediaElement.getTrait(MediaTraitType.TIME) as TimeTrait; + } + for each(var r:RegionLayoutTargetSprite in _regionsHash) + { + r.validateCaption(value.begin, value.end, testTime); + } + } + //trace("addCaption: "+value.id); + if (value.regionId && _regionsHash[value.regionId]) + { + _currentCaption = value; + if (_rootContainer) + { + var targetRegion:RegionLayoutTargetSprite = + RegionLayoutTargetSprite(_regionsHash[value.regionId]); + targetRegion.addCaption(value); + if (value.siblings) + { + for each(var s:CaptionElement in value.siblings){ + addCaption(s); + } + } + } } - } - - public function get mediaElement():MediaElement - { - return _mediaElement; - } - - public function set mediaElement(value:MediaElement):void - { - _mediaElement = value; - - if (!_rootContainer) buildRootContainer(); - - var dot:DisplayObjectTrait = _mediaElement.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; - if (dot - && dot.mediaWidth - && dot.mediaHeight) - { - trace("setMediaElement {mediaHeight:"+ dot.mediaWidth +", mediaWidth:"+dot.mediaHeight+"}"); - - setIntrinsicDimensions(dot.mediaWidth, dot.mediaHeight); - } - } - - private function buildRootContainer(width:Number=NaN, height:Number=NaN):void - { - - _rootContainer = new RootLayoutTargetSprite(); - - _displayObjectTrait = new LayoutTargetSpriteDisplayObjectTrait(_rootContainer, width, height); - addTrait(MediaTraitType.DISPLAY_OBJECT, _displayObjectTrait); - - _rootContainer.addEventListener(Event.RESIZE, rootContainer_resizeHandler); - } - - public function addRegion(value:CaptionRegion):RegionLayoutTargetSprite - { - - if (!_regionsHash) - { - _regionsHash = new Dictionary(); - } - var region:RegionLayoutTargetSprite - if (!_regionsHash[value.id]) - { - region = new RegionLayoutTargetSprite(value); - _regionsHash[value.id] = region; - if (_rootContainer) _rootContainer.layoutRenderer.addTarget(region); - } - return region; - } - - public function removeRegionById(id:String):void - { - if (_regionsHash && _regionsHash[id]) - { - var region:RegionLayoutTargetSprite = _regionsHash[id]; - if (_rootContainer) _rootContainer.layoutRenderer.removeTarget(region); - delete _regionsHash[id]; - } - } - - public function addCaption(value:CaptionElement):void - { - if (_rootContainer) - { - for each(var r:RegionLayoutTargetSprite in _regionsHash) - { - r.validateCaption(); - } - } - //trace("addCaption: "+value.id); - if (value.regionId && _regionsHash[value.regionId]) - { - _currentCaption = value; - if (_rootContainer) - { - var targetRegion:RegionLayoutTargetSprite = - RegionLayoutTargetSprite(_regionsHash[value.regionId]); - targetRegion.addCaption(value); - if (value.siblings) - { - for each(var s:CaptionElement in value.siblings){ - addCaption(s); - } - } - } - } - } - - public function removeCaption(value:CaptionElement=null):void - { - var r:RegionLayoutTargetSprite; - if (!value){ - for each(r in _regionsHash) - { - r.removeCaption(); - } - return; - } - if (_rootContainer) - { - for each(r in _regionsHash) - { - r.validateCaption(value.begin,value.end); - } - } - //trace("removeCaption: "+value.id); - if (value.regionId && _regionsHash[value.regionId]){ - var targetRegion:RegionLayoutTargetSprite = - RegionLayoutTargetSprite(_regionsHash[value.regionId]); - if (_rootContainer) - { - targetRegion.removeCaption(value); - if (value.siblings){ - for each(var s:CaptionElement in value.siblings){ - removeCaption(s); - } - } - } - _currentCaption = null; - } - } - - public function clear():void{ - if (_regionsHash){ - _currentCaption = null; - for(var i:String in _regionsHash){ - var r:RegionLayoutTargetSprite = _regionsHash[i] as RegionLayoutTargetSprite; - r.clear(); - if (_rootContainer) _rootContainer.layoutRenderer.removeTarget(r); - delete _regionsHash[i]; - } - } - if (_displayObjectTrait){ - removeTrait(MediaTraitType.DISPLAY_OBJECT); - } - delete this; - } - - private function redrawCaptions():void - { - if (_regionsHash) - { - for each(var r:RegionLayoutTargetSprite in _regionsHash) - { - r.redrawCaption(); - } - /* - removeCaption(); - var cme:CaptioningMediaElement = this; - _rootContainer.addEventListener(Event.ENTER_FRAME, - function(e:Event):void - { - e.target.removeEventListener(Event.ENTER_FRAME,arguments.callee); - cme.addCaption(cachedCurrentCaption); - }); - */ - } - } - - private function rootContainer_resizeHandler(event:Event):void - { - redrawCaptions(); - } - - public function validateCaptions():void - { - if (_currentCaption && _regionsHash) - { - for each(var r:RegionLayoutTargetSprite in _regionsHash){ - r.validateCaption(); - } - } - } - - public function setIntrinsicDimensions(width:Number, height:Number, fireEvent:Boolean=true):void - { - trace(this + " setIntrinsicDimensions: {width : "+width+", height : "+height+", _measuredWidth : "+_measuredWidth+", _measuredHeight : "+_measuredHeight+" }"); - - if (_measuredWidth == width && _measuredHeight == height) return; - - if (_rootContainer) - { - _displayObjectTrait.newMediaSize(width, height); - - if (_mediaElement) - { - var layoutMetadata:LayoutMetadata = _mediaElement.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; - - if (layoutMetadata) - { - _rootContainer.layoutMetadata.scaleMode = layoutMetadata.scaleMode; - _rootContainer.layoutMetadata.verticalAlign = layoutMetadata.verticalAlign; - _rootContainer.layoutMetadata.horizontalAlign = layoutMetadata.horizontalAlign; - _rootContainer.layoutMetadata.percentWidth = layoutMetadata.percentWidth; - _rootContainer.layoutMetadata.percentHeight = layoutMetadata.percentHeight; - _rootContainer.layoutMetadata.index = 1; - - layoutMetadata.index = 0; - _mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); - } - - redrawCaptions(); - } - _displayObjectTrait.dispatchEvent - ( new DisplayObjectEvent - ( DisplayObjectEvent.MEDIA_SIZE_CHANGE, false, false - , null, null - , _measuredWidth - , _measuredHeight - , _measuredWidth = width - , _measuredHeight = height - ) - ); - } - } - - private var _mediaElement:MediaElement; - private var _regionsHash:Dictionary; - private var _rootContainer:RootLayoutTargetSprite; - private var _displayObjectTrait:LayoutTargetSpriteDisplayObjectTrait; - private var _currentCaption:CaptionElement; - private var _measuredWidth:Number = NaN; - private var _measuredHeight:Number = NaN; - } + } + + public function removeCaption(value:CaptionElement=null):void + { + var r:RegionLayoutTargetSprite; + if (!value){ + for each(r in _regionsHash) + { + r.removeCaption(); + } + return; + } + if (_rootContainer) + { + for each(r in _regionsHash) + { + r.validateCaption(); + } + } + //trace("removeCaption: "+value.id); + if (value.regionId && _regionsHash[value.regionId]){ + var targetRegion:RegionLayoutTargetSprite = + RegionLayoutTargetSprite(_regionsHash[value.regionId]); + if (_rootContainer) + { + targetRegion.removeCaption(value); + if (value.siblings){ + for each(var s:CaptionElement in value.siblings){ + removeCaption(s); + } + } + } + _currentCaption = null; + } + } + + public function clear():void{ + if (_regionsHash){ + _currentCaption = null; + for(var i:String in _regionsHash){ + var r:RegionLayoutTargetSprite = _regionsHash[i] as RegionLayoutTargetSprite; + r.clear(); + if (_rootContainer) _rootContainer.layoutRenderer.removeTarget(r); + delete _regionsHash[i]; + } + } + if (_displayObjectTrait){ + removeTrait(MediaTraitType.DISPLAY_OBJECT); + } + delete this; + } + + private function redrawCaptions():void + { + if (_regionsHash) + { + for each(var r:RegionLayoutTargetSprite in _regionsHash) + { + r.redrawCaption(); + } + /* + removeCaption(); + var cme:CaptioningMediaElement = this; + _rootContainer.addEventListener(Event.ENTER_FRAME, + function(e:Event):void + { + e.target.removeEventListener(Event.ENTER_FRAME,arguments.callee); + cme.addCaption(cachedCurrentCaption); + }); + */ + } + } + + private function rootContainer_resizeHandler(event:Event):void + { + redrawCaptions(); + } + + public function validateCaptions():void + { + if (_regionsHash) + { + for each(var r:RegionLayoutTargetSprite in _regionsHash){ + r.validateCaption(); + } + } + } + + public function setIntrinsicDimensions(width:Number, height:Number, fireEvent:Boolean=true):void + { + trace(this + " setIntrinsicDimensions: {width : "+width+", height : "+height+", _measuredWidth : "+_measuredWidth+", _measuredHeight : "+_measuredHeight+" }"); + + if (_measuredWidth == width && _measuredHeight == height) return; + + if (_rootContainer) + { + _displayObjectTrait.newMediaSize(width, height); + + if (_mediaElement) + { + var layoutMetadata:LayoutMetadata = _mediaElement.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata; + + if (layoutMetadata) + { + _rootContainer.layoutMetadata.scaleMode = layoutMetadata.scaleMode; + _rootContainer.layoutMetadata.verticalAlign = layoutMetadata.verticalAlign; + _rootContainer.layoutMetadata.horizontalAlign = layoutMetadata.horizontalAlign; + _rootContainer.layoutMetadata.percentWidth = layoutMetadata.percentWidth; + _rootContainer.layoutMetadata.percentHeight = layoutMetadata.percentHeight; + _rootContainer.layoutMetadata.index = 1; + + layoutMetadata.index = 0; + _mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata); + } + + redrawCaptions(); + } + _displayObjectTrait.dispatchEvent + ( new DisplayObjectEvent + ( DisplayObjectEvent.MEDIA_SIZE_CHANGE, false, false + , null, null + , _measuredWidth + , _measuredHeight + , _measuredWidth = width + , _measuredHeight = height + ) + ); + } + } + + private var _mediaElement:MediaElement; + private var _regionsHash:Dictionary; + private var _rootContainer:RootLayoutTargetSprite; + private var _displayObjectTrait:LayoutTargetSpriteDisplayObjectTrait; + private var _currentCaption:CaptionElement; + private var _measuredWidth:Number = NaN; + private var _measuredHeight:Number = NaN; + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/LayoutTargetSpriteDisplayObjectTrait.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/LayoutTargetSpriteDisplayObjectTrait.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/RegionLayoutTargetSprite.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/RegionLayoutTargetSprite.as old mode 100755 new mode 100644 index 86aea41..0be296f --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/RegionLayoutTargetSprite.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/RegionLayoutTargetSprite.as @@ -1,838 +1,1023 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.media -{ - import flash.display.BlendMode; - import flash.display.Sprite; - import flash.filters.GlowFilter; - import flash.geom.Rectangle; - import flash.text.engine.TextLine; - import flash.utils.Dictionary; - - import flashx.textLayout.compose.TextFlowLine; - import flashx.textLayout.container.ContainerController; - import flashx.textLayout.container.TextContainerManager; - import flashx.textLayout.conversion.ITextImporter; - import flashx.textLayout.conversion.TextConverter; - import flashx.textLayout.elements.BreakElement; - import flashx.textLayout.elements.DivElement; - import flashx.textLayout.elements.FlowElement; - import flashx.textLayout.elements.FlowGroupElement; - import flashx.textLayout.elements.ParagraphElement; - import flashx.textLayout.elements.ParagraphFormattedElement; - import flashx.textLayout.elements.SpanElement; - import flashx.textLayout.elements.SubParagraphGroupElement; - import flashx.textLayout.elements.TextFlow; - import flashx.textLayout.formats.LineBreak; - - import org.osmf.layout.LayoutMetadata; - import org.osmf.layout.LayoutRendererBase; - import org.osmf.layout.ScaleMode; - import org.osmf.smpte.tt.captions.CaptionElement; - import org.osmf.smpte.tt.captions.CaptionRegion; - import org.osmf.smpte.tt.captions.ShowBackground; - import org.osmf.smpte.tt.captions.TimedTextElement; - import org.osmf.smpte.tt.captions.TimedTextElementType; - import org.osmf.smpte.tt.captions.TimedTextStyle; - import org.osmf.smpte.tt.enums.Unit; - import org.osmf.smpte.tt.primitives.Size; - import org.osmf.smpte.tt.styling.AutoExtent; - import org.osmf.smpte.tt.styling.AutoOrigin; - import org.osmf.smpte.tt.styling.Extent; - import org.osmf.smpte.tt.styling.FontSize; - import org.osmf.smpte.tt.styling.LineHeight; - import org.osmf.smpte.tt.styling.NumberPair; - import org.osmf.smpte.tt.styling.Origin; - import org.osmf.smpte.tt.styling.PaddingThickness; - import org.osmf.smpte.tt.styling.TextOutline; - import org.osmf.smpte.tt.styling.WrapOption; - import org.osmf.smpte.tt.utilities.DictionaryUtils; - import org.osmf.smpte.tt.utilities.VectorUtils; - import org.osmf.traits.MediaTraitType; +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.media +{ + import flash.display.BlendMode; + import flash.display.Sprite; + import flash.filters.GlowFilter; + import flash.geom.Rectangle; + import flash.text.engine.TextLine; + import flash.utils.Dictionary; + + import flashx.textLayout.compose.TextFlowLine; + import flashx.textLayout.container.ContainerController; + import flashx.textLayout.conversion.ConversionType; + import flashx.textLayout.conversion.TextConverter; + import flashx.textLayout.elements.BreakElement; + import flashx.textLayout.elements.DivElement; + import flashx.textLayout.elements.FlowElement; + import flashx.textLayout.elements.FlowGroupElement; + import flashx.textLayout.elements.ParagraphElement; + import flashx.textLayout.elements.ParagraphFormattedElement; + import flashx.textLayout.elements.SpanElement; + import flashx.textLayout.elements.SubParagraphGroupElement; + import flashx.textLayout.elements.TextFlow; + import flashx.textLayout.formats.Direction; + import flashx.textLayout.formats.LineBreak; + import flashx.textLayout.formats.TextDecoration; + + import org.osmf.layout.LayoutMetadata; + import org.osmf.layout.LayoutRendererBase; + import org.osmf.layout.ScaleMode; + import org.osmf.smpte.tt.captions.CaptionElement; + import org.osmf.smpte.tt.captions.CaptionRegion; + import org.osmf.smpte.tt.captions.ShowBackground; + import org.osmf.smpte.tt.captions.TimedTextElement; + import org.osmf.smpte.tt.captions.TimedTextElementType; + import org.osmf.smpte.tt.captions.TimedTextStyle; + import org.osmf.smpte.tt.enums.Unit; + import org.osmf.smpte.tt.model.TimedTextElementBase; + import org.osmf.smpte.tt.primitives.Size; + import org.osmf.smpte.tt.styling.AutoExtent; + import org.osmf.smpte.tt.styling.AutoOrigin; + import org.osmf.smpte.tt.styling.Extent; + import org.osmf.smpte.tt.styling.FontSize; + import org.osmf.smpte.tt.styling.LineHeight; + import org.osmf.smpte.tt.styling.NumberPair; + import org.osmf.smpte.tt.styling.Origin; + import org.osmf.smpte.tt.styling.PaddingThickness; + import org.osmf.smpte.tt.styling.TextDecorationAttributeValue; + import org.osmf.smpte.tt.styling.TextOutline; + import org.osmf.smpte.tt.styling.Visibility; + import org.osmf.smpte.tt.styling.WrapOption; + import org.osmf.smpte.tt.utilities.VectorUtils; + import org.osmf.traits.MediaTraitType; import org.osmf.traits.TimeTrait; - - public class RegionLayoutTargetSprite extends RootLayoutTargetSprite - { - - public function RegionLayoutTargetSprite(captionRegion:CaptionRegion, layoutRenderer:LayoutRendererBase=null, layoutMetadata:LayoutMetadata=null) - { - super(layoutRenderer, layoutMetadata); - - this.captionRegion = captionRegion; - - this.layoutMetadata.scaleMode = ScaleMode.NONE; - this.layoutMetadata.snapToPixel = true; - this.layoutMetadata.width = width; - this.layoutMetadata.height = height; - - _textFlowContainer = new Sprite(); - addChild(_textFlowContainer); - - _textFlow = new TextFlow(); - - _containerController = new ContainerController(_textFlowContainer, width, height); - _textFlow.flowComposer.addController(_containerController); - } - - public function get id():String - { - return _id; - } - - public function set id(value:String):void - { - _id = value; - } - - public function get captionRegion():CaptionRegion - { - return _captionRegion; - } - - public function set captionRegion(value:CaptionRegion):void - { - if(_captionRegion != value){ - _captionRegion = value; - _id = _captionRegion.id; - } - } - - public function addCaption(value:CaptionElement):void - { - _currentCaption = value; - if(hasRendererContext()) - { - buildTextFlow(_currentCaption); - } - - //trace("\n*******\nADD CAPTION:\n\t "+_textFlow.getText()+"\n\t from "+this.id+"\n*******\n"); - } - - public function redrawCaption():void - { - if (_textFlow.numChildren>0 && _textFlow.getText().length) - { - _textFlow.replaceChildren(0,_textFlow.numChildren); - } - - if (hasRendererContext()) - { - if (_currentCaption) - { - buildTextFlow(_currentCaption); - } else - { - applyRegionStyles(); - autoSizeContainerController(); - } - } - } - - private function hasRendererContext():Boolean - { - return (layoutRenderer - && layoutRenderer.parent - && layoutRenderer.parent.container - && layoutRenderer.parent.container.measuredWidth - && layoutRenderer.parent.container.measuredHeight); - } - - public function removeCaption(value:CaptionElement=null):void - { - // trace("\n*******\nREMOVE CAPTION:\n\t "+_textFlow.getText()+"\n\t from "+this.id+"\n*******\n"); - if (_textFlow.numChildren>0) - { - _textFlow.replaceChildren(0,_textFlow.numChildren); - } - autoSizeContainerController(); - _currentCaption = null; - } - - public function validateCaption(begin:Number=NaN, end:Number=NaN):void - { - if (_currentCaption) - { - var timeTrait:TimeTrait; - - if (mediaElement) - timeTrait = mediaElement.getTrait(MediaTraitType.TIME) as TimeTrait; - - if (isNaN(begin)) - begin = (timeTrait) ? timeTrait.currentTime : _currentCaption.begin; - - if (isNaN(end)) - end = _currentCaption.end; - - if (!_currentCaption.isActiveInRange(begin, end)) - { - removeCaption(_currentCaption); - } - else if (timeTrait) - { - if (!_currentCaption.isActiveAtPosition(timeTrait.currentTime, true)) - removeCaption(_currentCaption); - else - redrawAtPosition(_currentCaption, timeTrait.currentTime); - } - } - } - - private function redrawAtPosition(captionElement:CaptionElement, currentTime:Number):Boolean - { - if (!captionElement.isActiveAtPosition(currentTime)) - { - redrawCaption(); - return true; - } - - for each(var c:CaptionElement in captionElement.children) - { - if (!c.isActiveAtPosition(currentTime)) - { - redrawCaption(); - return true; - } else if (redrawAtPosition(c, currentTime)) - { - return true; - } - } - return false; - } - - private function getFlowElement(captionElement:CaptionElement):FlowElement - { - if (captionElement.style.display == "none") - return null; - - //trace(captionElement+" "+captionElement.captionElementType +" "+captionElement.content); - - var flowElement:FlowElement; - - if(captionElement.captionElementType == TimedTextElementType.Text) - { - var span:SpanElement = new SpanElement(); - span.text = captionElement.content; - - applyStyles(span, captionElement.style, captionElement); - - flowElement = span as FlowElement; - } - else if (captionElement.captionElementType == TimedTextElementType.LineBreak) - { - var br:BreakElement = new BreakElement(); - - applyStyles(br, captionElement.style, captionElement); - - flowElement = br; - } else if (captionElement.captionElementType == TimedTextElementType.Container - || captionElement.captionElementType == TimedTextElementType.SupParagraphGroupElement) - { - - var children:Vector. = captionElement.children; - var div:DivElement; - var paragraph:ParagraphElement; - var subParagraphGroupElement:SubParagraphGroupElement; - if (captionElement.captionElementType == TimedTextElementType.SupParagraphGroupElement) - { - subParagraphGroupElement = new SubParagraphGroupElement(); - - flowElement = subParagraphGroupElement as FlowElement; - } else if (children - && children.length>0 - && children[0].captionElementType==TimedTextElementType.Container) - { - div = new DivElement(); - - flowElement = div as FlowElement; - } else - { - paragraph = new ParagraphElement(); - - flowElement = paragraph as FlowElement; - } - - if (flowElement) { - applyStyles(flowElement, captionElement.style, captionElement); - } - - var timeTrait:TimeTrait; - if (mediaElement) - timeTrait = mediaElement.getTrait(MediaTraitType.TIME) as TimeTrait; - - if(timeTrait) - { - var currentTime:Number = timeTrait.currentTime; - - for each(var c:CaptionElement in children) - { - if (timeTrait - && c.isActiveAtPosition(currentTime, true) - && c.isActiveInRange(currentTime,captionElement.end) - && c.style.display != "none") - { - /* - trace("YES: "+c.captionElementType - +"\t"+ currentTime - +"\t("+c.begin+", "+c.end+")" - +"\t"+c.content+"\n"); - */ - var childElement:FlowElement = getFlowElement(c); - if(childElement) - FlowGroupElement(flowElement).addChild(childElement); - } - /*else - { - trace("NO: "+c.captionElementType - +"\t"+ currentTime - +"\t("+c.begin+", "+c.end+")" - +"\t"+c.content); - }*/ - } - } - } - - // trace(captionElement.captionElementType + " " + flowElement + " "+(flowElement as FlowElement).getText()); - return flowElement as FlowElement; - } - - private function updateContext():void { - _size = new Size(layoutRenderer.parent.container.measuredWidth, layoutRenderer.parent.container.measuredHeight); - _cellSize = new Size(toTextSafeArea(_size.width)/NumberPair.cellColumns, toTextSafeArea(_size.height)/NumberPair.cellRows); - } - - private function get size():Size { - updateContext(); - return _size; - } - - private function get cellSize():Size { - updateContext(); - return _cellSize; - } - - - private function toTextSafeArea(value:Number):Number - { - return value*TEXT_SAFE_AREA_RATIO; - } - - public function get showBackground():String - { - return _showBackground; - } - - public function set showBackground(value:String):void - { - _showBackground = value; - } - - private function applyRegionStyles():void - { - //trace("\n*************\n"+this.id+".applyRegionStyles()"); - var styles:Object = captionRegion.style.styles; - var cellWidth:Number, cellHeight:Number, - safeAreaWidth:Number, safeAreaHeight:Number; - - layoutMetadata.left = NaN; - layoutMetadata.right = NaN; - layoutMetadata.bottom = NaN; - - if(styles.origin){ - - //trace("is AutoOrigin? "+ (styles.origin is AutoOrigin)); - if (styles.origin as AutoOrigin == null) - { - - styles.origin.setContext(size.width,size.height); - styles.origin.setFontContext(cellSize.width,cellSize.height); - - if(styles.origin.x>0) - { - layoutMetadata.x = styles.origin.x; - layoutMetadata.right = 0; - } - if(styles.origin.y>0) - { - layoutMetadata.y = styles.origin.y; - layoutMetadata.bottom = 0; - } - - } else - { - layoutMetadata.x = 0; - layoutMetadata.y = 0; - } - - //trace("\tlayoutMetadata {x:"+layoutMetadata.x +", y:"+layoutMetadata.y+"}"); - } - - if(styles.extent){ - //trace("{width:"+size.width+", height:"+size.height+"}") - - //trace("is AutoExtent? "+ (styles.extent is AutoExtent)); - if (styles.extent as AutoExtent == null) - { - - styles.extent.setContext(size.width,size.height); - styles.extent.setFontContext(cellSize.width,cellSize.height); - - layoutMetadata.width = (styles.extent.width>0) ? Math.min(styles.extent.width, size.width-layoutMetadata.x) : NaN; - layoutMetadata.height = (styles.extent.height>0) ? Math.min(styles.extent.height, size.height-layoutMetadata.y) : NaN; - - } else - { - layoutMetadata.width = size.width-layoutMetadata.x; - layoutMetadata.height = size.height-layoutMetadata.y; - } - //trace("\tlayoutMetadata {width:"+layoutMetadata.width +", height:"+layoutMetadata.height+"}"); - } - - for(var key:String in styles){ - switch(key){ - case "showBackground": - case "backgroundColor": - case "backgroundAlpha": - { - this[key] = styles[key]; - break; - } - case "wrapOption": - { - _containerController.lineBreak = (styles.wrapOption == WrapOption.NOWRAP.value) ? LineBreak.EXPLICIT : LineBreak.TO_FIT; - break; - } - case "ttFontSize": - { - var ttFontSize:FontSize = styles[key] as FontSize; - if(ttFontSize){ - safeAreaWidth = (ttFontSize.unitMeasureHorizontal==Unit.CELL) ? toTextSafeArea(size.width) : size.width; - safeAreaHeight = (ttFontSize.unitMeasureVertical==Unit.CELL) ? toTextSafeArea(size.height) : size.height; - ttFontSize.setContext(safeAreaWidth, safeAreaHeight); - - cellWidth = (ttFontSize.unitMeasureHorizontal==Unit.PERCENT) ? cellSize.width*(NumberPair.cellColumns-2) : cellSize.width; - cellHeight = (ttFontSize.unitMeasureVertical==Unit.PERCENT) ? cellSize.height*(NumberPair.cellRows-2) : cellSize.height; - ttFontSize.setFontContext(cellWidth, cellHeight); - - _containerController.fontSize = ttFontSize.fontHeight; - //trace(_containerController+" setContext("+safeAreaWidth+","+safeAreaHeight+")"); - //trace(_containerController+" setFontContext("+cellWidth+","+cellHeight+")"); - } else { - _containerController.fontSize = 16; - } - //trace(_containerController+" fontSize="+_containerController.fontSize); - break; - } - case "ttLineHeight": - { - var ttLineHeight:LineHeight = styles[key] as LineHeight; - if(ttLineHeight){ - safeAreaWidth = (ttLineHeight.unitMeasureHorizontal==Unit.CELL) ? toTextSafeArea(size.width) : size.width; - safeAreaHeight = (ttLineHeight.unitMeasureVertical==Unit.CELL) ? toTextSafeArea(size.height) : size.height; - ttLineHeight.setContext(safeAreaWidth, safeAreaHeight); - - cellWidth = (ttLineHeight.unitMeasureHorizontal==Unit.PERCENT) ? cellSize.width*(NumberPair.cellColumns-2) : cellSize.width; - cellHeight = (ttLineHeight.unitMeasureVertical==Unit.PERCENT) ? cellSize.height*(NumberPair.cellRows-2) : cellSize.height; - ttLineHeight.setFontContext(cellWidth, cellHeight); - _containerController.lineHeight = ttLineHeight.height; - } - //trace("lineHeight: " + _containerController.lineHeight); - break; - } - case "padding": - { - var padding:PaddingThickness = styles[key] as PaddingThickness; - if (padding) - { - padding.setContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); - padding.setFontContext(cellSize.width, cellSize.height); - _containerController.paddingTop = (padding.widthBefore>0) ? padding.widthBefore : 0; - _containerController.paddingRight = (padding.widthEnd>0) ? padding.widthEnd : 0; - _containerController.paddingBottom = (padding.widthAfter>0) ? padding.widthAfter : 0; - _containerController.paddingLeft = (padding.widthStart>0) ? padding.widthStart : 0; - } - break; - } - case "opacity": - { - if (!isNaN(styles[key])) - { - blendMode = BlendMode.LAYER; - alpha = styles[key]; - } - } - default: - { - if(_containerController.hasOwnProperty(key) && styles[key]!=null){ - _containerController.setStyle(key,styles[key]); - } else { - //trace(this+" "+key+"="+styles[key]); - } - break; - } - } - } - //trace("*************\n"); - } - - - - private function applyStyles(flowElement:FlowElement, style:TimedTextStyle, captionElement:CaptionElement):void { - - //trace("\n*************\n"+flowElement+".applyStyles()"); - - updateContext(); - - var styles:Object = style.styles; - var cellWidth:Number, cellHeight:Number, - safeAreaWidth:Number, safeAreaHeight:Number; - - for(var key:String in styles){ - switch(key) - { - case "backgroundColor" : - case "backgroundAlpha" : - { - if(flowElement is ParagraphFormattedElement){ - this[key] = styles[key]; - } else { - flowElement[key] = styles[key]; - } - break; - } - case "showBackground" : - { - this[key] = styles[key]; - break; - } - case "wrapOption" : - { - flowElement.lineBreak = (style.wrapOption == WrapOption.NOWRAP.value) ? LineBreak.EXPLICIT : LineBreak.TO_FIT; - _textFlow.lineBreak = flowElement.lineBreak; - //trace("\n"+captionElement.captionElementType+" "+key+"="+styles[key] + " : "+flowElement.lineBreak+"\n"); - break; - } - case "ttFontSize" : - { - var ttFontSize:FontSize = styles[key] as FontSize; - if(ttFontSize){ - safeAreaWidth = (ttFontSize.unitMeasureHorizontal==Unit.CELL) ? toTextSafeArea(size.width) : size.width; - safeAreaHeight = (ttFontSize.unitMeasureVertical==Unit.CELL) ? toTextSafeArea(size.height) : size.height; - ttFontSize.setContext(safeAreaWidth, safeAreaHeight); - - cellWidth = (ttFontSize.unitMeasureHorizontal==Unit.PERCENT) ? cellSize.width*(NumberPair.cellColumns-2) : cellSize.width; - cellHeight = (ttFontSize.unitMeasureVertical==Unit.PERCENT) ? cellSize.height*(NumberPair.cellRows-2) : cellSize.height; - ttFontSize.setFontContext(cellWidth, cellHeight); - flowElement.fontSize = ttFontSize.fontHeight; - //trace(flowElement+" setContext("+safeAreaWidth+","+safeAreaHeight+")"); - //trace(flowElement+" setFontContext("+cellWidth+","+cellHeight+")"); - - } else { - flowElement.fontSize = 16; - } - //trace(flowElement+" fontSize="+flowElement.fontSize); - break; - } - case "ttLineHeight" : - { - var ttLineHeight:LineHeight = styles[key] as LineHeight; - if(ttLineHeight){ - safeAreaWidth = (ttLineHeight.unitMeasureHorizontal==Unit.CELL) ? toTextSafeArea(size.width) : size.width; - safeAreaHeight = (ttLineHeight.unitMeasureVertical==Unit.CELL) ? toTextSafeArea(size.height) : size.height; - ttLineHeight.setContext(safeAreaWidth, safeAreaHeight); - - cellWidth = (ttLineHeight.unitMeasureHorizontal==Unit.PERCENT) ? cellSize.width*(NumberPair.cellColumns-2) : cellSize.width; - cellHeight = (ttLineHeight.unitMeasureVertical==Unit.PERCENT) ? cellSize.height*(NumberPair.cellRows-2) : cellSize.height; - ttLineHeight.setFontContext(cellWidth, cellHeight); - - flowElement.lineHeight = ttLineHeight.height; - } - //trace(flowElement+" lineHeight=" + flowElement.lineHeight); - break; - } - case "padding" : - { - var padding:PaddingThickness = styles[key] as PaddingThickness; - if(padding){ - padding.setContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); - - if(padding.widthBeforeUnit == Unit.PERCENT){ - padding.setFontContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); - } else { - padding.setFontContext(cellSize.width, cellSize.height); - } - flowElement.paddingTop = (padding.widthBefore>0) ? padding.widthBefore : 0; - - if(padding.widthEndUnit == Unit.PERCENT){ - padding.setFontContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); - } else { - padding.setFontContext(cellSize.width, cellSize.height); - } - flowElement.paddingRight = (padding.widthEnd>0) ? padding.widthEnd : 0; - - if(padding.widthAfterUnit == Unit.PERCENT){ - padding.setFontContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); - } else { - padding.setFontContext(cellSize.width, cellSize.height); - } - flowElement.paddingBottom = (padding.widthAfter>0) ? padding.widthAfter : 0; - - if(padding.widthStartUnit == Unit.PERCENT){ - padding.setFontContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); - } else { - padding.setFontContext(cellSize.width, cellSize.height); - } - flowElement.paddingLeft = (padding.widthStart>0) ? padding.widthStart : 0; - - //trace("padding: "+flowElement.paddingTop+" "+flowElement.paddingRight+" "+flowElement.paddingBottom+" "+flowElement.paddingLeft); - } - break; - } - case "textOutline" : - { - - - var textOutline:TextOutline = styles[key] as TextOutline; - if (textOutline) - { - - textOutline.setContext(this.layoutRenderer.parent.container.measuredWidth, - this.layoutRenderer.parent.container.measuredHeight); - textOutline.setFontContext(cellSize.width, cellSize.height); - - if(!textOutline.colorDefined - && textOutline.width - && styles.color) - { - textOutline.color = styles.color; - for each(var filter:GlowFilter in textOutline.filters) - { - filter.color = styles.color; - } - } - /* - trace(captionElement+" "+key+"="+styles[key]); - trace("\twidth: "+textOutline.width); - trace("\tcolorDefined: "+textOutline.colorDefined); - trace("\tcolor: "+textOutline.color); - trace("\talpha: "+textOutline.alpha); - trace("\tblur: "+textOutline.blur); - trace("\tfilters: "+textOutline.filters); - */ - if (!_textOutlineFiltersDict) - { - _textOutlineFiltersDict = new Dictionary(); - _textOutlineFiltersHash = new Vector.(); - } - - _textOutlineFiltersDict[flowElement] = textOutline.filters; - _textOutlineFiltersHash.push(flowElement); - } - break; - } - default : - { - if(flowElement.hasOwnProperty(key) && styles[key]!=null){ - // trace(flowElement+"\t"+key+"\t"+styles[key]); - flowElement.setStyle(key,styles[key]); - } else { - //trace(captionElement+" "+key+"="+styles[key]); - } - break; - } - } - } - //trace("*************\n"); - } - - private function buildTextFlow(captionElement:CaptionElement):void - { - updateContext(); - - _textOutlineFiltersDict = null; - _textOutlineFiltersHash = null; - - applyRegionStyles(); - - var styles:Object = captionElement.style.styles; - var origin:Origin, - extent:Extent, - opacity:Number, - ttFontSize:FontSize, - ttLineHeight:LineHeight; - - if(styles.origin){ - origin = styles.origin as Origin; - - origin.setContext(size.width,size.height); - origin.setFontContext(cellSize.width,cellSize.height); - - if(origin.x>0) - { - layoutMetadata.x = origin.x; - layoutMetadata.right = 0; - } - if(origin.y>0) - { - layoutMetadata.y = origin.y; - layoutMetadata.bottom = 0; - } - //trace("layoutMetadata {x:"+layoutMetadata.x +", y:"+layoutMetadata.y+"}"); - } - - if(styles.extent){ - extent = styles.extent as Extent; - extent.setContext(size.width,size.height); - extent.setFontContext(cellSize.width,cellSize.height); - if(extent.width>0) - { - layoutMetadata.width = extent.width; - } - if(extent.height>0) - { - layoutMetadata.height = extent.height; - } - //trace("\n\nlayoutMetadata {width:"+layoutMetadata.width +", height:"+layoutMetadata.height+"}\n\n"); - } - - validateNow(); - - if(_textFlow.numChildren>0) - _textFlow.replaceChildren(0,_textFlow.numChildren); - - var flowElement:FlowElement = getFlowElement(captionElement); - - if (flowElement) - _textFlow.addChild(flowElement); - - autoSizeContainerController(); - } - - private function applyTextOutlines():void - { - - if (_textOutlineFiltersDict) - { - var len:Number = _textOutlineFiltersHash.length; - for (var i:uint; i = _textOutlineFiltersDict[flow] as Vector.; - var filters:Array = VectorUtils.toArray(toFilters); - - if (filters) - { - var pos:uint = FlowElement(flow).getAbsoluteStart(); - var endPos:uint = pos + FlowElement(flow).textLength; - while (pos < endPos) - { - var line:TextFlowLine = _textFlow.flowComposer.findLineAtPosition(pos); - if (line) - { - var textLine:TextLine = line.getTextLine(true); - if(textLine) - { - textLine.filters = filters; - } - pos += line.textLength; - } - } - } - } - _textOutlineFiltersDict = null; - _textOutlineFiltersHash = null; - } - } - - public function clear():void - { - if (_textFlow.numChildren>0) - { - _textFlow.replaceChildren(0,_textFlow.numChildren); - autoSizeContainerController(); - } - } - - private function autoSizeContainerController():void - { - - _textFlow.flowComposer.composeToPosition(); - var contentBounds:Rectangle = _containerController.getContentBounds(); - - _containerController.setCompositionSize(Math.min(_containerController.compositionWidth, layoutMetadata.x-size.width), contentBounds.height); - _textFlow.flowComposer.updateAllControllers(); - - layoutMetadata.height = contentBounds.height; - - measure(); - validateNow(); - } - - // Overrides - // - override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void - { - if(lastAvailableWidth==availableWidth && lastAvailableHeight==availableHeight) return; - - // trace(">>>>>>>>>"+this+" "+this.id+".layout("+availableWidth+","+availableHeight+","+deep+")"); - if (_containerController) - { - _containerController.setCompositionSize(availableWidth, availableHeight); - _textFlow.flowComposer.updateAllControllers(); - - applyTextOutlines(); - } - - super.layout(availableWidth, availableHeight, deep); - } - - override public function set width(value:Number):void - { - if (_containerController) - { - _containerController.setCompositionSize(value, _containerController.compositionHeight); - _textFlow.flowComposer.updateAllControllers(); - } - super.width = value; - } - - override public function set height(value:Number):void - { - if (_containerController) - { - _containerController.setCompositionSize(_containerController.compositionWidth, value); - _textFlow.flowComposer.updateAllControllers(); - } - super.height = value; - } - - private var _id:String = ""; - private var _captionRegion:CaptionRegion; - private var _textFlow:TextFlow; - private var _textFlowContainer:Sprite; - private var _containerController:ContainerController; - private var _currentCaption:CaptionElement; - private var _size:Size; - private var _cellSize:Size; - private var _showBackground:String = ShowBackground.Always.value; - private var _textOutlineFiltersDict:Dictionary; - private var _textOutlineFiltersHash:Vector.; - private static const TEXT_SAFE_AREA_RATIO:Number = 0.8; - } + + public class RegionLayoutTargetSprite extends RootLayoutTargetSprite + { + + public function RegionLayoutTargetSprite(captionRegion:CaptionRegion, layoutRenderer:LayoutRendererBase=null, layoutMetadata:LayoutMetadata=null) + { + super(layoutRenderer, layoutMetadata); + + this.captionRegion = captionRegion; + + this.layoutMetadata.scaleMode = ScaleMode.NONE; + this.layoutMetadata.snapToPixel = true; + this.layoutMetadata.width = width; + this.layoutMetadata.height = height; + + _textFlowContainer = new Sprite(); + addChild(_textFlowContainer); + + _textFlow = new TextFlow(); + + _containerController = new ContainerController(_textFlowContainer, width, height); + _textFlow.flowComposer.addController(_containerController); + } + + public function get id():String + { + return _id; + } + + public function set id(value:String):void + { + _id = value; + } + + public function get captionRegion():CaptionRegion + { + return _captionRegion; + } + + public function set captionRegion(value:CaptionRegion):void + { + if(_captionRegion != value){ + _captionRegion = value; + _id = _captionRegion.id; + } + } + + public function addCaption(value:CaptionElement):void + { + _currentCaption = value; + if(hasRendererContext()) + { + buildTextFlow(_currentCaption); + } + + //trace("\n*******\nADD CAPTION:\n\t "+_textFlow.getText()+"\n\t from "+this.id+"\n*******\n"); + } + + public function redrawCaption():void + { + if (_textFlow.numChildren>0 && _textFlow.getText().length) + _textFlow.replaceChildren(0,_textFlow.numChildren); + + + if (hasRendererContext()) + { + if (_currentCaption) + { + buildTextFlow(_currentCaption); + } else + { + applyRegionStyles(); + autoSizeContainerController(); + } + } + } + + private function hasRendererContext():Boolean + { + return (layoutRenderer + && layoutRenderer.parent + && layoutRenderer.parent.measuredWidth + && layoutRenderer.parent.measuredHeight); + } + + public function removeCaption(value:CaptionElement=null):void + { + // trace("\n*******\nREMOVE CAPTION:\n\t "+_textFlow.getText()+"\n\t from "+this.id+"\n*******\n"); + if (_textFlow.numChildren>0) + { + _textFlow.replaceChildren(0,_textFlow.numChildren); + } + autoSizeContainerController(); + _currentCaption = null; + } + + public function validateCaption(begin:Number=NaN, end:Number=NaN, currentTime:Number=NaN):void + { + if (_currentCaption) + { + var round:Boolean = false; + + if (isNaN(currentTime) && timeTrait) + { + // if no currentTime is specified and a TimeTrait exist, + // use the currentTime of the mediaElement's TimeTrait for comparison, + // but round to adjust for time interval imprecision. + currentTime = timeTrait.currentTime; + } + + if (isNaN(begin)) + { + // If an expilict begin time is not specified, + // use either the currentTime if a TimeTrait is present, + // or the begin time of the currentCaption for this region. + if (timeTrait) + { + begin = currentTime; + round = true; + } else + { + begin = _currentCaption.begin; + round = false; + } + } + + if (isNaN(end)) + end = _currentCaption.end; + + if (timeTrait) + { + if (!_currentCaption.isActiveAtPosition(currentTime, round)) + { + removeCaption(_currentCaption); + } else + { + redrawAtPosition(_currentCaption, currentTime); + } + } else if (!_currentCaption.isActiveInRange(begin, end)) + { + removeCaption(_currentCaption); + } + + } + } + + private function redrawAtPosition(captionElement:CaptionElement, currentTime:Number):Boolean + { + if (captionElement.hasAnimations + || captionRegion.hasAnimations + || !captionElement.isActiveAtPosition(currentTime, true)) + { + //trace(_id+" redrawAtPosition("+captionElement+", "+currentTime+") hasAnimations="+captionElement.hasAnimations); + redrawCaption(); + return true; + } + + for each(var c:CaptionElement in captionElement.children) + { + if (c.hasAnimations || !c.isActiveAtPosition(currentTime, true)) + { + redrawCaption(); + return true; + } else if (redrawAtPosition(c, currentTime)) + { + return true; + } + } + return false; + } + + private function getFlowElement(captionElement:CaptionElement):FlowElement + { + //("\t>>>START getFlowElement "+captionElement.captionElementType+"<<<"); + + if (timeTrait) + captionElement.calculateCurrentStyle(timeTrait.currentTime); + + if (captionElement.currentStyle.display == "none") + return null; + + //(captionElement+" "+captionElement.captionElementType +" "+captionElement.content); + + var flowElement:FlowElement; + var parentElement:TimedTextElement = captionElement.parentElement; + + if(captionElement.captionElementType == TimedTextElementType.Text) + { + var span:SpanElement = new SpanElement(); + span.text = captionElement.content; + + applyStyles(span, captionElement.currentStyle, captionElement); + + span.text = addBidirectionEncoding(span.text, + (captionElement.currentStyle.unicodeBidi + || parentElement.currentStyle.unicodeBidi), + (captionElement.currentStyle.direction + || parentElement.currentStyle.direction)); + + flowElement = span as FlowElement; + } + else if (captionElement.captionElementType == TimedTextElementType.LineBreak) + { + var br:BreakElement = new BreakElement(); + + applyStyles(br, captionElement.currentStyle, captionElement); + + flowElement = br; + } else if (captionElement.captionElementType == TimedTextElementType.Container + || captionElement.captionElementType == TimedTextElementType.SupParagraphGroupElement) + { + + var children:Vector. = captionElement.children; + var div:DivElement; + var paragraph:ParagraphElement; + var subParagraphGroupElement:SubParagraphGroupElement; + if (captionElement.captionElementType == TimedTextElementType.SupParagraphGroupElement) + { + subParagraphGroupElement = new SubParagraphGroupElement(); + + flowElement = subParagraphGroupElement as FlowElement; + } else if (children + && children.length>0 + && children[0].captionElementType==TimedTextElementType.Container) + { + div = new DivElement(); + + flowElement = div as FlowElement; + } else + { + paragraph = new ParagraphElement(); + + flowElement = paragraph as FlowElement; + } + + if (flowElement) + { + applyStyles(flowElement, captionElement.currentStyle, captionElement); + + if (timeTrait) + { + var currentTime:Number = timeTrait.currentTime; + + for each(var c:CaptionElement in children) + { + if (c.isActiveAtPosition(currentTime, true) + && c.isActiveInRange(currentTime,captionElement.end) + && c.currentStyle.display != "none") + { + /* + trace("YES: "+c.captionElementType + +"\t"+ currentTime + +"\t("+c.begin+", "+c.end+")" + +"\t"+c.content+"\n"); + */ + var childElement:FlowElement = getFlowElement(c); + if (childElement) + FlowGroupElement(flowElement).addChild(childElement); + } + /*else + { + trace("NO: "+c.captionElementType + +"\t"+ currentTime + +"\t("+c.begin+", "+c.end+")" + +"\t"+c.content); + }*/ + } + } + } + } + + // trace(captionElement.captionElementType + " " + flowElement + " "+(flowElement as FlowElement).getText()); + return flowElement as FlowElement; + } + + private function updateContext():void { + if (!hasRendererContext()) return; + _size = new Size(layoutRenderer.parent.measuredWidth, layoutRenderer.parent.measuredHeight); + _cellSize = new Size(toTextSafeArea(_size.width)/NumberPair.cellColumns, toTextSafeArea(_size.height)/NumberPair.cellRows); + } + + private function get size():Size { + updateContext(); + return _size; + } + + private function get cellSize():Size { + updateContext(); + return _cellSize; + } + + + private function toTextSafeArea(value:Number):Number + { + return value*TEXT_SAFE_AREA_RATIO; + } + + public function get showBackground():String + { + return _showBackground; + } + + public function set showBackground(value:String):void + { + _showBackground = value; + } + + private function applyRegionStyles():void + { + //trace("\n*************\n"+this.id+".applyRegionStyles()"); + if (timeTrait) + captionRegion.calculateCurrentStyle(timeTrait.currentTime); + + var styles:Object = captionRegion.currentStyle.styles; + var cellWidth:Number, cellHeight:Number, + safeAreaWidth:Number, safeAreaHeight:Number; + + layoutMetadata.left = NaN; + layoutMetadata.right = NaN; + layoutMetadata.bottom = NaN; + + if (styles.origin) + { + //trace("is AutoOrigin? "+ (styles.origin is AutoOrigin)); + if (styles.origin as AutoOrigin == null) + { + styles.origin.setContext(size.width,size.height); + styles.origin.setFontContext(cellSize.width,cellSize.height); + + if(styles.origin.x>0) + { + layoutMetadata.x = styles.origin.x; + layoutMetadata.right = 0; + } + if(styles.origin.y>0) + { + layoutMetadata.y = styles.origin.y; + layoutMetadata.bottom = 0; + } + + } else + { + layoutMetadata.x = 0; + layoutMetadata.y = 0; + } + + //trace("\tlayoutMetadata {x:"+layoutMetadata.x +", y:"+layoutMetadata.y+"}"); + } + + if(styles.extent) + { + //trace("{width:"+size.width+", height:"+size.height+"}") + + //trace("is AutoExtent? "+ (styles.extent is AutoExtent)); + if (styles.extent as AutoExtent == null) + { + + styles.extent.setContext(size.width,size.height); + styles.extent.setFontContext(cellSize.width,cellSize.height); + + layoutMetadata.width = (styles.extent.width>0) ? Math.min(styles.extent.width, size.width-layoutMetadata.x) : NaN; + layoutMetadata.height = (styles.extent.height>0) ? Math.min(styles.extent.height, size.height-layoutMetadata.y) : NaN; + + } else + { + layoutMetadata.width = size.width-layoutMetadata.x; + layoutMetadata.height = size.height-layoutMetadata.y; + } + //trace("\tlayoutMetadata {width:"+layoutMetadata.width +", height:"+layoutMetadata.height+"}"); + } + + if(styles.zIndex) + { + layoutMetadata.index = styles.zIndex; + } + + for(var key:String in styles){ + var value:* = styles[key]; + //trace("\t{"+key+":"+value+"}"); + switch(key){ + case "showBackground": + case "backgroundColor": + case "backgroundAlpha": + { + this[key] = value; + break; + } + case "wrapOption": + { + _containerController.lineBreak = _textFlow.lineBreak = (styles.wrapOption == WrapOption.NOWRAP.value) ? LineBreak.EXPLICIT : LineBreak.TO_FIT; + break; + } + case "ttFontSize": + { + var ttFontSize:FontSize = value as FontSize; + if (ttFontSize) + { + safeAreaWidth = (ttFontSize.unitMeasureHorizontal==Unit.CELL) ? toTextSafeArea(size.width) : size.width; + safeAreaHeight = (ttFontSize.unitMeasureVertical==Unit.CELL) ? toTextSafeArea(size.height) : size.height; + ttFontSize.setContext(safeAreaWidth, safeAreaHeight); + + cellWidth = (ttFontSize.unitMeasureHorizontal==Unit.PERCENT) ? cellSize.width*(NumberPair.cellColumns-2) : cellSize.width; + cellHeight = (ttFontSize.unitMeasureVertical==Unit.PERCENT) ? cellSize.height*(NumberPair.cellRows-2) : cellSize.height; + ttFontSize.setFontContext(cellWidth, cellHeight); + + _containerController.fontSize = _textFlow.fontSize = ttFontSize.fontHeight; + //trace(_containerController+" setContext("+safeAreaWidth+","+safeAreaHeight+")"); + //trace(_containerController+" setFontContext("+cellWidth+","+cellHeight+")"); + } else { + _containerController.fontSize = _textFlow.fontSize = cellSize.height; + } + //trace(_containerController+" fontSize="+_containerController.fontSize); + break; + } + case "ttLineHeight": + { + var ttLineHeight:LineHeight = value as LineHeight; + if (ttLineHeight) + { + safeAreaWidth = (ttLineHeight.unitMeasureHorizontal==Unit.CELL) ? toTextSafeArea(size.width) : size.width; + safeAreaHeight = (ttLineHeight.unitMeasureVertical==Unit.CELL) ? toTextSafeArea(size.height) : size.height; + ttLineHeight.setContext(safeAreaWidth, safeAreaHeight); + + cellWidth = (ttLineHeight.unitMeasureHorizontal==Unit.PERCENT) ? cellSize.width*(NumberPair.cellColumns-2) : cellSize.width; + cellHeight = (ttLineHeight.unitMeasureVertical==Unit.PERCENT) ? cellSize.height*(NumberPair.cellRows-2) : cellSize.height; + ttLineHeight.setFontContext(cellWidth, cellHeight); + _containerController.lineHeight = _textFlow.lineHeight = ttLineHeight.height; + } else + { + _containerController.lineHeight = _textFlow.lineHeight = (_containerController.fontSize ? _containerController.fontSize : cellSize.height) * 1.2; + } + //trace("lineHeight: " + _containerController.lineHeight); + break; + } + case "padding": + { + var padding:PaddingThickness = value as PaddingThickness; + if (padding) + { + padding.setContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); + padding.setFontContext(cellSize.width, cellSize.height); + _containerController.paddingTop = _textFlow.paddingTop = (padding.widthBefore>0) ? padding.widthBefore : 0; + _containerController.paddingRight = _textFlow.paddingRight = (padding.widthEnd>0) ? padding.widthEnd : 0; + _containerController.paddingBottom = _textFlow.paddingBottom = (padding.widthAfter>0) ? padding.widthAfter : 0; + _containerController.paddingLeft = _textFlow.paddingLeft = (padding.widthStart>0) ? padding.widthStart : 0; + } + break; + } + case "opacity": + { + if (!isNaN(value)) + { + blendMode = BlendMode.LAYER; + alpha = value; + } + break; + } + case "lineThrough": + case "textDecoration": + { + _containerController.textDecoration = _textFlow.textDecoration = styles["textDecoration"] ? styles["textDecoration"] : TextDecoration.NONE; + _containerController.lineThrough = _textFlow.lineThrough = (styles["lineThrough"]) ? styles["lineThrough"] : false; + break; + } + case "direction": + { + _containerController.direction = _textFlow.direction = (value==Direction.RTL) ? Direction.RTL : Direction.LTR; + break; + } + case "visibility": + { + if (styles[key]==Visibility.HIDDEN.value) + { + _containerController.textAlpha = _textFlow.textAlpha = 0; + _containerController.backgroundAlpha = _textFlow.backgroundAlpha = 0; + } else + { + _containerController.textAlpha = _textFlow.textAlpha = styles["textAlpha"]; + _containerController.backgroundAlpha = _textFlow.backgroundAlpha = styles["backgroundAlpha"]; + } + break; + } + default: + { + if(_containerController.hasOwnProperty(key) && value) + { + _containerController.setStyle(key,value); + } else if(_textFlow.hasOwnProperty(key) && value) + { + _textFlow.setStyle(key,value); + } else { + // trace(this+" "+key+"="+styles[key]); + } + + + break; + } + } + } + //trace("*************\n"); + } + + + + private function applyStyles(flowElement:FlowElement, style:TimedTextStyle, captionElement:CaptionElement):void { + + //trace("\n*************\n"+flowElement+".applyStyles()"); + updateContext(); + + var styles:Object = style.styles; + var cellWidth:Number, cellHeight:Number, + safeAreaWidth:Number, safeAreaHeight:Number; + + for(var key:String in styles) + { + var value:* = styles[key]; + //trace("\t{"+key+":"+value+"}"); + switch(key) + { + case "backgroundColor" : + case "backgroundAlpha" : + { + if(flowElement is ParagraphFormattedElement){ + this[key] = value; + } else { + flowElement[key] = value; + } + break; + } + + case "color" : + case "textAlpha" : + { + flowElement[key] = value; + break; + } + + case "showBackground" : + { + this[key] = value; + break; + } + case "wrapOption" : + { + flowElement.lineBreak = (style.wrapOption == WrapOption.NOWRAP.value) ? LineBreak.EXPLICIT : LineBreak.TO_FIT; + _textFlow.lineBreak = flowElement.lineBreak; + //trace("\n"+captionElement.captionElementType+" "+key+"="+styles[key] + " : "+flowElement.lineBreak+"\n"); + break; + } + case "ttFontSize" : + { + var ttFontSize:FontSize = value as FontSize; + if(ttFontSize){ + safeAreaWidth = (ttFontSize.unitMeasureHorizontal==Unit.CELL) ? toTextSafeArea(size.width) : size.width; + safeAreaHeight = (ttFontSize.unitMeasureVertical==Unit.CELL) ? toTextSafeArea(size.height) : size.height; + ttFontSize.setContext(safeAreaWidth, safeAreaHeight); + + cellWidth = (ttFontSize.unitMeasureHorizontal==Unit.PERCENT) ? cellSize.width*(NumberPair.cellColumns-2) : cellSize.width; + cellHeight = (ttFontSize.unitMeasureVertical==Unit.PERCENT) ? cellSize.height*(NumberPair.cellRows-2) : cellSize.height; + ttFontSize.setFontContext(cellWidth, cellHeight); + flowElement.fontSize = ttFontSize.fontHeight; + //trace(flowElement+" setContext("+safeAreaWidth+","+safeAreaHeight+")"); + //trace(flowElement+" setFontContext("+cellWidth+","+cellHeight+")"); + + } else { + flowElement.fontSize = cellSize.height; + } + //trace(flowElement+" fontSize="+flowElement.fontSize); + break; + } + case "ttLineHeight" : + { + var ttLineHeight:LineHeight = value as LineHeight; + if(ttLineHeight){ + safeAreaWidth = (ttLineHeight.unitMeasureHorizontal==Unit.CELL) ? toTextSafeArea(size.width) : size.width; + safeAreaHeight = (ttLineHeight.unitMeasureVertical==Unit.CELL) ? toTextSafeArea(size.height) : size.height; + ttLineHeight.setContext(safeAreaWidth, safeAreaHeight); + + cellWidth = (ttLineHeight.unitMeasureHorizontal==Unit.PERCENT) ? cellSize.width*(NumberPair.cellColumns-2) : cellSize.width; + cellHeight = (ttLineHeight.unitMeasureVertical==Unit.PERCENT) ? cellSize.height*(NumberPair.cellRows-2) : cellSize.height; + ttLineHeight.setFontContext(cellWidth, cellHeight); + + flowElement.lineHeight = ttLineHeight.height; + } else + { + flowElement.lineHeight = (flowElement.fontSize ? flowElement.fontSize : cellSize.height) * 1.2; + } + //trace(flowElement+" lineHeight=" + flowElement.lineHeight); + break; + } + case "padding" : + { + var padding:PaddingThickness = value as PaddingThickness; + if(padding){ + padding.setContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); + + if(padding.widthBeforeUnit == Unit.PERCENT){ + padding.setFontContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); + } else { + padding.setFontContext(cellSize.width, cellSize.height); + } + flowElement.paddingTop = (padding.widthBefore>0) ? padding.widthBefore : 0; + + if(padding.widthEndUnit == Unit.PERCENT){ + padding.setFontContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); + } else { + padding.setFontContext(cellSize.width, cellSize.height); + } + flowElement.paddingRight = (padding.widthEnd>0) ? padding.widthEnd : 0; + + if(padding.widthAfterUnit == Unit.PERCENT){ + padding.setFontContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); + } else { + padding.setFontContext(cellSize.width, cellSize.height); + } + flowElement.paddingBottom = (padding.widthAfter>0) ? padding.widthAfter : 0; + + if(padding.widthStartUnit == Unit.PERCENT){ + padding.setFontContext(this.layoutRenderer.parent.container.measuredWidth,this.layoutRenderer.parent.container.measuredHeight); + } else { + padding.setFontContext(cellSize.width, cellSize.height); + } + flowElement.paddingLeft = (padding.widthStart>0) ? padding.widthStart : 0; + + //trace("padding: "+flowElement.paddingTop+" "+flowElement.paddingRight+" "+flowElement.paddingBottom+" "+flowElement.paddingLeft); + } + break; + } + case "textOutline" : + { + var textOutline:TextOutline = value as TextOutline; + if (textOutline) + { + + textOutline.setContext(this.layoutRenderer.parent.container.measuredWidth, + this.layoutRenderer.parent.container.measuredHeight); + textOutline.setFontContext(cellSize.width, cellSize.height); + + if(!textOutline.colorDefined + && textOutline.width + && styles.color) + { + textOutline.color = styles.color; + for each(var filter:GlowFilter in textOutline.filters) + { + filter.color = styles.color; + } + } + /* + trace(captionElement+" "+key+"="+styles[key]); + trace("\twidth: "+textOutline.width); + trace("\tcolorDefined: "+textOutline.colorDefined); + trace("\tcolor: "+textOutline.color); + trace("\talpha: "+textOutline.alpha); + trace("\tblur: "+textOutline.blur); + trace("\tfilters: "+textOutline.filters); + */ + if (!_textOutlineFiltersDict) + { + _textOutlineFiltersDict = new Dictionary(); + _textOutlineFiltersHash = new Vector.(); + } + + _textOutlineFiltersDict[flowElement] = textOutline.filters; + _textOutlineFiltersHash.push(flowElement); + } + break; + } + case "lineThrough": + case "textDecoration": + { + flowElement.textDecoration = styles["textDecoration"] ? styles["textDecoration"] : TextDecoration.NONE; + flowElement.lineThrough = (styles["lineThrough"]) ? styles["lineThrough"] : false; + break; + } + case "direction": + { + flowElement.direction = (value==Direction.RTL) ? Direction.RTL : Direction.LTR; + break; + } + case "visibility": + { + if (value==Visibility.HIDDEN.value) + { + flowElement.textAlpha = 0; + flowElement.backgroundAlpha = 0; + } else + { + flowElement.textAlpha = styles["textAlpha"]; + flowElement.backgroundAlpha = styles["backgroundAlpha"]; + } + break; + } + default : + { + if(flowElement.hasOwnProperty(key) && value!==null){ + // trace(flowElement+"\t"+key+"\t"+styles[key]); + flowElement.setStyle(key,value); + } else { + //trace(captionElement+" "+key+"="+styles[key]); + } + break; + } + } + } + //trace("*************\n"); + } + + /** + * Assemble the Unicode Bidi text for a given string. + * + * @param text + * @param unicodeBidirection Either embed, normal or bidiOveride + * @param direction Either ltr or rtl + * @return + */ + private function addBidirectionEncoding(text:String, unicodeBidirection:String, direction:String):String + { + var data:String = ""; + switch (unicodeBidirection) + { + case "embed": + //The direction of this embedding level is given by the 'direction' + //property. Inside the element, reordering is done implicitly. + //This corresponds to adding a LRE (U+202A; for 'direction: ltr') + //or RLE (U+202B; for 'direction: rtl') at the start of the + //element and a PDF (U+202C) at the end of the element. + if (direction == "ltr") + { + data = "\u202A" + text + "\u202C"; + } + else + { + data = "\u202B" + text + "\u202C"; + } + break; + case "bidiOverride": + //reordering is strictly in sequence according to the 'direction' + //property; the implicit part of the bidirectional algorithm + //is ignored. This corresponds to adding a LRO (U+202D; for + //'direction: ltr') or RLO (U+202E; for 'direction: rtl') at + //the start of the element and a PDF (U+202C) at the end + //of the element. + if (direction == "ltr") + { + data = "\u202D" + text + "\u202C"; + } + else + { + data = "\u202E" + text + "\u202C"; + } break; + default: + data = text; + break; + + } + return data; + } + + private function buildTextFlow(captionElement:CaptionElement):void + { + //("\n>>>START buildTextFlow<<<"); + updateContext(); + + _textOutlineFiltersDict = null; + _textOutlineFiltersHash = null; + + applyRegionStyles(); + + if (timeTrait) + captionElement.calculateCurrentStyle(timeTrait.currentTime); + + var styles:Object = captionElement.currentStyle.styles; + var origin:Origin, + extent:Extent, + opacity:Number, + ttFontSize:FontSize, + ttLineHeight:LineHeight; + + if(styles.origin && styles.origin as AutoOrigin == null){ + origin = styles.origin as Origin; + + origin.setContext(size.width,size.height); + origin.setFontContext(cellSize.width,cellSize.height); + + if(origin.x>0) + { + layoutMetadata.x = origin.x; + layoutMetadata.right = 0; + } + if(origin.y>0) + { + layoutMetadata.y = origin.y; + layoutMetadata.bottom = 0; + } + //trace("layoutMetadata {x:"+layoutMetadata.x +", y:"+layoutMetadata.y+"}"); + } + + if(styles.extent && styles.extent as AutoExtent == null){ + extent = styles.extent as Extent; + extent.setContext(size.width,size.height); + extent.setFontContext(cellSize.width,cellSize.height); + if(extent.width>0) + { + layoutMetadata.width = extent.width; + } + if(extent.height>0) + { + layoutMetadata.height = extent.height; + } + //trace("\n\nlayoutMetadata {width:"+layoutMetadata.width +", height:"+layoutMetadata.height+"}\n\n"); + } + + validateNow(); + + if(_textFlow.numChildren>0) + _textFlow.replaceChildren(0,_textFlow.numChildren); + + var flowElement:FlowElement = getFlowElement(captionElement); + + if (flowElement) + _textFlow.addChild(flowElement); + var xmlOut:XML = TextConverter.export(_textFlow,TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.XML_TYPE) as XML; + //trace(xmlOut.toXMLString()); + autoSizeContainerController(); + } + + private function applyTextOutlines():void + { + if (_textOutlineFiltersDict) + { + var len:Number = _textOutlineFiltersHash.length; + for (var i:uint; i = _textOutlineFiltersDict[flow] as Vector.; + var filters:Array = VectorUtils.toArray(toFilters); + + if (filters) + { + var pos:uint = FlowElement(flow).getAbsoluteStart(); + var endPos:uint = pos + FlowElement(flow).textLength; + while (pos < endPos) + { + var line:TextFlowLine = _textFlow.flowComposer.findLineAtPosition(pos); + if (line) + { + var textLine:TextLine = line.getTextLine(true); + if(textLine) + { + textLine.filters = filters; + } + pos += line.textLength; + } + } + } + } + _textOutlineFiltersDict = null; + _textOutlineFiltersHash = null; + } + } + + public function clear():void + { + if (_textFlow.numChildren>0) + { + _textFlow.replaceChildren(0,_textFlow.numChildren); + autoSizeContainerController(); + } + } + + private function autoSizeContainerController():void + { + _textFlow.flowComposer.composeToPosition(); + + var contentBounds:Rectangle = _containerController.getContentBounds(); + + _containerController.setCompositionSize(Math.min(_containerController.compositionWidth, layoutMetadata.x-size.width), contentBounds.height); + _textFlow.flowComposer.updateAllControllers(); + + layoutMetadata.height = contentBounds.height; + + measure(); + validateNow(); + } + + // Overrides + // + override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean=true):void + { + if(lastAvailableWidth==availableWidth && lastAvailableHeight==availableHeight) return; + + // trace(">>>>>>>>>"+this+" "+this.id+".layout("+availableWidth+","+availableHeight+","+deep+")"); + if (_containerController) + { + _containerController.setCompositionSize(availableWidth, availableHeight); + _textFlow.flowComposer.updateAllControllers(); + + applyTextOutlines(); + + this._textFlowContainer.scrollRect = null; + } + + super.layout(availableWidth, availableHeight, deep); + } + + override public function set width(value:Number):void + { + if (_containerController) + { + _containerController.setCompositionSize(value, _containerController.compositionHeight); + _textFlow.flowComposer.updateAllControllers(); + } + super.width = value; + } + + override public function set height(value:Number):void + { + if (_containerController) + { + _containerController.setCompositionSize(_containerController.compositionWidth, value); + _textFlow.flowComposer.updateAllControllers(); + } + super.height = value; + } + + + private function get timeTrait():TimeTrait + { + if (!_timeTrait && mediaElement) + { + _timeTrait = mediaElement.getTrait(MediaTraitType.TIME) as TimeTrait; + } + return _timeTrait; + } + + private var _id:String = ""; + private var _captionRegion:CaptionRegion; + private var _textFlow:TextFlow; + private var _textFlowContainer:Sprite; + private var _containerController:ContainerController; + private var _currentCaption:CaptionElement; + private var _size:Size; + private var _cellSize:Size; + private var _showBackground:String = ShowBackground.Always.value; + private var _textOutlineFiltersDict:Dictionary; + private var _textOutlineFiltersHash:Vector.; + private var _timeTrait:TimeTrait; + private static const TEXT_SAFE_AREA_RATIO:Number = 0.8; + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/RootLayoutTargetSprite.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/RootLayoutTargetSprite.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/SMPTETTProxyElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/SMPTETTProxyElement.as old mode 100755 new mode 100644 index 7773a3e..c53f8dd --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/SMPTETTProxyElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/media/SMPTETTProxyElement.as @@ -1,855 +1,1088 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.media -{ - import flash.display.DisplayObject; - import flash.events.Event; - import flash.events.TimerEvent; - import flash.utils.Dictionary; - import flash.utils.Timer; - - import org.osmf.containers.IMediaContainer; - import org.osmf.containers.MediaContainer; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.ProxyElement; - import org.osmf.events.DisplayObjectEvent; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorEvent; - import org.osmf.events.MetadataEvent; - import org.osmf.events.PlayEvent; - import org.osmf.events.SeekEvent; - import org.osmf.events.TimelineMetadataEvent; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactory; - import org.osmf.media.MediaPlayer; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.metadata.TimelineMarker; - import org.osmf.metadata.TimelineMetadata; - import org.osmf.smpte.tt.SMPTETTPluginInfo; - import org.osmf.smpte.tt.captions.CaptionElement; - import org.osmf.smpte.tt.captions.CaptioningDocument; - import org.osmf.smpte.tt.loader.SMPTETTLoadTrait; - import org.osmf.smpte.tt.loader.SMPTETTLoader; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitBase; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - - /** - * The SMPTETTProxyElement class is a wrapper for the media supplied. - * It's purpose is to override the loadable trait to allow the retrieval and - * processing of an Timed Text file used for captioning. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public class SMPTETTProxyElement extends ProxyElement - { - /** - * Constant for the MediaError that is triggered when the proxiedElement - * is invalid (e.g. doesn't have the captioning metadata). - **/ - public static const MEDIA_ERROR_INVALID_PROXIED_ELEMENT:int = 2201; - - private static const DEBUG:Boolean = true; - - /** - * Constructor. - * - * @inheritDoc - * - * @param continueLoadOnFailure Specifies whether or not the - * class should continue the load process if the captioning - * document fails to load. The default value is true. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function SMPTETTProxyElement(proxiedElement:MediaElement=null, continueLoadOnFailure:Boolean=true) - { - super(proxiedElement); - _continueLoadOnFailure = continueLoadOnFailure; - } - - - /** - * The MediaElement for which this ProxyElement serves as a proxy. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.media +{ + import flash.display.DisplayObject; + import flash.events.Event; + import flash.events.TimerEvent; + import flash.external.ExternalInterface; + import flash.utils.Dictionary; + import flash.utils.Timer; + + import org.osmf.containers.IMediaContainer; + import org.osmf.containers.MediaContainer; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.ProxyElement; + import org.osmf.events.DisplayObjectEvent; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorEvent; + import org.osmf.events.MetadataEvent; + import org.osmf.events.PlayEvent; + import org.osmf.events.SeekEvent; + import org.osmf.events.TimelineMetadataEvent; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactory; + import org.osmf.media.MediaPlayer; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.metadata.TimelineMarker; + import org.osmf.metadata.TimelineMetadata; + import org.osmf.smpte.tt.SMPTETTPluginInfo; + import org.osmf.smpte.tt.architecture.creation.SMPTETTFactoryFacade; + import org.osmf.smpte.tt.captions.CaptionElement; + import org.osmf.smpte.tt.captions.CaptioningDocument; + import org.osmf.smpte.tt.captions.TimedTextElement; + import org.osmf.smpte.tt.captions.TimedTextElementType; + import org.osmf.smpte.tt.loader.SMPTETTLoadTrait; + import org.osmf.smpte.tt.loader.SMPTETTLoader; + import org.osmf.smpte.tt.timing.TimeExpression; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitBase; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + + /** + * The SMPTETTProxyElement class is a wrapper for the media supplied. + * It's purpose is to override the loadable trait to allow the retrieval and + * processing of an Timed Text file used for captioning. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public class SMPTETTProxyElement extends ProxyElement + { + /** + * Constant for the MediaError that is triggered when the proxiedElement + * is invalid (e.g. doesn't have the captioning metadata). + **/ + public static const MEDIA_ERROR_INVALID_PROXIED_ELEMENT:int = 2201; + + public static const DEBUG:Boolean = false; + + /** + * Constructor. + * + * @inheritDoc + * + * @param continueLoadOnFailure Specifies whether or not the + * class should continue the load process if the captioning + * document fails to load. The default value is true. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function SMPTETTProxyElement(proxiedElement:MediaElement=null, continueLoadOnFailure:Boolean=true) + { + super(proxiedElement); + _continueLoadOnFailure = continueLoadOnFailure; + } + + + /** + * The MediaElement for which this ProxyElement serves as a proxy. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ public function get mediaElement():MediaElement - { - return _mediaElement; - } - - /** - * Specifies whether or not this class should continue loading - * the media element when the captioning document - * fails to load. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.6 - */ - public function get continueLoadOnFailure():Boolean - { - return _continueLoadOnFailure; - } - - /** - * @private - */ - override public function set proxiedElement(value:MediaElement):void - { - - super.proxiedElement = value; - - if (value != null) - { - // Override the LoadTrait with our own custom LoadTrait, - // which retrieves the Timed Text document, parses it, and sets up - // the object model representing the caption data. - - // Store a reference to the original proxied MediaElement - _mediaElement = super.proxiedElement; - - // Create a parallel element to hold the media and watermark image elements - var parallelElement:ParallelElement = new ParallelElement(); - - // Add the media element as a child of the parallel element - parallelElement.addChild( mediaElement ); - - // Set new parallelElement as the proxiedElement - super.proxiedElement = parallelElement; - - // Get the mediaElement resource of the element that is wrapped. - var tempResource:MediaResourceBase = (mediaElement && mediaElement.resource != null) ? mediaElement.resource : resource; - - if (tempResource == null) - { - dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, - new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); - } - else - { - var metadata:Metadata = tempResource.getMetadataValue(SMPTETTPluginInfo.SMPTETT_METADATA_NAMESPACE) as Metadata; - - if (metadata == null) - { - if (!_continueLoadOnFailure) - { - dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, - new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); - } else - { - metadata = new Metadata(); - tempResource.addMetadataValue(SMPTETTPluginInfo.SMPTETT_METADATA_NAMESPACE, metadata); - } - } - - // In order to respond to resize and scrub events, - // store a reference to the _mediaFactory, _mediaContainer and _mediaPlayer - _mediaFactory = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAFACTORY) as MediaFactory; - _mediaContainer = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIACONTAINER) as IMediaContainer; - _mediaPlayer = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAPLAYER) as MediaPlayer; - - // Get initial showCaptions value - var showCaptions:* = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_SHOWCAPTIONS); - if(showCaptions!==null && showCaptions is Boolean) - captioningEnabled = showCaptions; - - // Get the SMPTE-TT url resource from the metadata of the element - // that is wrapped. - var timedTextURL:String = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_URI); - - // If the SMPTE-TT url resource exists, load the captions - if (timedTextURL) - { - loadCaptions(timedTextURL); - } - else if (!_continueLoadOnFailure) - { - dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, - new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); - } - - // Listen for traits to be added so we can add any desired event listeners on any - // traits we care about. - proxiedElement.addEventListener( MediaElementEvent.TRAIT_ADD, _onAddTrait ); - proxiedElement.addEventListener( MediaElementEvent.TRAIT_REMOVE, _onRemoveTrait ); - - // Listen for metadata to be added so we can add any desired event listeners on any - // metadata facets we care about. - proxiedElement.addEventListener(MediaElementEvent.METADATA_ADD, onMetadataAdd); - - // Listen for metadata to be removed so we can remove an event listener. - proxiedElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onMetadataRemove); - - // Listen for metadata add change and remove events so that we can respond to changes - // to the SMPTE-TT url and showCaptions - metadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdd, false, 0, true); - metadata.addEventListener(MetadataEvent.VALUE_CHANGE, onMetadataValueChange, false, 0, true); - metadata.addEventListener(MetadataEvent.VALUE_REMOVE, onMetadataValueRemove, false, 0, true); - } - } - } - - /** - * @private - */ - override public function get resource():MediaResourceBase - { - return mediaElement ? mediaElement.resource : null; - } - - /** - * @private - */ - override public function set resource(value:MediaResourceBase):void - { - if (mediaElement != null) - { - mediaElement.resource = value; - } - } - - /** - * @private - */ - protected function onMetadataValueAdd(event:MetadataEvent):void - { - //trace(event.type+ " { "+event.key +", " +event.value+" } "); - var metadata:Metadata = event.target as Metadata; + { + return _mediaElement; + } + + /** + * Specifies whether or not this class should continue loading + * the media element when the captioning document + * fails to load. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + public function get continueLoadOnFailure():Boolean + { + return _continueLoadOnFailure; + } + + /** + * @private + */ + override public function set proxiedElement(value:MediaElement):void + { + super.proxiedElement = value; + + if (value != null) + { + // Override the LoadTrait with our own custom LoadTrait, + // which retrieves the Timed Text document, parses it, and sets up + // the object model representing the caption data. + + // Store a reference to the original proxied MediaElement + _mediaElement = super.proxiedElement; + + // Create a parallel element to hold the media and watermark image elements + var parallelElement:ParallelElement = new ParallelElement(); + + // Add the media element as a child of the parallel element + parallelElement.addChild( mediaElement ); + + // Set new parallelElement as the proxiedElement + super.proxiedElement = parallelElement; + + // Get the mediaElement resource of the element that is wrapped. + var tempResource:MediaResourceBase = (mediaElement && mediaElement.resource != null) ? mediaElement.resource : resource; + + if (tempResource == null) + { + dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, + new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); + } + else + { + var metadata:Metadata = tempResource.getMetadataValue(SMPTETTPluginInfo.SMPTETT_METADATA_NAMESPACE) as Metadata; + + if (metadata == null) + { + if (!_continueLoadOnFailure) + { + dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, + new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); + } else + { + metadata = new Metadata(); + tempResource.addMetadataValue(SMPTETTPluginInfo.SMPTETT_METADATA_NAMESPACE, metadata); + } + } + + // In order to respond to resize and scrub events, + // store a reference to the _mediaFactory, _mediaContainer and _mediaPlayer + _mediaFactory = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAFACTORY) as MediaFactory; + _mediaContainer = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIACONTAINER) as IMediaContainer; + _mediaPlayer = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAPLAYER) as MediaPlayer; + + // Get initial showCaptions value + var showCaptions:* = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_SHOWCAPTIONS); + if(showCaptions!==null && showCaptions is Boolean) + captioningEnabled = showCaptions; + + // Get the SMPTE-TT url resource from the metadata of the element + // that is wrapped. + var timedTextURL:String = metadata.getValue(SMPTETTPluginInfo.SMPTETT_METADATA_KEY_URI); + + // If the SMPTE-TT url resource exists, load the captions + if (timedTextURL) + { + loadCaptions(timedTextURL); + } + else if (!_continueLoadOnFailure) + { + dispatchEvent(new MediaErrorEvent( MediaErrorEvent.MEDIA_ERROR, false, false, + new MediaError(MEDIA_ERROR_INVALID_PROXIED_ELEMENT))); + } + + // Listen for traits to be added so we can add any desired event listeners on any + // traits we care about. + proxiedElement.addEventListener( MediaElementEvent.TRAIT_ADD, _onAddTrait, false, 0, true ); + proxiedElement.addEventListener( MediaElementEvent.TRAIT_REMOVE, _onRemoveTrait, false, 0, true ); + + // Listen for metadata to be added so we can add any desired event listeners on any + // metadata facets we care about. + proxiedElement.addEventListener(MediaElementEvent.METADATA_ADD, onMetadataAdd, false, 0, true); + + // Listen for metadata to be removed so we can remove an event listener. + proxiedElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onMetadataRemove, false, 0, true); + + // Listen for metadata add change and remove events so that we can respond to changes + // to the SMPTE-TT url and showCaptions + metadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdd, false, 0, true); + metadata.addEventListener(MetadataEvent.VALUE_CHANGE, onMetadataValueChange, false, 0, true); + metadata.addEventListener(MetadataEvent.VALUE_REMOVE, onMetadataValueRemove, false, 0, true); + } + } + } + + /** + * @private + */ + override public function get resource():MediaResourceBase + { + return mediaElement ? mediaElement.resource : null; + } + + /** + * @private + */ + override public function set resource(value:MediaResourceBase):void + { + if (mediaElement != null) + { + mediaElement.resource = value; + } + } + + /** + * @private + */ + protected function onMetadataValueAdd(event:MetadataEvent):void + { + debug(event.type+ " { "+event.key +", " +event.value+" } "); + var metadata:Metadata = event.target as Metadata; + switch(event.key) + { + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAFACTORY: + { + _mediaFactory = event.value as MediaFactory; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIACONTAINER: + { + _mediaContainer = event.value as MediaContainer; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAPLAYER: + { + _mediaPlayer = event.value as MediaPlayer; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_URI: + { + proxiedElement.removeMetadata(SMPTETTPluginInfo.SMPTETT_TEMPORAL_METADATA_NAMESPACE); + var timedTextURL:String = event.value as String; + if (timedTextURL) + { + loadCaptions(timedTextURL); + } + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_SHOWCAPTIONS: + { + captioningEnabled = Boolean(event.value); + break; + } + } + if (_queueLoad && _timedTextURL) + { + loadCaptions(_timedTextURL); + } + } + + /** + * @private + */ + protected function onMetadataValueChange(event:MetadataEvent):void + { + debug(event.type+ " { "+event.key +", " +event.value+" } "); + var metadata:Metadata = event.target as Metadata; switch(event.key) { case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAFACTORY: { - _mediaFactory = event.value as MediaFactory; + _mediaFactory = event.value as MediaFactory; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIACONTAINER: + { + _mediaContainer = event.value as MediaContainer; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAPLAYER: + { + _mediaPlayer = event.value as MediaPlayer; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_URI: + { + proxiedElement.removeMetadata(SMPTETTPluginInfo.SMPTETT_TEMPORAL_METADATA_NAMESPACE); + var timedTextURL:String = event.value as String; + if (timedTextURL) + { + loadCaptions(timedTextURL); + } + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_SHOWCAPTIONS: + { + captioningEnabled = Boolean(event.value); + break; + } + } + } + + /** + * @private + */ + protected function onMetadataValueRemove(event:MetadataEvent):void + { + //debug(event.type+ " { "+event.key +", " +event.value+" } "); + var metadata:Metadata = event.target as Metadata; + switch(event.key) + { + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAFACTORY: + { + _mediaFactory = null; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIACONTAINER: + { + _mediaContainer = null; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_MEDIAPLAYER: + { + _mediaPlayer = null; + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_URI: + { + proxiedElement.removeMetadata(SMPTETTPluginInfo.SMPTETT_TEMPORAL_METADATA_NAMESPACE); + break; + } + case SMPTETTPluginInfo.SMPTETT_METADATA_KEY_SHOWCAPTIONS: + { + captioningEnabled = Boolean(event.value); + break; + } + } + } + + /** + * @private + */ + private function loadCaptions(timedTextURL:String):void + { + var timeTrait:TimeTrait = proxiedElement.getTrait(MediaTraitType.TIME) as TimeTrait; + + if (!timeTrait || timeTrait.duration==0 + || !_mediaPlayer + || !_mediaContainer + || !_mediaFactory) + { + debug("queueLoad of "+timedTextURL); + _queueLoad = true; + _timedTextURL = timedTextURL; + return; + } + + _queueLoad = false; + _timedTextURL = null; + + debug( "loadCaptions(\""+timedTextURL+"\");"); + + var smptettLoader:SMPTETTLoader = SMPTETTFactoryFacade.getSMPTETTLoader(); + var urlResource:URLResource = new URLResource(timedTextURL); + + + if (_mediaPlayer) + { + // pauseMediaPlayerDuringLoadCaptions(); + updateEndTimetoMediaDuration(smptettLoader); + } + + loadTrait = createLoadTrait(smptettLoader,urlResource); + addLoadTraitListeners(loadTrait); + loadTrait.load(); + // addTrait(MediaTraitType.LOAD, loadTrait); + } + + protected function pauseMediaPlayerDuringLoadCaptions():void + { + if(_mediaPlayer.canPause) + { + if (_mediaPlayer.playing) _wasPlaying = true; + if (_mediaPlayer.paused) _wasPaused = true; + _mediaPlayer.pause(); + } + } + + protected function updateEndTimetoMediaDuration(smptettLoader:SMPTETTLoader):void + { + if(_mediaPlayer.duration) + { + TimeExpression.initializeParameters(); + smptettLoader.endTime = TimeExpression.parse(_mediaPlayer.duration+"s"); + } + } + + protected function createLoadTrait(smptettLoader:SMPTETTLoader, urlResource:URLResource):SMPTETTLoadTrait + { + return new SMPTETTLoadTrait(smptettLoader, urlResource); + } + + protected function addLoadTraitListeners(trait:SMPTETTLoadTrait):void + { + loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange, false, int.MAX_VALUE, true); + } + + /** + * @private + */ + protected function onLoadStateChange(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + addMetaDataTimelineMarkers(); + cleanUp(); + } + else if (event.loadState == LoadState.LOAD_ERROR) + { + onLoadStateChange_Error(event); + } + } + + + protected function addMetaDataTimelineMarkers():void + { + var document:CaptioningDocument = loadTrait.document; + + // Create a TimelineMetadata object to associate + // the captions with the media element. + var SMPTETTMetadata:TimelineMetadata = getOrCreateTimelineMetaData(); + if (document) + addTimelineMarkers(document, SMPTETTMetadata); + + // cleanUp(); + } + + protected function getOrCreateTimelineMetaData():TimelineMetadata + { + var SMPTETTMetadata:TimelineMetadata = proxiedElement.getMetadata(SMPTETTPluginInfo.SMPTETT_TEMPORAL_METADATA_NAMESPACE) as TimelineMetadata; + if (SMPTETTMetadata == null) + { + SMPTETTMetadata = new TimelineMetadata(proxiedElement); + proxiedElement.addMetadata(SMPTETTPluginInfo.SMPTETT_TEMPORAL_METADATA_NAMESPACE, SMPTETTMetadata); + } + return SMPTETTMetadata; + } + + + protected function onLoadStateChange_Error(event:LoadEvent):void + { + if (!_continueLoadOnFailure) + { + dispatchEvent(event.clone()); + } + else + { + cleanUp(); + } + } + + + /** + * @private + */ + private function cleanUp():void + { + // Our work is done, remove the custom LoadTrait. This will + // expose the base LoadTrait, which we can then use to do + // the actual load. + var loadTrait:LoadTrait = getTrait(MediaTraitType.LOAD) as LoadTrait; + + if (loadTrait != null + && loadTrait.loadState == LoadState.UNINITIALIZED) + loadTrait.load(); + + if (_mediaPlayer && _mediaPlayer.canPlay) + { + + if (_wasPlaying) + { + _mediaPlayer.play(); + _wasPlaying = false; + } + else if (_wasPaused) + { + _mediaPlayer.pause(); + _wasPaused = false; + } + + showNearestCaption(_mediaPlayer.currentTime); + } + } + + protected var captionElementsDisplayed:Dictionary; + protected var totalCaptionElementsToDisplay:uint = 0; + + /** + * @private + */ + protected function addTimelineMarkers(document:CaptioningDocument, + SMPTETTMetadata:TimelineMetadata):void + { + buildCaptioningMediaElement(document); + + addEachCaptionToMetaData(document,SMPTETTMetadata); + } + + protected function addEachCaptionToMetaData(document:CaptioningDocument, SMPTETTMetadata:TimelineMetadata):void + { + for each(var c:CaptionElement in document.captionElements){ + + if (c) + { + SMPTETTMetadata.addMarker(c); + if (DEBUG) addCaptionElementToDisplay(c); + } + } + } + + /** + * @private + */ + protected function addCaptionElementToDisplay(captionElement:CaptionElement):void + { + if (!DEBUG) return; + + if (!captionElementsDisplayed) + { + captionElementsDisplayed = new Dictionary(); + } + if (captionElement.captionElementType == TimedTextElementType.Text) + { + captionElementsDisplayed[captionElement] = {index:totalCaptionElementsToDisplay++, displayed:false}; + } else + { + var c:CaptionElement; + for each(c in captionElement.children) + { + addCaptionElementToDisplay(c); + } + + for each(c in captionElement.siblings) + { + addCaptionElementToDisplay(c); + } + } + } + + protected function flagCaptionElementAsDisplayed(captionElement:CaptionElement):void + { + + if (!DEBUG) return; + + if (captionElement.captionElementType == TimedTextElementType.Text + && captionElementsDisplayed[captionElement] + && captionElementsDisplayed[captionElement].displayed == false) + { + captionElementsDisplayed[captionElement].displayed = true; + debug((captionElementsDisplayed[captionElement].index)+" of "+(totalCaptionElementsToDisplay-1)+":\t"+captionElement.regionId+"\t"+TimeExpression.parse(captionElement.begin+"s")+"\t"+TimeExpression.parse(captionElement.end+"s")+"\t"+captionElement.content); + } else + { + var c:CaptionElement; + for each(c in captionElement.children) + { + flagCaptionElementAsDisplayed(c); + } + + for each(c in captionElement.siblings) + { + flagCaptionElementAsDisplayed(c); + } + } + } + + /** + * @private + */ + private function buildCaptioningMediaElement(document:CaptioningDocument):void + { + if (captioningMediaElement) {return;} + + var mediaContainer:IMediaContainer = proxiedElement.container; + + if (!mediaContainer && _mediaContainer) + mediaContainer = _mediaContainer; + + var parallelElement:ParallelElement = super.proxiedElement as ParallelElement; + + if (!captioningMediaElement) + captioningMediaElement = new CaptioningMediaElement(); + + captioningMediaElement.showCaptions = _captioningEnabled; + + if (parallelElement) + { + addToParallelElement(parallelElement,captioningMediaElement); + + captioningMediaElement.mediaElement = mediaElement; + + var len:int = document.captionRegions.length + for (var i:uint=0; i0) + { + return true; + } + } + return bool; + } + + /** + * @private + */ + private function onHideCaption(event:TimelineMetadataEvent):void + { + var captionElement:CaptionElement = event.marker as CaptionElement; + + if (_currentCaption + && _currentCaption.time == captionElement.time) + { + clearCaptionElement(captionElement); + _currentCaption = null; + } + } + + /** + * @private + */ + private function clearCaptionElement(captionElement:CaptionElement):void + { + if (captioningMediaElement) + { + captioningMediaElement.removeCaption(captionElement); + + if(_currentPositionTimer) + { + _currentPositionTimer.stop(); + captioningMediaElement.validateCaptions(); + } + } + } + + /** + * @private + */ + private function clearCaptionText():void + { + if (captioningMediaElement && _currentCaption) + { + clearCaptionElement(_currentCaption); + _currentCaption = null; + } + } + + /** + * @private + */ + private function onMetadataAdd(event:MediaElementEvent):void + { + var metadata:TimelineMetadata = event.metadata as TimelineMetadata; + + if (metadata) + { + debug(">>> Timeline metadata added to "+event.target+", namespace="+event.namespaceURL+" "+event.metadata); + _namespaces[metadata] = event.namespaceURL; + _timelineMetadata = metadata; + _timelineMetadata.addEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption, false, 0, true); + _timelineMetadata.addEventListener(TimelineMetadataEvent.MARKER_DURATION_REACHED, onHideCaption, false, 0, true); + } + else + { + debug(">>> Other metadata added to "+event.target+", namespace="+event.namespaceURL+" "+event.metadata); + mediaElement.addMetadata(event.namespaceURL, event.metadata); + } + } + + /** + * @private + */ + private function onMetadataRemove(event:MediaElementEvent):void + { + var metadata:TimelineMetadata = event.metadata as TimelineMetadata; + + if (metadata && _timelineMetadata) + { + debug(">>> Timeline metadata removed from "+event.target+", namespace="+event.namespaceURL); + delete _namespaces[metadata]; + _timelineMetadata.removeEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); + _timelineMetadata.removeEventListener(TimelineMetadataEvent.MARKER_DURATION_REACHED, onHideCaption); + _timelineMetadata = null; + } + else + { + debug(">>> Other metadata removed from "+event.target+", namespace=" + event.namespaceURL + " " + event.metadata); + mediaElement.removeMetadata(event.namespaceURL); + } + } + + /** + * @private + */ + private function onPlayStateChange(event:PlayEvent):void + { + debug(event.target + " onPlayStateChange: " + event.playState); + if (!captioningMediaElement) return; + if (event.playState != PlayState.PLAYING) + { + if (_wasPlaying) _wasPlaying = false; + _currentPositionTimer.stop(); + captioningMediaElement.validateCaptions(); + } + else if (event.playState != PlayState.PAUSED) + { + if (_wasPaused) _wasPaused = false; + } + } + + /** + * @private + */ + private function onDisplayObjectChange(event:DisplayObjectEvent):void + { + debug(event.target + " onDisplayObjectChange: " + event.newDisplayObject); + } + + /** + * @private + */ + private function onMediaSizeChange(event:DisplayObjectEvent):void + { + var dot:DisplayObjectTrait = _mediaElement.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; + + if (!dot) return; + + debug(dot+" "+ dot.displayObject + " onMediaSizeChange: {mediaWidth:"+dot.mediaWidth+", mediaHeight:"+dot.mediaHeight+"}"); + + if (captioningMediaElement + && !isNaN(dot.mediaWidth) + && !isNaN(dot.mediaHeight) + && dot.mediaWidth + && dot.mediaHeight) + captioningMediaElement.setIntrinsicDimensions(dot.mediaWidth, dot.mediaHeight); + } + + /** + * @private + */ + private function onSeekingChange(event:SeekEvent):void + { + // debug(event.target + " onSeekingChange: " + event.seeking); + _currentPositionTimer.stop(); + _seeked = true; + if (event.seeking) + clearCaptionText(); + showNearestCaption(event.time); + _seeked = false; + } + + private function findNearestCaption(time:Number):CaptionElement + { + if (!_timelineMetadata) return null; + var i:int = 0; + var toShow:CaptionElement; + var captionElement:CaptionElement; + while (i<_timelineMetadata.numMarkers) + { + captionElement = _timelineMetadata.getMarkerAt(i) as CaptionElement; + if (captionElement.isActiveAtPosition(time,true)) + { + toShow = captionElement; + } else if (toShow + && time>captionElement.end + && captionElement.end>> Timeline metadata added to "+event.target+", namespace="+event.namespaceURL+" "+event.metadata); - _namespaces[metadata] = event.namespaceURL; - _timelineMetadata = metadata; - _timelineMetadata.addEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); - _timelineMetadata.addEventListener(TimelineMetadataEvent.MARKER_DURATION_REACHED, onHideCaption); - } - else - { - debug(">>> Other metadata added to "+event.target+", namespace="+event.namespaceURL+" "+event.metadata); - mediaElement.addMetadata(event.namespaceURL, event.metadata); - } - } - - /** - * @private - */ - private function onMetadataRemove(event:MediaElementEvent):void - { - var metadata:TimelineMetadata = event.metadata as TimelineMetadata; - - if (metadata && _timelineMetadata) - { - debug(">>> Timeline metadata removed from "+event.target+", namespace="+event.namespaceURL); - delete _namespaces[metadata]; - _timelineMetadata.removeEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption); - _timelineMetadata.removeEventListener(TimelineMetadataEvent.MARKER_DURATION_REACHED, onHideCaption); - _timelineMetadata = null; - } - else - { - debug(">>> Other metadata removed from "+event.target+", namespace=" + event.namespaceURL + " " + event.metadata); - mediaElement.removeMetadata(event.namespaceURL); - } - } - - /** - * @private - */ - private function onPlayStateChange(event:PlayEvent):void - { - debug(event.target + " onPlayStateChange: " + event.playState); - if(captioningMediaElement - && event.playState != PlayState.PLAYING) - { - _currentPositionTimer.stop(); - captioningMediaElement.validateCaptions(); - } - } - - /** - * @private - */ - private function onDisplayObjectChange(event:DisplayObjectEvent):void - { - debug(event.target + " onDisplayObjectChange: " + event.newDisplayObject); - } - - /** - * @private - */ - private function onMediaSizeChange(event:DisplayObjectEvent):void - { - var dot:DisplayObjectTrait = event.target as DisplayObjectTrait; - - debug(dot+" "+dot.displayObject + " onMediaSizeChange: {mediaWidth:"+event.newWidth+", mediaHeight:"+event.newHeight+"}"); - - if (captioningMediaElement) - captioningMediaElement.setIntrinsicDimensions(event.newWidth, event.newHeight); - } - - /** - * @private - */ - private function onSeekingChange(event:SeekEvent):void - { - // debug(event.target + " onSeekingChange: " + event.seeking); - _currentPositionTimer.stop(); - _seeked = true; - clearCaptionText(); - showNearestCaption(event.time); - _seeked = false; - } - - /** - * @private - */ - private function showNearestCaption(time:Number):void - { - if (!_timelineMetadata) return; - - var toShow:CaptionElement; - - for (var i:uint=0; i<_timelineMetadata.numMarkers; i++) - { - var captionElement:CaptionElement = _timelineMetadata.getMarkerAt(i) as CaptionElement; - if (captionElement.isActiveAtPosition(time)) - toShow = captionElement; - else if (toShow - && time>captionElement.end - && captionElement.end = document.captionElements; + var c:CaptionElement; + var i:uint; + var startAt:int = Math.max(0,SMPTETTMetadata.numMarkers-1); + for (i=startAt; iABC @@ -81,7 +76,7 @@ package org.osmf.smpte.tt.model /// nested elements will still inherit correctly, as style is inherited /// throughthe tt_element tree, not the formatting object tree. /// something to watch out for when computing relative values though. - for each (var nestedInline:* in fo.children) + for each (var nestedInline:TreeType in fo.children) { nestedInline.parent = block; block.children.push(nestedInline); @@ -102,7 +97,7 @@ package org.osmf.smpte.tt.model } if (child is SetElement) { - fo = ((child as SetElement).getFormattingObject(tick)) as Animation; + fo = SetElement(child).getFormattingObject(tick) as Animation; if (fo != null) { block.animations.push(fo); @@ -149,54 +144,27 @@ package org.osmf.smpte.tt.model */ protected override function validElements():void { - var child:uint = 0; - - //{ region Allow arbitrary metadata - while ((child < children.length) - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement) - // || (children[child] is anonymousSpan) - )) - { - child++; - } - //} endregion - - //{ region Allow arbitrary set elements (Animation class) - while ((child < children.length) - && ((children[child] is SetElement) - //|| (children[child] is anonymousSpan) - )) - { - child++; - } - //} endregion - - //{ region Allow arbitrary span, br, PCDATA (Inline class) - while ((child < children.length) - && ((children[child] is SpanElement) - || (children[child] is BrElement) - || (children[child] is AnonymousSpanElement) - )) - { - child++; - } - //} endregion - - //{ region Check no other element is present - if (children.length != child) - { - error(children[child] + " is not allowed in " + this + " at position " + child); - } - //} endregion - + var child:uint = 0; //{ region now check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement + || element is SetElement + || element is SpanElement + || element is BrElement + || element is AnonymousSpanElement) + { + child++; + element.valid(); + } + else + { + error(element + " is not allowed in " + this + " at position " + (children.length-child)); + continue; + } } - //} endregion - + //} endregion } //} endregion } diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/RegionElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/RegionElement.as old mode 100755 new mode 100644 index c866215..4f67cb7 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/RegionElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/RegionElement.as @@ -24,6 +24,7 @@ package org.osmf.smpte.tt.model import org.osmf.smpte.tt.model.metadata.MetadataElement; import org.osmf.smpte.tt.timing.TimeCode; import org.osmf.smpte.tt.timing.TimeContainer; + import org.osmf.smpte.tt.timing.TreeType; public class RegionElement extends TimedTextElementBase { @@ -39,8 +40,6 @@ package org.osmf.smpte.tt.model public static const DEFAULT_REGION_NAME:String = "default region"; //} endregion - - //{ region Formatting /** * Return formatting object for region element @@ -87,59 +86,38 @@ package org.osmf.smpte.tt.model } /** - * Check vlidity of region element content model + * Check validity of region element content model */ protected override function validElements():void { var child:uint = 0; - - //{ region Allow arbitrary metadata - while ((child < children.length) - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement))) - { - child++; - } - //} endregion - - //{ region Allow arbitrary set element (Animation class) - while ((child < children.length) - && (children[child] is SetElement)) - { - child++; - } - //} endregion - - //{ region Allow arbitrary style elements - while ((child < children.length) - && (children[child] is StyleElement) - ) - { - var s:StyleElement = children[child] as StyleElement; - //{ region copy nested style attributes over as if they were inline - for each (var a:* in s.attributes) - { - // we should really check if its already defined, however - // by adding at the start we ensure the later (inline) - // style will override. - this.attributes.unshift(a); - } - //} endregion - child++; - } - //} endregion - - //{ region Ensure no other element is present - if (children.length != child) - { - error(children[child] + " is not allowed in " + this+ " at position " + child); - } - //} endregion - //{ region Check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement + || element is SetElement + || element is StyleElement) + { + if (element is StyleElement) + { + var styleAttributes:Vector. = element.attributes; + //{ region copy nested style attributes over as if they were inline + for each (var a:TimedTextAttributeBase in styleAttributes) + { + // we should really check if its already defined, however + // by adding at the start we ensure the later (inline) + // style will override. + this.attributes.unshift(a); + } + //} endregion + } + child++; + element.valid(); + } else { + error(element + " is not allowed in " + this+ " at position " + (children.length-child)); + continue; + } } //} endregion diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/SetElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/SetElement.as old mode 100755 new mode 100644 index b2745f0..7faa038 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/SetElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/SetElement.as @@ -23,7 +23,6 @@ package org.osmf.smpte.tt.model import org.osmf.smpte.tt.formatting.FormattingObject; import org.osmf.smpte.tt.model.metadata.MetadataElement; import org.osmf.smpte.tt.timing.TimeCode; - import org.osmf.smpte.tt.timing.TimeTree; public class SetElement extends TimedTextElementBase { @@ -81,27 +80,18 @@ package org.osmf.smpte.tt.model protected override function validElements():void { var child:uint = 0; - - //{ region Allow arbitrary metadata - while ((child < children.length) - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement))) - { - child++; - } - //} endregion - - //{ region Ensure no other element is present - if (children.length != child) - { - error(children[child] + " is not allowed in " + this + " at position " + child); - } - //} endregion - //{ region Check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement) + { + child++; + element.valid(); + } else + { + error(element + " is not allowed in " + this + " at position " + (children.length-child)); + } } //} endregion } diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/SpanElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/SpanElement.as old mode 100755 new mode 100644 index 6b045b5..90042ee --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/SpanElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/SpanElement.as @@ -25,8 +25,7 @@ package org.osmf.smpte.tt.model import org.osmf.smpte.tt.model.metadata.MetadataElement; import org.osmf.smpte.tt.timing.TimeCode; import org.osmf.smpte.tt.timing.TimeContainer; - import org.osmf.smpte.tt.timing.TimeTree; - import org.osmf.smpte.tt.utilities.DictionaryUtils; + import org.osmf.smpte.tt.timing.TreeType; public class SpanElement extends TimedTextElementBase { @@ -53,13 +52,13 @@ package org.osmf.smpte.tt.model if(temporallyActive(tick)) { var block:Inline = new Inline(this); - for each (var child:* in children) + for each (var child:TreeType in children) { var fo:FormattingObject; if (child is BrElement || child is AnonymousSpanElement) { //{ region Add text to the Inline formatting object - fo = (child as TimedTextElementBase).getFormattingObject(tick); + fo = TimedTextElementBase(child).getFormattingObject(tick); if (fo != null) { fo.parent = block; @@ -68,7 +67,7 @@ package org.osmf.smpte.tt.model //{ region copy metadata across to inline, since we want to use this for(var d:* in metadata) { - if (!DictionaryUtils.containsKey(child.metadata,d)) + if (child.metadata[d] === undefined) { child.metadata[d] = metadata[d]; } @@ -79,7 +78,7 @@ package org.osmf.smpte.tt.model else if (child is SpanElement) { //{ region flatten span hierarchy - fo = (child as SpanElement).getFormattingObject(tick); + fo = SpanElement(child).getFormattingObject(tick); if (fo != null) { /* @@ -91,7 +90,7 @@ package org.osmf.smpte.tt.model /// something to watch out for when computing relative /// values though. */ - for each (var nestedInline:* in fo.children) + for each (var nestedInline:TreeType in fo.children) { nestedInline.parent = block; block.children.push(nestedInline); @@ -102,7 +101,7 @@ package org.osmf.smpte.tt.model if (child is SetElement) { //{ region Add animations to Inline - fo = ((child as SetElement).getFormattingObject(tick)) as Animation; + fo = SetElement(child).getFormattingObject(tick) as Animation; if (fo != null) { block.animations.push(fo); @@ -151,46 +150,24 @@ package org.osmf.smpte.tt.model protected override function validElements():void { var child:uint = 0; - - //{ region Allow arbitrary metadata - while ((child < children.length) - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement))) - { - child++; - } - //} endregion - - //{ region Allow arbitrary set elements (Animation class) - while ((child < children.length) - && (children[child] is SetElement)) - { - child++; - } - //} endregion - - //{ region Allow arbitrary span, br and PCDATA (Inline class) - while ((child < children.length) - && ((children[child] is SpanElement) - || (children[child] is BrElement) - || (children[child] is AnonymousSpanElement) - )) - { - child++; - } - //} endregion - - //{ region Ensure no other element present - if (children.length != child) - { - error(children[child] + " is not allowed in " + this + " at position " + child); - } - //} endregion - //{ region Check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement + || element is SetElement + || element is SpanElement + || element is BrElement + || element is AnonymousSpanElement) + { + child++; + element.valid(); + } + else + { + error(element + " is not allowed in " + this + " at position " + (children.length-child)); + continue; + } } //} endregion } diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/StyleElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/StyleElement.as old mode 100755 new mode 100644 index 6359322..4098b7e --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/StyleElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/StyleElement.as @@ -53,28 +53,20 @@ package org.osmf.smpte.tt.model */ protected override function validElements():void { - var child:uint = 0; - - //{ region Allow arbitrary metadata - while ((child < children.length) - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement))) - { - child++; - } - //} endregion - - //{ region Ensure no other element is present - if (children.length != child) - { - error(children[child] + " is not allowed in " + this + " at position " + child); - } - //} endregion - + var child:uint = 0; //{ region Check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement) + { + child++; + element.valid(); + } + else + { + error(element + " is not allowed in " + this + " at position " + (children.length-child)); + } } //} endregion } diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/StylingElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/StylingElement.as old mode 100755 new mode 100644 index 6834efc..e349f15 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/StylingElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/StylingElement.as @@ -20,7 +20,6 @@ package org.osmf.smpte.tt.model { import org.osmf.smpte.tt.model.metadata.MetadataElement; - import org.osmf.smpte.tt.timing.TimeTree; public class StylingElement extends TimedTextElementBase { @@ -45,29 +44,22 @@ package org.osmf.smpte.tt.model protected override function validElements():void { - var child:uint = 0; - - while ((child < children.length) - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement))) - { - child++; - } - while ((child < children.length) - && (children[child] is StyleElement)) - { - child++; - } - - if (children.length != child) - { - error(children[child] + " is not allowed in " + this + " at position " + child); - } - + var child:uint = 0; // now check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement + || element is StyleElement) + { + child++; + element.valid(); + } + else + { + error(element + " is not allowed in " + this + " at position " + (children.length-child)); + continue; + } } } //} endregion diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TimedTextAttributeBase.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TimedTextAttributeBase.as old mode 100755 new mode 100644 index 414a93a..9f07130 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TimedTextAttributeBase.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TimedTextAttributeBase.as @@ -25,12 +25,8 @@ package org.osmf.smpte.tt.model import org.osmf.smpte.tt.styling.FontSize; import org.osmf.smpte.tt.styling.FontStyleAttributeValue; import org.osmf.smpte.tt.styling.FontWeightAttributeValue; - import org.osmf.smpte.tt.styling.LineHeight; - import org.osmf.smpte.tt.styling.NormalHeight; - import org.osmf.smpte.tt.styling.Origin; import org.osmf.smpte.tt.styling.PaddingThickness; import org.osmf.smpte.tt.styling.TextDecorationAttributeValue; - import org.osmf.smpte.tt.styling.TextOutline; import org.osmf.smpte.tt.vocabulary.Namespaces; public class TimedTextAttributeBase @@ -39,141 +35,109 @@ package org.osmf.smpte.tt.model { } - private var _parent:TimedTextElementBase; - public function get parent():TimedTextElementBase - { - return _parent; - } - public function set parent(value:TimedTextElementBase):void - { - _parent = value; - } + public var parent:TimedTextElementBase; - private var _localName:String; - public function get localName():String - { - return _localName; - } - public function set localName(value:String):void - { - _localName = value; - } + public var localName:String; - private var _namespace:Namespace; - public function get namespace():Namespace - { - return _namespace; - } - public function set namespace(value:Namespace):void - { - _namespace = value; - } + public var namespace:Namespace; - private var _value:String; - public function get value():String - { - return _value; - } - public function set value(value:String):void - { - _value = value; - } + public var value:String; public static function getInitialStyle(property:String):Object { var obj:* = ""; switch (property) { - case "backgroundColor": + case "backgroundColor": obj = Colors.Transparent; break; - case "color": + case "color": obj = Colors.White; // spec says transparent break; - case "direction": + case "direction": obj = "auto"; // this is not what the spec says, but we need it to respect writingMode. break; - case "display": + case "display": obj = "auto"; break; - case "displayAlign": + case "displayAlign": obj = "before"; break; - case "dynamicFlow": + case "dynamicFlow": obj = "none"; break; - case "extent": - obj = new AutoExtent(); + case "extent": + obj = AutoExtent.instance; break; - case "fontFamily": + case "fontFamily": obj = "default"; break; - case "fontSize": - obj = new FontSize("1c 1c"); + case "fontSize": + obj = FontSize.getFontSize("1c"); break; - case "fontStyle": + case "fontStyle": obj = FontStyleAttributeValue.REGULAR; break; - case "fontWeight": + case "fontWeight": obj = FontWeightAttributeValue.REGULAR; break; - case "lineHeight": + case "lineHeight": obj = null; // stand in for normal. break; - case "opacity": + case "opacity": obj = 1.0; break; - case "origin": - obj = new AutoOrigin(); + case "origin": + obj = AutoOrigin.instance; break; case "overflow": obj = "hidden"; break; - case "padding": - obj = new PaddingThickness("0px"); + case "padding": + obj = PaddingThickness.getPaddingThickness("0px"); break; - case "showBackground": + case "showBackground": obj = "always"; break; - case "textAlign": + case "textAlign": obj = "start"; break; - case "textDecoration": + case "textDecoration": obj = TextDecorationAttributeValue.NONE; break; - case "textOutline": + case "textOutline": obj = null; // new TextOutline("none"); break; - case "unicodeBidi": + case "unicodeBidi": obj = "undefined"; break; - case "visibility": + case "visibility": obj = "visible"; break; - case "wrapOption": + case "wrapOption": obj = "wrap"; break; - case "writingMode": + case "writingMode": obj = "lrtb"; break; - case "zIndex": + case "zIndex": obj = "auto"; break; // these are defaults for the xml attributes - case "space": + case "space": obj = "default"; break; - case "lang": + case "lang": obj = "en-us"; break; - case "region": + case "region": obj = ""; // this is not a style per se, but we use the same mechanics. break; // the following cases are for internal styles - case "#preserve": + case "#preserve": obj = false; break; default: diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TimedTextElementBase.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TimedTextElementBase.as old mode 100755 new mode 100644 index d3f2d98..bb6076e --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TimedTextElementBase.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TimedTextElementBase.as @@ -25,14 +25,7 @@ package org.osmf.smpte.tt.model import org.osmf.smpte.tt.errors.SMPTETTException; import org.osmf.smpte.tt.formatting.FormattingObject; - import org.osmf.smpte.tt.model.metadata.ActorElement; import org.osmf.smpte.tt.model.metadata.AgentElement; - import org.osmf.smpte.tt.model.metadata.CopyrightElement; - import org.osmf.smpte.tt.model.metadata.DescElement; - import org.osmf.smpte.tt.model.metadata.NameElement; - import org.osmf.smpte.tt.model.metadata.TitleElement; - import org.osmf.smpte.tt.model.parameter.ExtensionElement; - import org.osmf.smpte.tt.model.parameter.FeatureElement; import org.osmf.smpte.tt.model.parameter.ParameterElement; import org.osmf.smpte.tt.styling.AutoExtent; import org.osmf.smpte.tt.styling.AutoOrigin; @@ -67,65 +60,17 @@ package org.osmf.smpte.tt.model } //{ region Properties - private var _language:String; - public function get language():String - { - return _language; - } - public function set language(value:String):void - { - _language = value; - } + public var language:String; - private var _localName:String; - public function get localName():String - { - return _localName; - } - public function set localName(value:String):void - { - _localName = value; - } + public var localName:String; - private var _namespace:Namespace; - public function get namespace():Namespace - { - return _namespace; - } - public function set namespace(value:Namespace):void - { - _namespace = value; - } + public var namespace:Namespace; - private var _body:BodyElement; - public function get body():BodyElement - { - return _body; - } - public function set body(value:BodyElement):void - { - _body = value; - } + public var body:BodyElement; - private var _id:String; - public function get id():String - { - return _id; - } - public function set id(value:String):void - { - _id = value; - } + public var id:String; - private var _root:TtElement; - public function get root():TtElement - { - return _root; - } - public function set root(value:TtElement):void - { - _root = value; - } + public var root:TtElement; //} endregion //{ region Local members @@ -155,7 +100,7 @@ package org.osmf.smpte.tt.model */ public static function getElementFromName(elem:String):TimedTextElementBase { - var ClassReference:Class = flash.utils.getDefinitionByName(elem) as Class; + var ClassReference:Class = getDefinitionByName(elem) as Class; if (ClassReference != null) { @@ -244,35 +189,36 @@ package org.osmf.smpte.tt.model var styleCount:uint = DictionaryUtils.getLength(_styling); // check for local override, this will always win - if (styleCount > 0 && DictionaryUtils.containsKey(_styling,property)) + if (styleCount > 0 && _styling[property] !== undefined) { return _styling[property]; } // find out if we refer to any other styles. - if (styleCount > 0 && DictionaryUtils.containsKey(_styling,"style")) + var referentStyles:Vector. = _styling["style"] as Vector.; + if (styleCount > 0 && referentStyles) { - - var referentStyles:Vector. = _styling["style"] as Vector.; - if (referentStyles == null || referentStyles.length == 0) { _styling[property] = null; return null; } // recursively check them in reverse order. - for (var i:int = referentStyles.length - 1; i >= 0; i--) + var i:int = referentStyles.length - 1; + while (i >= 0) { var s:String = referentStyles[i]; - if (DictionaryUtils.containsKey(root.styles,s)) + var styleElement:StyleElement = root.styles[s] as StyleElement; + if (styleElement) { - var result:* = (root.styles[s] as StyleElement).getReferentStyle(property); + var result:* = styleElement.getReferentStyle(property); if (result != null) { _styling[property] = result; return result; } } + i--; } } @@ -314,7 +260,7 @@ package org.osmf.smpte.tt.model public function getInheritedStyle(propertyName:String, currentRegion:RegionElement):Object { var isBodyElement:Boolean = (this is BodyElement); - var canInherit:Boolean = !(isBodyElement) && !(this is RegionElement); + var canInherit:Boolean = !isBodyElement && !(this is RegionElement); // we don't want the same background colors to to be // inherited by a container element and an inline element. @@ -325,7 +271,7 @@ package org.osmf.smpte.tt.model if (parent != null && canInherit) { - return (parent as TimedTextElementBase).getComputedStyle(propertyName, currentRegion); + return TimedTextElementBase(parent).getComputedStyle(propertyName, currentRegion); } if (isBodyElement && currentRegion != null) { // body needs to inherit from the region it has been parented to @@ -385,17 +331,6 @@ package org.osmf.smpte.tt.model : new Namespace(a.namespace.prefix,a.namespace.uri); writer.@aNS::[a.localName] = a.value; } - var ns:Namespace = new Namespace( writer.namespace().uri ); - if(begin){ - writer.@ns::begin = begin.toString(); - } - if(duration){ - writer.@ns::dur = duration.toString(); - } - if(end){ - writer.@ns::end = end.toString(); - } - } public function serialize():String @@ -662,7 +597,7 @@ package org.osmf.smpte.tt.model case "http://www.w3.org/ns/ttml/profile/dfxp-transformation": for each (f in ParameterElement.transformProfile) { - if (!DictionaryUtils.containsKey(ParameterElement.features, f.key)) + if (ParameterElement.features[f.key] !== undefined) { // if local profile has added this, then dont over-ride it ParameterElement.features[f.key] = f.value; } @@ -671,7 +606,7 @@ package org.osmf.smpte.tt.model case "http://www.w3.org/ns/ttml/profile/dfxp-presentation": for each (f in ParameterElement.presentationProfile) { - if (!DictionaryUtils.containsKey(ParameterElement.features, f.key)) + if (ParameterElement.features[f.key] !== undefined) { // if local profile has added this, then dont over-ride it ParameterElement.features[f.key] = f.value; } @@ -680,14 +615,14 @@ package org.osmf.smpte.tt.model case "http://www.w3.org/ns/ttml/profile/dfxp-full": for each (f in ParameterElement.presentationProfile) { - if (!DictionaryUtils.containsKey(ParameterElement.features, f.key)) + if (ParameterElement.features[f.key] !== undefined) { // if local profile has added this, then dont over-ride it ParameterElement.features[f.key] = f.value; } } for each (f in ParameterElement.transformProfile) { - if (!DictionaryUtils.containsKey(ParameterElement.features, f.key)) + if (ParameterElement.features[f.key] !== undefined) { // if local profile has added this, then dont over-ride it ParameterElement.features[f.key] = f.value; } @@ -751,7 +686,8 @@ package org.osmf.smpte.tt.model // we should do a pattern match to ensure its legal. var idrefs:Vector. = new Vector.(); var whitespace:String = " "; - for each (var s:String in attribute.value.split(whitespace)) + var attributeArray:Array = attribute.value.split(whitespace); + for each (var s:String in attributeArray) { // to do - what we want to do here is check it's in m_styles; however that won't work for // forward references in styling; can we get a spec restriction here?. @@ -801,7 +737,7 @@ package org.osmf.smpte.tt.model private function validAttributeValue(matchExpression:String, attribute:TimedTextAttributeBase):Boolean { var matchRE:RegExp; - if (DictionaryUtils.containsKey(cachedRegex, matchExpression)) + if (cachedRegex[matchExpression]) { matchRE = cachedRegex[matchExpression]; } @@ -862,11 +798,11 @@ package org.osmf.smpte.tt.model case "extent": if (value == "auto") { - _styling[attribute.localName] = new AutoExtent(); + _styling[attribute.localName] = AutoExtent.instance; } else { - _styling[attribute.localName] = new Extent(value); + _styling[attribute.localName] = Extent.getExtent(value); }; break; case "fontFamily": @@ -882,9 +818,9 @@ package org.osmf.smpte.tt.model case "fontSize": if(validAttributeValue(s_fontSizeExpression, attribute)) { - _styling["fontSize"] = new FontSize(value); + _styling["fontSize"] = FontSize.getFontSize(value); } else { - _styling["fontSize"] = new FontSize("1c 1c"); + _styling["fontSize"] = FontSize.getFontSize("1c"); } break; case "fontStyle": @@ -921,8 +857,8 @@ package org.osmf.smpte.tt.model { _styling["lineHeight"] = (value=="normal") - ? new NormalHeight() - : new LineHeight(value); + ? NormalHeight.instance + : LineHeight.getLineHeight(value); } break; case "opacity": @@ -935,13 +871,13 @@ package org.osmf.smpte.tt.model switch (value) { case "auto": - _styling["origin"] = new AutoOrigin(); + _styling["origin"] = AutoOrigin.instance; break; case "inherit": _styling["origin"] = new Inherit(); break; default: - _styling["origin"] = new Origin(value); + _styling["origin"] = Origin.getOrigin(value); break; }; break; @@ -951,7 +887,7 @@ package org.osmf.smpte.tt.model case "padding": if (validAttributeValue(s_paddingExpression, attribute)) { - _styling["padding"] = new PaddingThickness(value); + _styling["padding"] = PaddingThickness.getPaddingThickness(value); } break; case "showBackground": @@ -963,29 +899,31 @@ package org.osmf.smpte.tt.model case "textDecoration": if (validAttributeValue(s_textDecorationExpression, attribute)) { - switch (value) - { //underline | noUnderline ] || [ lineThrough | noLineThrough ] || [ overline | noOverline - case "underline": - _styling["textDecoration"] = TextDecorationAttributeValue.UNDERLINE; - break; - case "noUnderline": - _styling["textDecoration"] = TextDecorationAttributeValue.NO_UNDERLINE; - break; - case "lineThrough": - _styling["textDecoration"] = TextDecorationAttributeValue.LINE_THROUGH; - break; - case "noLineThrough": - _styling["textDecoration"] = TextDecorationAttributeValue.NO_LINE_THROUGH; - break; - case "overline": - _styling["textDecoration"] = TextDecorationAttributeValue.OVERLINE; - break; - case "noOverline": - _styling["textDecoration"] = TextDecorationAttributeValue.NO_OVERLINE; - break; - default: - _styling["textDecoration"] = TextDecorationAttributeValue.NONE; - break; + var matchRE:RegExp = new RegExp(s_textDecorationExpression,"g"); + var result:Array = matchRE.exec(value); + + while (result != null) + { + switch(result.toString()) + { + case TextDecorationAttributeValue.UNDERLINE.value: + _styling["textDecoration"] = TextDecorationAttributeValue.UNDERLINE; + break; + case TextDecorationAttributeValue.NO_UNDERLINE.value: + _styling["textDecoration"] = TextDecorationAttributeValue.NO_UNDERLINE; + break; + case TextDecorationAttributeValue.LINE_THROUGH.value: + _styling["lineThrough"] = TextDecorationAttributeValue.LINE_THROUGH; + break; + case TextDecorationAttributeValue.NO_LINE_THROUGH.value: + _styling["lineThrough"] = TextDecorationAttributeValue.NO_LINE_THROUGH; + break; + case TextDecorationAttributeValue.NONE.value: + _styling["textDecoration"] = TextDecorationAttributeValue.NONE; + break; + } + + result = matchRE.exec(value); } } break; @@ -1090,12 +1028,12 @@ package org.osmf.smpte.tt.model case "thought": case "title": case "transcription": - this.metadata[attribute.localName] = attribute.value; + metadata[attribute.localName] = attribute.value; break; default: if (attribute.value.indexOf("x-")==0) { - this.metadata[attribute.localName] = attribute.value; + metadata[attribute.localName] = attribute.value; } else { @@ -1111,316 +1049,14 @@ package org.osmf.smpte.tt.model } //} endregion - //{ region Parsing - /** - * Convert an XML object to the internal TimedText classes. - * - * @param timedTextData Raw XML construct - * @returns Timed text Element hierachy - */ - public static function parse(timedTextData:XML):TimedTextElementBase - { - TimedTextElementBase.initializeDefaults(); - - var tteb:TimedTextElementBase; - tteb = TimedTextElementBase.parseRecursive(timedTextData, null, false); - return tteb; - } - /** - * Initialise all the components for this parse - */ - private static function initializeDefaults():void - { - TimeExpression.initializeParameters(); - ParameterElement.initializeParameters(); - } - /** - * Convert an XML object to the internal TimedText classes. - * - * @param timedTextData Raw XML construct - * @param root root element of the tree - * @returns tt_element hierachy - */ - private static function parseRecursive(xmlElement:XML, root:TtElement, preserveContext:Boolean):TimedTextElementBase - { - if(root==null){ - if(xmlElement.namespace().uri.match(/^http\:\/\/www.w3.org\/2006\/(?:02|04|10)\/ttaf1/)){ - Namespaces.useLegacyNamespace(xmlElement.namespace()); - } - } - - var element:String = xmlElement.localName(); - - var nameSpace:String = namespaceFromTimedTextNamespace(xmlElement.namespace().uri); - - var parentNode:TimedTextElementBase = null; - - if (!(!nameSpace || nameSpace.length==0)) - { - // To meet naming conventions, have to manipulate the name. - var conventionName:String = StringUtils.capitalize(element) + "Element"; - - // if there is a namespace, then its a timed text element - parentNode = TimedTextElementBase.getElementFromName(nameSpace + conventionName); - parentNode.localName = element; - parentNode.namespace = xmlElement.namespace(); - } - - /// if node is still null, either we failed to implement the element - /// or its an element in a foreign namespace, either way we bail. - if (parentNode == null) return null; - - //{ region test if root element - var newRoot:TtElement = (root == null) ? parentNode as TtElement : root; - - // null should only occur in the first call, - if (newRoot == null) - { - error("tt not at root of document"); - } - parentNode.root = newRoot; - //} endregion - - var localPreserve:Boolean = preserveContext; // record whether xml:space=preserve is in effect - - //{ region process raw xml attributes into timed text equivalents - for each (var xmlAttribute:XML in xmlElement.attributes()) - { - // copy the attribute identity - var attribute:TimedTextAttributeBase = new TimedTextAttributeBase(); - attribute.parent = parentNode as TimedTextElementBase;; - attribute.localName = xmlAttribute.localName(); - attribute.value = xmlAttribute; - - // not sure if it is absolutely correct to move - // empty namespace elements into tt namespace but seems - // to work. - attribute.namespace = (!xmlAttribute.namespace()) ? xmlElement.namespace() : xmlAttribute.namespace(); - - if(!attribute.namespace.uri && attribute.parent.namespace) { - attribute.namespace = attribute.parent.namespace; - } - - // attach new attribute to current element - parentNode.attributes.push(attribute); - - // check whether we are changing the space preserve behaviour - if (attribute.isXmlAttribute() && attribute.localName == "space") - { - localPreserve = (attribute.value == "preserve"); - } - // record the type of preservation as a local style. - parentNode.setLocalStyle("preserve", localPreserve); - - //trace("\t"+attribute.namespace+":"+attribute.localName+"="+attribute.value); - } - //} endregion - - //{ region process child elements - for each (var xmlNode:XML in xmlElement.children()) - { - parseChild( - { - xmlNode:xmlNode, - parentNode:parentNode, - newRoot:newRoot, - localPreserve:localPreserve - } - ); - } - //} endregion - return parentNode; - } - - private static function parseChild(obj:Object):void { - - var xmlNode:XML = obj.xmlNode, - parentNode:TimedTextElementBase = obj.parentNode, - newRoot:TtElement = obj.newRoot, - localPreserve:Boolean = obj.localPreserve; - - switch(xmlNode.nodeKind()) - { - //text, comment, processing-instruction, attribute, or element. - case "element": - - //{ region convert XML Element to Timed Text Element - var child:TimedTextElementBase = parseRecursive(xmlNode, newRoot, localPreserve); - if (child != null) - { - parentNode.children.push(child as TreeType); - - if (child is BodyElement) - { - parentNode.body = child as BodyElement; - } - if (parentNode is TtElement) - { - var ttElement:TtElement = parentNode as TtElement; - if (child is HeadElement) - { - ttElement.head = child as HeadElement; - } - } - - child.parent = parentNode; - child.root = parentNode.root; - } - //} endregion - break; - - case "text": - - //{ region convert XML Text into an anonymous span element - if (isContentElement(parentNode)) - { - //{ region elements that admit PCDATA as children get anonymous spans - var text:AnonymousSpanElement; - if (!localPreserve) - { // squeeze out all the redundant whitespace - var normalized:String = normalizeWhitespace(xmlNode); - text = new AnonymousSpanElement(normalized); - } - else - { - // preserve the raw text as it came in - text = new AnonymousSpanElement(xmlNode.toString()); - } - parentNode.children.push(text as TreeType); - text.parent = parentNode; - if(!isMetadataContentElement(parentNode) - && !isParameterContentElement(parentNode)) - { - parentNode.root.totalNodeCount++; - } - //} endregion - } - else - { - //{ region test non content element for non-whitespace error. - if (normalizeWhitespace(xmlNode) != " ") - { - error("Use of non whitespace in " + parentNode); - } - //} endregion - } - //} endregion - break; - - } - } - //{ region Helper Methods - /** - * convert newlines to space, and collpase runs of space to a single space - * - * @param n - */ - private static function normalizeWhitespace(n:XML):String - { - var normalized:String = n.normalize().toString().replace(/[\n\r\t]/g, " "); - while (/\ {2}/g.test(normalized)) - { - normalized = normalized.replace(/\ {2}/g, " "); - } - return normalized; - } - /** - * Is it a content element for purposes of parenting anonymous span's? - * - * @param node - */ - private static function isContentElement(node:TimedTextElementBase):Boolean - { - if (node is PElement) return true; - if (node is SpanElement) return true; - if (isMetadataContentElement(node)) return true; - if (isParameterContentElement(node)) return true; - return false; - } - - /** - * Metadata items that admit PCDATA as content - * - * @param node - */ - private static function isMetadataContentElement(node:TimedTextElementBase):Boolean - { - if (node is TitleElement) return true; - if (node is NameElement) return true; - if (node is DescElement) return true; - if (node is CopyrightElement) return true; - if (node is AgentElement) return true; - if (node is ActorElement) return true; - - return false; - } - /** - * Parameter items that admit PCDATA as content - * - * @param node - */ - private static function isParameterContentElement(node:TimedTextElementBase):Boolean - { - if (node is ExtensionElement) return true; - if (node is FeatureElement) return true; - return false; - } - //} endregion + - //{ region Namespace Handling - /** - * Get the local AS3 namespace from the Timed Text XML namespace - * @param pXML namespace - * @returns as3 namespace prefix as a string - */ - private static function namespaceFromTimedTextNamespace(p:String):String - { - var nsPrefix:String = ""; - switch (p) - { // got to be a better way to do this using reflection? - case "http://www.w3.org/2006/02/ttaf1": - case "http://www.w3.org/2006/04/ttaf1": - case "http://www.w3.org/2006/10/ttaf1": - case "http://www.w3.org/ns/ttml": - nsPrefix = "org.osmf.smpte.tt.model."; - break; - case "http://www.w3.org/2006/02/ttaf1#metadata": - case "http://www.w3.org/2006/04/ttaf1#metadata": - case "http://www.w3.org/2006/10/ttaf1#metadata": - case "http://www.w3.org/ns/ttml#metadata": - nsPrefix = "org.osmf.smpte.tt.model.metadata."; - break; - case "http://www.w3.org/2006/02/ttaf1#style": - case "http://www.w3.org/2006/02/ttaf1#styling": - case "http://www.w3.org/2006/04/ttaf1#style": - case "http://www.w3.org/2006/04/ttaf1#styling": - case "http://www.w3.org/2006/10/ttaf1#style": - case "http://www.w3.org/2006/10/ttaf1#styling": - case "http://www.w3.org/ns/ttml#styling": - nsPrefix = "org.osmf.smpte.tt.styling."; - break; - case "http://www.w3.org/2006/02/ttaf1#parameter": - case "http://www.w3.org/2006/04/ttaf1#parameter": - case "http://www.w3.org/2006/10/ttaf1#parameter": - case "http://www.w3.org/ns/ttml#parameter": - nsPrefix = "org.osmf.smpte.tt.model.parameter."; - break; - case "http://www.w3.org/ns/ttml/profile": - nsPrefix = "org.osmf.smpte.tt.model.parameter."; - break; - default: - nsPrefix = ""; - break; - } - return nsPrefix; - } - //} endregion /** * Get recorded metadata for the given attribute @@ -1429,9 +1065,9 @@ package org.osmf.smpte.tt.model */ public function getMetadata(attribute:String):String { - if (DictionaryUtils.containsKey(metadata,attribute)) + if (metadata[attribute] !== undefined) { - return this.metadata[attribute] as String; + return metadata[attribute] as String; } else { diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TtElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TtElement.as old mode 100755 new mode 100644 index 97e1b5a..823f65c --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TtElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/TtElement.as @@ -1,323 +1,299 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.model -{ - import flash.sampler.NewObjectSample; - import flash.utils.Dictionary; - - import flashx.textLayout.formats.TextAlign; - - import org.osmf.smpte.tt.formatting.Animation; - import org.osmf.smpte.tt.formatting.BlockContainer; - import org.osmf.smpte.tt.formatting.Flow; - import org.osmf.smpte.tt.formatting.FormattingObject; - import org.osmf.smpte.tt.formatting.Root; - import org.osmf.smpte.tt.styling.ColorExpression; - import org.osmf.smpte.tt.styling.Colors; - import org.osmf.smpte.tt.styling.Extent; - import org.osmf.smpte.tt.styling.FontSize; - import org.osmf.smpte.tt.styling.LineHeight; - import org.osmf.smpte.tt.styling.Origin; - import org.osmf.smpte.tt.styling.PaddingThickness; - import org.osmf.smpte.tt.timing.TimeCode; - import org.osmf.smpte.tt.utilities.DictionaryUtils; - - public class TtElement extends TimedTextElementBase - { - public function TtElement() - { - super(); - _parameters = new Dictionary(); - _styles = new Dictionary(); - _agents = new Dictionary(); - _regions = new Dictionary(); - } - - private var _head:HeadElement; - public function get head():HeadElement - { - return _head; - } - public function set head(value:HeadElement):void - { - _head = value; - } - - private var _body:BodyElement; - public override function get body():BodyElement - { - return _body; - } - public override function set body(value:BodyElement):void - { - _body = value; - } - - private var _regions:Dictionary; - public function get regions():Dictionary - { - return _regions; - } - public function set regions(value:Dictionary):void - { - _regions = value; - } - - private var _agents:Dictionary; - public function get agents():Dictionary - { - return _agents; - } - public function set agents(value:Dictionary):void - { - _agents = value; - } - - private var _styles:Dictionary; - public function get styles():Dictionary - { - return _styles; - } - public function set styles(value:Dictionary):void - { - _styles = value; - } - - private var _parameters:Dictionary; - public function get parameters():Dictionary - { - return _parameters; - } - public function set parameters(value:Dictionary):void - { - _parameters = value; - } - - private var _totalNodeCount:int = 0; - public function get totalNodeCount():int - { - return _totalNodeCount; - } - public function set totalNodeCount(value:int):void - { - _totalNodeCount = value; - } - - - /** - * return the root formatting object - * @param regionId - * @param tick - */ - public override function getFormattingObject(tick:TimeCode):FormattingObject - { - // if there is no body. then empty regions would be pruned - // see 9.3.3. part 5. map each non-empty region element to - // an fo:block-container element... - if (body == null) return null; - if (!body.temporallyActive(tick)) return null; - - //region create single root and flow for the document. - var root:Root = new Root(this) - var flow:Flow = new Flow(null); - flow.parent = root; - root.children.push(flow); - //endregion - - //region add a block container to the flow for each temporally active region - for each (var region:RegionElement in DictionaryUtils.getValues(regions)) - { - if (region.temporallyActive(tick)) - { - var blockContainer:BlockContainer = region.getFormattingObject(tick) as BlockContainer; - //region apply animations on regions - for each (var child:TimedTextElementBase in region.children) - { - { - var fo:FormattingObject = (child as SetElement).getFormattingObject(tick); - if (fo is Animation) - { - blockContainer.animations.push(fo as Animation); - } - } - } - //endregion - - blockContainer.parent = flow; - flow.children.push(blockContainer); - - /// region create a new subtree for the body element - /// select it into this region by adding its children - /// to block container - var block:FormattingObject = body.getFormattingObject(tick); - if (block != null) - { - block.prune(region.id); // deselect any content not for this region - if (block.children.length > 0) - { - if (block.children[0].children.length > 0) - { - blockContainer.children.push(block); - block.parent = blockContainer; - } - } - } - //endregion - } - } - //endregion - return root; - } - - //{ region validity - /* - - Content: head?, body? - - */ - - /** - * Check tt element attribute validity - */ - protected override function validAttributes():void - { - validateAttributes(true, false, false, false, false, false); - - if (language == null) - { - error("TT element must specify xml:lang attribute "); - } - } - - /** - * Check tt element validity - */ - protected override function validElements():void - { - - - var isValid:Boolean = true; - // we need an extra check to validate the root attributes in order - // to ensure parameters are parsed. - validAttributes(); - //{ region check this elements model - switch (children.length) - { - case 0: - return; - break; - case 1: - - //{ region test if child element is head or body - if (children[0] is HeadElement) - { - _head = children[0] as HeadElement; - isValid = true; - } - else if (children[0] is BodyElement) - { - _body = children[0] as BodyElement; - _head = new HeadElement(); - children.length = 0; - children.push(_head); - children.push(_body); - isValid = true; - } - else - { - isValid = false; - } - //} endregion - - break; - case 2: - - - - //{ region Check first child is head, and second is body - if (children[0] is HeadElement) - { - _head = children[0] as HeadElement; - } - if (children[1] is BodyElement) - { - _body = children[1] as BodyElement; - } - - isValid = (_body != null && _head != null); - //} endregion - - break; - default: - //{ region Cannot be valid - isValid = false; - //} endregion - break; - } - //} endregion - - if (!isValid) - { - error("erroneous child in " + this); - } - - - //{ region now check each of the children is individually valid - for each (var element:TimedTextElementBase in children) - { - element.valid(); - } - //} endregion - - //{ region Add default region if none was specified - if (isValid && DictionaryUtils.getLength(regions) < 1) - { - - var defaultLayout:LayoutElement = new LayoutElement(); - defaultLayout.localName = "layout"; - defaultLayout.namespace = _head.namespace; - - _head.children.push(defaultLayout); - defaultLayout.parent = _head; - var defaultRegion:RegionElement = new RegionElement(); - defaultRegion.id = RegionElement.DEFAULT_REGION_NAME; - defaultRegion.setLocalStyle("backgroundColor",new ColorExpression(0,0.75)); - defaultRegion.setLocalStyle("color", Colors.White); - defaultRegion.setLocalStyle("textAlign",TextAlign.CENTER); - defaultRegion.setLocalStyle("fontFamily","_sans"); - defaultRegion.setLocalStyle("fontSize", new FontSize("1c 1c")); - defaultRegion.setLocalStyle("extent",new Extent("100% 10%")); - defaultRegion.setLocalStyle("origin",new Origin("0% 90%")); - defaultRegion.setLocalStyle("padding",new PaddingThickness("2px 10%")); - defaultLayout.children.push(defaultRegion); - defaultRegion.parent = defaultLayout; - root.regions[defaultRegion.id] = defaultRegion; - } - //} endregion - } - //} endregion - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.model +{ + import flash.sampler.NewObjectSample; + import flash.utils.Dictionary; + + import flashx.textLayout.formats.TextAlign; + + import org.osmf.smpte.tt.formatting.Animation; + import org.osmf.smpte.tt.formatting.BlockContainer; + import org.osmf.smpte.tt.formatting.Flow; + import org.osmf.smpte.tt.formatting.FormattingObject; + import org.osmf.smpte.tt.formatting.Root; + import org.osmf.smpte.tt.styling.ColorExpression; + import org.osmf.smpte.tt.styling.Colors; + import org.osmf.smpte.tt.styling.Extent; + import org.osmf.smpte.tt.styling.FontSize; + import org.osmf.smpte.tt.styling.LineHeight; + import org.osmf.smpte.tt.styling.Origin; + import org.osmf.smpte.tt.styling.PaddingThickness; + import org.osmf.smpte.tt.timing.TimeCode; + import org.osmf.smpte.tt.utilities.DictionaryUtils; + + public class TtElement extends TimedTextElementBase + { + public function TtElement() + { + super(); + _parameters = new Dictionary(); + _styles = new Dictionary(); + _agents = new Dictionary(); + _regions = new Dictionary(); + } + + public var head:HeadElement; + + private var _regions:Dictionary; + public function get regions():Dictionary + { + return _regions; + } + public function set regions(value:Dictionary):void + { + _regions = value; + } + + private var _agents:Dictionary; + public function get agents():Dictionary + { + return _agents; + } + public function set agents(value:Dictionary):void + { + _agents = value; + } + + private var _styles:Dictionary; + public function get styles():Dictionary + { + return _styles; + } + public function set styles(value:Dictionary):void + { + _styles = value; + } + + private var _parameters:Dictionary; + public function get parameters():Dictionary + { + return _parameters; + } + public function set parameters(value:Dictionary):void + { + _parameters = value; + } + + private var _totalNodeCount:int = 0; + public function get totalNodeCount():int + { + return _totalNodeCount; + } + public function set totalNodeCount(value:int):void + { + _totalNodeCount = value; + } + + /** + * return the root formatting object + * @param regionId + * @param tick + */ + public override function getFormattingObject(tick:TimeCode):FormattingObject + { + // if there is no body. then empty regions would be pruned + // see 9.3.3. part 5. map each non-empty region element to + // an fo:block-container element... + if (body == null) return null; + if (!body.temporallyActive(tick)) return null; + + //region create single root and flow for the document. + var root:Root = new Root(this) + var flow:Flow = new Flow(null); + flow.parent = root; + root.children.push(flow); + //endregion + + //region add a block container to the flow for each temporally active region + for each (var region:RegionElement in regions) + { + if (region.temporallyActive(tick)) + { + var blockContainer:BlockContainer = region.getFormattingObject(tick) as BlockContainer; + //region apply animations on regions + for each (var child:TimedTextElementBase in region.children) + { + { + var fo:FormattingObject = SetElement(child).getFormattingObject(tick); + if (fo is Animation) + { + blockContainer.animations.push(fo as Animation); + } + } + } + //endregion + + blockContainer.parent = flow; + flow.children.push(blockContainer); + + /// region create a new subtree for the body element + /// select it into this region by adding its children + /// to block container + var block:FormattingObject = body.getFormattingObject(tick); + if (block != null) + { + block.prune(region.id); // deselect any content not for this region + if (block.children.length > 0) + { + if (block.children[0].children.length > 0) + { + blockContainer.children.push(block); + block.parent = blockContainer; + } + } + } + //endregion + } + } + //endregion + return root; + } + + //{ region validity + /* + + Content: head?, body? + + */ + + /** + * Check tt element attribute validity + */ + protected override function validAttributes():void + { + validateAttributes(true, false, false, false, false, false); + + if (language == null) + { + error("TT element must specify xml:lang attribute "); + } + } + + /** + * Check tt element validity + */ + protected override function validElements():void + { + var isValid:Boolean = true; + // we need an extra check to validate the root attributes in order + // to ensure parameters are parsed. + validAttributes(); + //{ region check this elements model + switch (children.length) + { + case 0: + return; + break; + case 1: + + //{ region test if child element is head or body + if (children[0] is HeadElement) + { + head = children[0] as HeadElement; + isValid = true; + } + else if (children[0] is BodyElement) + { + body = children[0] as BodyElement; + head = new HeadElement(); + children.length = 0; + children.push(head); + children.push(body); + isValid = true; + } + else + { + isValid = false; + } + //} endregion + + break; + case 2: + + //{ region Check first child is head, and second is body + if (children[0] is HeadElement) + { + head = children[0] as HeadElement; + } + if (children[1] is BodyElement) + { + body = children[1] as BodyElement; + } + + isValid = (body != null && head != null); + //} endregion + + break; + default: + //{ region Cannot be valid + isValid = false; + //} endregion + break; + } + //} endregion + + if (!isValid) + { + error("erroneous child in " + this); + } + + //{ region now check each of the children is individually valid + for each (var element:TimedTextElementBase in children) + { + element.valid(); + } + //} endregion + + //{ region Add default region if none was specified + if (isValid && DictionaryUtils.getLength(regions) < 1) + { + + var defaultLayout:LayoutElement = new LayoutElement(); + defaultLayout.localName = "layout"; + defaultLayout.namespace = head.namespace; + + head.children.push(defaultLayout); + defaultLayout.parent = head; + var defaultRegion:RegionElement = new RegionElement(); + defaultRegion.id = RegionElement.DEFAULT_REGION_NAME; + defaultRegion.setLocalStyle("backgroundColor",new ColorExpression(0,0.75)); + defaultRegion.setLocalStyle("color", Colors.White); + defaultRegion.setLocalStyle("textAlign",TextAlign.CENTER); + defaultRegion.setLocalStyle("fontFamily","_sans"); + defaultRegion.setLocalStyle("fontSize", FontSize.getFontSize("1c")); + defaultRegion.setLocalStyle("extent", Extent.getExtent("100% 10%")); + defaultRegion.setLocalStyle("origin", Origin.getOrigin("0% 90%")); + defaultRegion.setLocalStyle("padding",new PaddingThickness("2px 10%")); + defaultLayout.children.push(defaultRegion); + defaultRegion.parent = defaultLayout; + root.regions[defaultRegion.id] = defaultRegion; + } + //} endregion + } + //} endregion + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/ActorElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/ActorElement.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/AgentElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/AgentElement.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/CopyrightElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/CopyrightElement.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/DescElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/DescElement.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/MetadataElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/MetadataElement.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/NameElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/NameElement.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/TitleElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/metadata/TitleElement.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ExtensionElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ExtensionElement.as old mode 100755 new mode 100644 index 7e7f735..1488b15 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ExtensionElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ExtensionElement.as @@ -19,12 +19,8 @@ **********************************************************/ package org.osmf.smpte.tt.model.parameter { - import org.osmf.smpte.tt.errors.SMPTETTException; import org.osmf.smpte.tt.model.AnonymousSpanElement; import org.osmf.smpte.tt.model.TimedTextAttributeBase; - import org.osmf.smpte.tt.model.TimedTextElementBase; - import org.osmf.smpte.tt.timing.TimeTree; - import org.osmf.smpte.tt.utilities.DictionaryUtils; public class ExtensionElement extends ParameterElement { @@ -69,17 +65,21 @@ package org.osmf.smpte.tt.model.parameter { var child:uint = 0; var sb:String = ""; - while (child < children.length - && (children[child] is AnonymousSpanElement)) + var childElement:AnonymousSpanElement + while (child < children.length) { - sb += ((children[child] as AnonymousSpanElement).text); - child++; + childElement = children[child] as AnonymousSpanElement; + if(childElement) + { + sb += childElement.text; + child++; + } } text = sb; if (children.length != child) { - error(children[child] + " is not allowed in " + this + " at position " + child); + error(childElement + " is not allowed in " + this + " at position " + child); } } } diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ExtensionsElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ExtensionsElement.as old mode 100755 new mode 100644 index 72d4527..564085e --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ExtensionsElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ExtensionsElement.as @@ -62,24 +62,21 @@ package org.osmf.smpte.tt.model.parameter protected override function validElements():void { var child:int = 0; - - while (child < children.length - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement) - || (children[child] is ExtensionElement))) - { - child++; - } - - if (children.length != child) - { - error(children[child] + " is not allowed in " + this + " at position " + child); - } - - // now check each of the children is individually valid + // check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement + || element is ExtensionElement) + { + child++; + element.valid(); + } + else + { + error(element + " is not allowed in " + this + " at position " + (children.length-child)); + continue; + } } } } diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeatureElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeatureElement.as old mode 100755 new mode 100644 index 99c2947..3f33545 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeatureElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeatureElement.as @@ -19,12 +19,8 @@ **********************************************************/ package org.osmf.smpte.tt.model.parameter { - import org.osmf.smpte.tt.errors.SMPTETTException; import org.osmf.smpte.tt.model.AnonymousSpanElement; import org.osmf.smpte.tt.model.TimedTextAttributeBase; - import org.osmf.smpte.tt.model.TimedTextElementBase; - import org.osmf.smpte.tt.timing.TimeTree; - import org.osmf.smpte.tt.utilities.DictionaryUtils; public class FeatureElement extends ParameterElement { @@ -68,11 +64,15 @@ package org.osmf.smpte.tt.model.parameter { var child:uint = 0; var sb:String = ""; - while (child < children.length - && (children[child] is AnonymousSpanElement)) + var childElement:AnonymousSpanElement; + while (child < children.length) { - sb += ((children[child] as AnonymousSpanElement).text); - child++; + childElement = children[child] as AnonymousSpanElement; + if(childElement) + { + sb += childElement.text; + child++; + } } text = sb; diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeatureValue.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeatureValue.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeaturesElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeaturesElement.as old mode 100755 new mode 100644 index aa7a94d..8dae47a --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeaturesElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/FeaturesElement.as @@ -19,13 +19,10 @@ **********************************************************/ package org.osmf.smpte.tt.model.parameter { - import org.osmf.smpte.tt.errors.SMPTETTException; import org.osmf.smpte.tt.model.MetadataElement; import org.osmf.smpte.tt.model.TimedTextAttributeBase; import org.osmf.smpte.tt.model.TimedTextElementBase; import org.osmf.smpte.tt.model.metadata.MetadataElement; - import org.osmf.smpte.tt.timing.TimeTree; - import org.osmf.smpte.tt.utilities.DictionaryUtils; public class FeaturesElement extends ParameterElement { @@ -59,24 +56,21 @@ package org.osmf.smpte.tt.model.parameter protected override function validElements():void { var child:uint = 0; - - while (child < children.length - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement) - || (children[child] is FeatureElement))) - { - child++; - } - - if (children.length != child) - { - error(children[child] + " is not allowed in " + this + " at position " + child); - } - - // now check each of the children is individually valid + // check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement + || element is FeatureElement) + { + child++; + element.valid(); + } + else + { + error(element + " is not allowed in " + this + " at position " + (children.length-child)); + continue; + } } } } diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ParameterElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ParameterElement.as old mode 100755 new mode 100644 index 1959d80..dd3f600 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ParameterElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ParameterElement.as @@ -107,7 +107,7 @@ package org.osmf.smpte.tt.model.parameter case "value": if (feature) { - if (DictionaryUtils.containsKey(ParameterElement.features,key)) + if (ParameterElement.features[key] !== undefined) { valInt = ParameterElement.features[key] as int; valInt |= int(attribute.value == "required"); @@ -120,7 +120,7 @@ package org.osmf.smpte.tt.model.parameter } else { - if (DictionaryUtils.containsKey(ParameterElement.extensions,key)) + if (ParameterElement.extensions[key] !== undefined) { valInt = ParameterElement.extensions[key] as int; valInt |= int(attribute.value == "required"); diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ProfileElement.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ProfileElement.as old mode 100755 new mode 100644 index 482f33d..edbe366 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ProfileElement.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/model/parameter/ProfileElement.as @@ -23,7 +23,6 @@ package org.osmf.smpte.tt.model.parameter import org.osmf.smpte.tt.model.TimedTextAttributeBase; import org.osmf.smpte.tt.model.TimedTextElementBase; import org.osmf.smpte.tt.model.metadata.MetadataElement; - import org.osmf.smpte.tt.timing.TimeTree; import org.osmf.smpte.tt.utilities.DictionaryUtils; public class ProfileElement extends ParameterElement @@ -64,7 +63,8 @@ package org.osmf.smpte.tt.model.parameter var noExtensions:Boolean = true; var sb:String = "The following features are not supported:\n"; var feature:String; - for each (feature in DictionaryUtils.getKeys(extensions)) + var keys:Array = DictionaryUtils.getKeys(extensions); + for each (feature in keys) { if (extensions[feature]) { @@ -73,7 +73,8 @@ package org.osmf.smpte.tt.model.parameter noExtensions = false; } } - for (feature in DictionaryUtils.getKeys(features)) + keys = DictionaryUtils.getKeys(features); + for (feature in keys) { if (features[feature] && nonFeatures.indexOf(feature)>=0) { @@ -90,25 +91,21 @@ package org.osmf.smpte.tt.model.parameter protected override function validElements():void { var child:uint = 0; - - while (child < children.length - && ((children[child] is org.osmf.smpte.tt.model.MetadataElement) - || (children[child] is org.osmf.smpte.tt.model.metadata.MetadataElement) - || (children[child] is FeaturesElement) - || (children[child] is ExtensionsElement))) - { - child++; - } - - if (children.length != child) - { - error(children[child] + " is not allowed in " + this+ " at position " + child); - } - // now check each of the children is individually valid for each (var element:TimedTextElementBase in children) { - element.valid(); + if (element is org.osmf.smpte.tt.model.MetadataElement + || element is org.osmf.smpte.tt.model.metadata.MetadataElement + || element is FeaturesElement + || element is ExtensionsElement) + { + child++; + element.valid(); + } + else + { + error(element + " is not allowed in " + this+ " at position " + (children.length-child)); + } } } } diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/ISMPTETTParser.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/ISMPTETTParser.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/SMPTETTParser.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/SMPTETTParser.as old mode 100755 new mode 100644 index 87482a3..52c5e01 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/SMPTETTParser.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/SMPTETTParser.as @@ -1,640 +1,716 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.parsing -{ - import flash.display.Sprite; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.IEventDispatcher; - import flash.utils.Dictionary; - import flash.utils.getTimer; - import flash.utils.setTimeout; - - import org.osmf.smpte.tt.captions.CaptionElement; - import org.osmf.smpte.tt.captions.CaptionRegion; - import org.osmf.smpte.tt.captions.CaptioningDocument; - import org.osmf.smpte.tt.captions.TimedTextAnimation; - import org.osmf.smpte.tt.captions.TimedTextElement; - import org.osmf.smpte.tt.captions.TimedTextElementType; - import org.osmf.smpte.tt.errors.SMPTETTException; - import org.osmf.smpte.tt.events.ParseEvent; - import org.osmf.smpte.tt.formatting.Animation; - import org.osmf.smpte.tt.logging.SMPTETTLogging; - import org.osmf.smpte.tt.model.AnonymousSpanElement; - import org.osmf.smpte.tt.model.BrElement; - import org.osmf.smpte.tt.model.LayoutElement; - import org.osmf.smpte.tt.model.PElement; - import org.osmf.smpte.tt.model.RegionElement; - import org.osmf.smpte.tt.model.SetElement; - import org.osmf.smpte.tt.model.SpanElement; - import org.osmf.smpte.tt.model.TimedTextAttributeBase; - import org.osmf.smpte.tt.model.TimedTextElementBase; - import org.osmf.smpte.tt.model.TtElement; - import org.osmf.smpte.tt.model.metadata.CopyrightElement; - import org.osmf.smpte.tt.model.metadata.DescElement; - import org.osmf.smpte.tt.model.metadata.TitleElement; - import org.osmf.smpte.tt.timing.TimeCode; - import org.osmf.smpte.tt.timing.TimeContainer; - import org.osmf.smpte.tt.timing.TimeExpression; - import org.osmf.smpte.tt.timing.TimeSpan; - import org.osmf.smpte.tt.timing.TreeType; - import org.osmf.smpte.tt.utilities.AsyncThread; - import org.osmf.smpte.tt.utilities.DictionaryUtils; - import org.osmf.smpte.tt.vocabulary.Namespaces; - - [Event(name="begin", type="org.osmf.smpte.tt.events.ParseEvent")] - [Event(name="progress", type="org.osmf.smpte.tt.events.ParseEvent")] - [Event(name="complete", type="org.osmf.smpte.tt.events.ParseEvent")] - - public class SMPTETTParser extends EventDispatcher - implements IEventDispatcher, ISMPTETTParser - { - - - - - public static var ns:Namespace; - public static var ttm:Namespace; - public static var tts:Namespace; - public static var ttp:Namespace; - public static var smpte:Namespace; - public static var m608:Namespace; - public static var rootNamespace:Namespace; - - private var _document:CaptioningDocument; - private var _sprite:Sprite; - - private function get sprite():Sprite - { - if(!_sprite){ - _sprite = new Sprite(); - } - return _sprite; - } - - public function get document():CaptioningDocument - { - return _document; - } - - public function SMPTETTParser(){ - } - - private var _startTime:TimeCode = null; - private var _taskId:uint=0; - - private var _ttElement:TtElement; - - public function get ttElement():TtElement - { - return _ttElement; - } - - private var _regionElementsHash:Dictionary; - - public function get regionElementsHash():Dictionary - { - return _regionElementsHash; - } - - private var _captionRegionsHash:Dictionary; - - public function get captionRegionsHash():Dictionary - { - return _captionRegionsHash; - } - - private var _captionElements:Vector.; - /** - * Returns a vector of CaptionElements, one for each unique timeline event in the file. - *

      Additional CaptionsElements that occur at the same TimelineMarker are stored in each CaptionElements siblings Vector..

      - * - * @return - * - */ - public function get captionElements():Vector. - { - return _captionElements; - } - - - public function get startTime():TimeCode - { - return _startTime; - } - - public function set startTime(value:TimeCode):void - { - _startTime = value; - } - - private var _endTime:TimeCode = null; - - public function get endTime():TimeCode - { - return _endTime; - } - - public function set endTime(value:TimeCode):void - { - _endTime = value; - } - - public function parse(i_rawData:String):CaptioningDocument - { - _document = new CaptioningDocument(); - - // if global time parameters for this session haven't been established, we should set them - if(!TimeExpression.CurrentTimeBase){ - TimeExpression.initializeParameters(); - } - - var parseTree:TtElement = null; - - dispatchEvent(new ParseEvent(ParseEvent.BEGIN, true, false, parseTree) ); - addEventListener(ParseEvent.PROGRESS, handleParseTtElement); - parseTree = parseTtElement(i_rawData); - - return _document; - } - - - private function handleParseTtElement(e:ParseEvent):void - { - if(e.data && e.data is TtElement){ - //trace(this+".handleParseTtElement("+e+")"); - removeEventListener(ParseEvent.PROGRESS, handleParseTtElement); - addEventListener(ParseEvent.PROGRESS, handleComputeTimeIntervals); - - _ttElement = e.data as TtElement; - computeTimeIntervals(e.data as TtElement, _startTime, _endTime); - } - } - - private function handleComputeTimeIntervals(e:ParseEvent):void - { - - if(e.data && e.data is TtElement){ - //trace(this+".handleComputeTimeIntervals("+e+")"); - removeEventListener(ParseEvent.PROGRESS, handleComputeTimeIntervals); - var parseTree:TtElement = e.data as TtElement; - _ttElement = parseTree; - //trace(_ttElement.serialize()); - addEventListener(ParseEvent.PROGRESS, handleBuildDocumentTimeInterval); - buildRegions(parseTree); - } - } - - private var asyncThread:AsyncThread; - private function handleBuildDocumentTimeInterval(e:ParseEvent):void - { - - if(e.data) - { - //trace(this+".handleBuildDocumentTimeInterval("+e+")"); - //removeEventListener(ParseEvent.PROGRESS, handleBuildDocumentTimeInterval); - //addEventListener(ParseEvent.PROGRESS, handleBuildCaptionsTimeInterval); - if(e.data is ParseEventData) - { - var ped:ParseEventData = ParseEventData(e.data); - if(e.data.timedTextElement != null) - { - // buildCaptions( ped.timedTextElement, ped.regionElementsHash, ped.captionRegionsHash, ped.timelineEventsHash ); - - if(!asyncThread){ - asyncThread =AsyncThread.create( buildCaptions, [ ped.timedTextElement,ped.regionElementsHash,ped.captionRegionsHash,ped.timelineEventsHash ] ); - asyncThread.runEachFrame(100); - } else { - AsyncThread.queue( buildCaptions, [ ped.timedTextElement,ped.regionElementsHash,ped.captionRegionsHash,ped.timelineEventsHash ] ); - } - - } else - { - removeEventListener(ParseEvent.PROGRESS, handleBuildDocumentTimeInterval); - - var keys:Array = DictionaryUtils.getKeys(ped.timelineEventsHash).sort(); - - _captionElements = new Vector.; - for each(var k:String in keys) - { - _captionElements.push(ped.timelineEventsHash[k]); - } - - this._regionElementsHash = ped.regionElementsHash; - this._captionRegionsHash = ped.captionRegionsHash; - - dispatchEvent(new ParseEvent(ParseEvent.COMPLETE, true, false, _document)); - } - } - } - } - - private function repairNamespaces(xml:XML):Namespace { - var newDefaultNS:Namespace = xml.namespace(); - if (newDefaultNS.uri.length==0) - { - var nsDeclarations:Array = xml.namespaceDeclarations(); - for each(var ns:Namespace in nsDeclarations) - { - if(ns.uri.match(/^http\:\/\/www\.w3\.org\/2006\/(?:02|04|10)\/ttaf1/) - || ns.uri.indexOf("http://www.w3.org/ns/ttml")==0) - { - newDefaultNS = new Namespace(ns.uri.split("#")[0]); - break; - } - } - if(newDefaultNS.uri.length==0) - { - newDefaultNS = Namespaces.TTML_NS; - } - } - - return newDefaultNS; - } - - private function parseTtElement(rawData:String):TtElement - { - var parsetree:TtElement = null; - - // cache our original XML.ignoreWhitespace and XML.prettyPrinting settings - var saveXMLIgnoreWhitespace:Boolean = XML.ignoreWhitespace; - var saveXMLPrettyPrinting:Boolean = XML.prettyPrinting; - - // Remove line ending whitespaces - var xmlStr:String = rawData.replace(/\s+$/, ""); - - // Remove whitespaces between tags - xmlStr = xmlStr.replace(/>\s+<"); - - // Tell the XML class to show white space in text nodes - XML.ignoreWhitespace = false; - // Tell the XML class not to normalize white space for toString() method calls - XML.prettyPrinting = false; - - try { - var xml:XML = new XML(xmlStr); - - // this cleans up some namespace wierdness with legacy dfxp - // or ttml that omits the default namespace - var newNS:Namespace = repairNamespaces(xml); - - default xml namespace = newNS; - ns = xml.namespace(); - tts = xml.namespace("tts"); - ttm = xml.namespace("ttm"); - ttp = xml.namespace("ttp"); - smpte = xml.namespace("smpte"); - m608 = xml.namespace("m608"); - - // rewrite xml with corrected namespace - xml = new XML(xmlStr); - - default xml namespace = new Namespace( "" ); - - parsetree = TimedTextElementBase.parse(xml) as TtElement; - - } catch (e:SMPTETTException) { - SMPTETTLogging.debugLog("Unhandled exception in TimedTextParser : "+e.message); - throw e; - } finally { - // restore our original XML.ignoreWhitespace and XML.prettyPrinting settings from cache - XML.ignoreWhitespace = saveXMLIgnoreWhitespace; - XML.prettyPrinting = saveXMLPrettyPrinting; - } - - if (parsetree == null) - { - trace("No Parse tree returned"); - throw new SMPTETTException("No Parse tree returned"); - } - if (!parsetree.valid()) - { - trace("Document is Well formed XML, but invalid Timed Text"); - throw new SMPTETTException("Document is Well formed XML, but invalid Timed Text"); - } - dispatchEvent(new ParseEvent(ParseEvent.PROGRESS, true, false, parsetree) ); - return parsetree; - } - - private function computeTimeIntervals(parsetree:TtElement, i_startTime:TimeCode=null, i_endTime:TimeCode=null):TtElement - { - var startTime:TimeCode = (i_startTime) ? i_startTime : TimeExpression.parse("00:00:00:00"); - var endTime:TimeCode = (i_endTime) ? i_endTime : TimeExpression.parse("12:00:00:00"); - - parsetree.computeTimeIntervals(TimeContainer.PAR, startTime, endTime); - - //XML.ignoreWhitespace = true; - //XML.prettyPrinting = false; - // trace(XML(parsetree.serialize()).toXMLString()); - - dispatchEvent(new ParseEvent(ParseEvent.PROGRESS, true, false, parsetree) ); - return parsetree; - } - - // private var regionElementsHash:Dictionary; - // private var captionRegionsHash:Dictionary; - - private var remainingNodeCount:int = 0; - private function buildRegions(document:TtElement):void - { - var regionElementsHash:Dictionary = new Dictionary(); - var regionElements:Vector. = new Vector.(); - if(document.head != null) - { - for each(var i:TreeType in document.head.children) - { - if(i is LayoutElement) - { - for each(var r:RegionElement in i.children) - { - regionElementsHash[r.id] = r; - // trace(r.id); - } - } else if(i is TitleElement) - { - _document.title = TitleElement(i).text; - } else if(i is CopyrightElement) - { - _document.copyright = CopyrightElement(i).text; - } else if(i is DescElement) - { - _document.description = DescElement(i).text; - } - } - } - - var captionRegionsHash:Dictionary = new Dictionary(); - for each(var k:RegionElement in regionElementsHash){ - var captionRegion:CaptionRegion = mapToCaptionRegion(k) as CaptionRegion; - captionRegionsHash[captionRegion.id] = captionRegion; - _document.addCaptionRegion(captionRegion); - } - - var timelineEventsHash:Dictionary = new Dictionary(); - - - // trace((++this._taskId) + " build Regions"); - if (document.body != null) - { - remainingNodeCount = document.totalNodeCount; - - trace("totalNodeCount: "+document.totalNodeCount); - - var parseEvent:ParseEvent = new ParseEvent(ParseEvent.PROGRESS); - parseEvent.data = new ParseEventData(document.body - ,regionElementsHash - ,captionRegionsHash - ,timelineEventsHash - ); - dispatchEvent( parseEvent ); - } - - //return regions; - } - - private var parseTime:uint; - private function buildCaptions(timedTextElement:TimedTextElementBase, regionElementsHash:Dictionary, captionRegionsHash:Dictionary, timelineEventsHash:Dictionary):void - { - if(!parseTime) parseTime=flash.utils.getTimer(); - var parseEvent:ParseEvent; - var pElement:PElement = timedTextElement as PElement; - if (pElement != null) - { - var regionNameAttribute:TimedTextAttributeBase; - for each(var i:TimedTextAttributeBase in timedTextElement.attributes) - { - if(i.localName=="region"){ - regionNameAttribute = i; - break; - } - } - var computedRegionName:String = pElement.getComputedStyle("region",null); - var regionName:String = (regionNameAttribute != null) - ? regionNameAttribute.value - : ((computedRegionName && computedRegionName!="") - ? computedRegionName - : RegionElement.DEFAULT_REGION_NAME); - var regionElement:RegionElement; - if (DictionaryUtils.containsKey(regionElementsHash,regionName)) - { - regionElement = regionElementsHash[regionName]; - var captionElement:CaptionElement = mapToCaption(pElement, regionElement) as CaptionElement; - - var captionRegion:CaptionRegion; - if (DictionaryUtils.containsKey(captionRegionsHash, regionName)) - { - captionRegion = captionRegionsHash[regionName]; - captionElement.index = captionRegion.children.length; - - captionRegion.children.push(captionElement); - - var timecode:String = TimeExpression.parse(captionElement.begin+"s").toString(); - if(timelineEventsHash[timecode] is CaptionElement){ - (timelineEventsHash[timecode] as CaptionElement).siblings.push(captionElement); - } else { - timelineEventsHash[timecode] = captionElement; - // trace("new timeline event at "+timecode); - } - - _document.addCaptionElement(captionElement); - _document.captionRegionsHash[regionName].children.push(captionElement); - } - } - } - else if (timedTextElement.children != null) - { - //trace((++this._taskId) + " build Captions"); - var count:uint = 0; - var children:Vector. = timedTextElement.children; - var j:TimedTextElementBase; - for each(j in children) - { - //j = children[k] as TimedTextElementBase; - - //trace(j) - - /* green-threading */ - /* - if(getTimer()-parseTime<100){ - buildCaptions(j, regionElementsHash, captionRegionsHash, timelineEventsHash); - } else { - parseTime = getTimer(); - - parseEvent = new ParseEvent(ParseEvent.PROGRESS); - parseEvent.data = new ParseEventData(j, regionElementsHash, captionRegionsHash, timelineEventsHash); - dispatchEvent( parseEvent ); - } - */ - AsyncThread.queue(buildCaptions, [ j, regionElementsHash, captionRegionsHash, timelineEventsHash ] ); - } - } - if(remainingNodeCount<=0) - { - parseEvent = new ParseEvent(ParseEvent.PROGRESS); - parseEvent.data = new ParseEventData(null, regionElementsHash, captionRegionsHash, timelineEventsHash); - - dispatchEvent( parseEvent ); - } else { - // trace(remainingNodeCount); - } - } - - private function mapToCaptionRegion(regionElement:RegionElement):CaptionRegion - { - var endTime:Number = (regionElement.end.totalSeconds >= TimeSpan.MAX_VALUE.totalSeconds) - ? TimeSpan.MAX_VALUE.totalSeconds - : regionElement.end.totalSeconds; - - var captionRegion:CaptionRegion = new CaptionRegion(regionElement.begin.totalSeconds, endTime, regionElement.id); - captionRegion.id = regionElement.id; - captionRegion.style = TimedTextStyleParser.mapStyle(regionElement, regionElement); - - for each (var element:TimedTextElementBase in regionElement.children) - { - - var child:TimedTextElement = buildTimedTextElements(element, regionElement); - - if (child != null && child.captionElementType == TimedTextElementType.Animation) - { - captionRegion.animations.push(child as TimedTextAnimation); - } - } - return captionRegion; - } - - private function mapToCaption(pElement:PElement, region:RegionElement):CaptionElement - { - var captionElement:CaptionElement = buildTimedTextElements(pElement, region) as CaptionElement; - captionElement.id = (pElement.id) ? pElement.id : flash.utils.getTimer().toString(); //GUID.create(); - return captionElement; - } - - private function buildTimedTextElements(element:TimedTextElementBase, region:RegionElement):TimedTextElement - { - // trace(region.id+" buildTimedTextElements: "+ element+" "+(element.hasOwnProperty("text") ? element["text"]:"")); - - var timedTextElement:TimedTextElement = createTimedTextElement(element, region); - var captionElement:CaptionElement = timedTextElement as CaptionElement; - - for each (var c:TimedTextElementBase in element.children) - { - var child:TimedTextElement = buildTimedTextElements(c, region); - if (child is TimedTextAnimation) - { - timedTextElement.animations.push(TimedTextAnimation(child)); - } else if (captionElement != null && child is CaptionElement) - { - (child as CaptionElement).index = captionElement.children.length; - captionElement.children.push(child as CaptionElement); - } - } - return timedTextElement; - } - - private function createTimedTextElement(element:TimedTextElementBase, region:RegionElement):TimedTextElement - { - var captionElement:TimedTextElement = (element is SetElement) - ? TimedTextElement(buildCaptionAnimationElement(element)) - : new CaptionElement(element.begin.totalSeconds, element.end.totalSeconds) as TimedTextElement; - - if(captionElement is CaptionElement && region) { - CaptionElement(captionElement).regionId = region.id; - } - - // captionElement.end = element.end.totalSeconds; - // captionElement.begin = element.begin.totalSeconds; - - if (element is BrElement) - { - captionElement.captionElementType = TimedTextElementType.LineBreak; - } else if (element is AnonymousSpanElement) - { - var aSpan:AnonymousSpanElement = element as AnonymousSpanElement; - captionElement.captionElementType = TimedTextElementType.Text; - captionElement.content = aSpan.text; - - var styledElement:TimedTextElementBase = (element.parent is SpanElement) ? TimedTextElementBase(element.parent) : element; - - captionElement.style = TimedTextStyleParser.mapStyle(styledElement, region); - - remainingNodeCount--; - } - /* - else if (element is SpanElement - && element.children.length==1 - && element.children[0] is AnonymousSpanElement) - { - var span:SpanElement = element as SpanElement; - var child:AnonymousSpanElement = span.children[0] as AnonymousSpanElement; - captionElement.captionElementType = TimedTextElementType.Text; - captionElement.content = child.text; - captionElement.style = TimedTextStyleParser.mapStyle(span as TimedTextElementBase, region); - //remainingNodeCount--; - } - */ - else if (!(element is SetElement)) - { - captionElement.captionElementType = (element is SpanElement) ? TimedTextElementType.SupParagraphGroupElement : TimedTextElementType.Container; - captionElement.style = TimedTextStyleParser.mapStyle(element, region); - } - return captionElement; - } - - private function buildCaptionAnimationElement(element:TimedTextElementBase):TimedTextAnimation - { - var propertyName:String; - - for each(var i:TimedTextAttributeBase in element.attributes) { - if(TimedTextStyleParser.isValidAnimationPropertyName(i.localName)){ - propertyName = i.localName; - break; - } - } - if(propertyName && propertyName.length>0) { - var tta:TimedTextAnimation = new TimedTextAnimation(element.begin.totalSeconds,element.end.totalSeconds); - tta.captionElementType = TimedTextElementType.Animation; - tta.propertyName = propertyName; - tta.style = TimedTextStyleParser.mapStyle(element, null); - return tta; - } else { - return null; - } - } - } -} - -class ParseEventData -{ - import org.osmf.smpte.tt.model.TimedTextElementBase; - import flash.utils.Dictionary; - - public var timedTextElement:TimedTextElementBase=null; - public var regionElementsHash:Dictionary=null; - public var captionRegionsHash:Dictionary=null; - public var timelineEventsHash:Dictionary=null; - - public function ParseEventData(i_timedTextElement:TimedTextElementBase=null, i_regionElementsHash:Dictionary=null, i_captionRegionsHash:Dictionary=null, i_timelineEventsHash:Dictionary=null) - { - if(i_timedTextElement) timedTextElement = i_timedTextElement; - if(i_regionElementsHash) regionElementsHash = i_regionElementsHash; - if(i_captionRegionsHash) captionRegionsHash = i_captionRegionsHash; - if(i_timelineEventsHash) timelineEventsHash = i_timelineEventsHash; - } -} +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.parsing +{ + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.IEventDispatcher; + import flash.external.ExternalInterface; + import flash.utils.Dictionary; + import flash.utils.getTimer; + + import org.osmf.smpte.tt.captions.CaptionElement; + import org.osmf.smpte.tt.captions.CaptionRegion; + import org.osmf.smpte.tt.captions.CaptioningDocument; + import org.osmf.smpte.tt.captions.TimedTextAnimation; + import org.osmf.smpte.tt.captions.TimedTextElement; + import org.osmf.smpte.tt.captions.TimedTextElementType; + import org.osmf.smpte.tt.errors.SMPTETTException; + import org.osmf.smpte.tt.events.ParseEvent; + import org.osmf.smpte.tt.logging.SMPTETTLogging; + import org.osmf.smpte.tt.model.AnonymousSpanElement; + import org.osmf.smpte.tt.model.BrElement; + import org.osmf.smpte.tt.model.LayoutElement; + import org.osmf.smpte.tt.model.PElement; + import org.osmf.smpte.tt.model.RegionElement; + import org.osmf.smpte.tt.model.SetElement; + import org.osmf.smpte.tt.model.SpanElement; + import org.osmf.smpte.tt.model.TimedTextAttributeBase; + import org.osmf.smpte.tt.model.TimedTextElementBase; + import org.osmf.smpte.tt.model.TtElement; + import org.osmf.smpte.tt.model.metadata.CopyrightElement; + import org.osmf.smpte.tt.model.metadata.DescElement; + import org.osmf.smpte.tt.model.metadata.TitleElement; + import org.osmf.smpte.tt.timing.TimeCode; + import org.osmf.smpte.tt.timing.TimeContainer; + import org.osmf.smpte.tt.timing.TimeExpression; + import org.osmf.smpte.tt.timing.TimeSpan; + import org.osmf.smpte.tt.timing.TreeType; + import org.osmf.smpte.tt.utilities.AsyncThread; + import org.osmf.smpte.tt.vocabulary.Namespaces; + + [Event(name="begin", type="org.osmf.smpte.tt.events.ParseEvent")] + [Event(name="progress", type="org.osmf.smpte.tt.events.ParseEvent")] + [Event(name="complete", type="org.osmf.smpte.tt.events.ParseEvent")] + + public class SMPTETTParser extends EventDispatcher + implements IEventDispatcher, ISMPTETTParser + { + + private static const DEBUG:Boolean = true; + + public static var ns:Namespace; + public static var ttm:Namespace; + public static var tts:Namespace; + public static var ttp:Namespace; + public static var smpte:Namespace; + public static var m608:Namespace; + public static var rootNamespace:Namespace; + public static var ASYNC_THREAD:AsyncThread; + public static var REMAINING_NODE_COUNT:uint; + + protected var _document:CaptioningDocument; + + public function get document():CaptioningDocument + { + return _document; + } + + public function SMPTETTParser(){ + } + + private var _taskId:uint=0; + + private var _ttElement:TtElement; + + public function get ttElement():TtElement + { + return _ttElement; + } + + private var _regionElementsHash:Dictionary; + + public function get regionElementsHash():Dictionary + { + return _regionElementsHash; + } + + private var _captionRegionsHash:Dictionary; + + public function get captionRegionsHash():Dictionary + { + return _captionRegionsHash; + } + + protected var _captionElements:Vector.; + /** + * Returns a vector of CaptionElements, one for each unique timeline event in the file. + *

      Additional CaptionsElements that occur at the same TimelineMarker are stored in each CaptionElements siblings Vector..

      + * + * @return + * + */ + public function get captionElements():Vector. + { + return _captionElements; + } + + private var _startTime:TimeCode = null; + public function get startTime():TimeCode + { + return _startTime; + } + + public function set startTime(value:TimeCode):void + { + _startTime = value; + } + + private var _endTime:TimeCode = null; + public function get endTime():TimeCode + { + return _endTime; + } + + public function set endTime(value:TimeCode):void + { + _endTime = value; + } + + protected function set remainingNodeCount(v:int):void + { + SMPTETTParser.REMAINING_NODE_COUNT = v; + } + + protected function get remainingNodeCount():int + { + return SMPTETTParser.REMAINING_NODE_COUNT + } + + public function parse(i_rawData:String):CaptioningDocument + { + if (ASYNC_THREAD) + { + // clean-up any running threads + debug("ASYNC_THREAD.stop()"); + ASYNC_THREAD.stop(); + ASYNC_THREAD = null; + } + + _document = new CaptioningDocument(); + + // if global time parameters for this session haven't been established, we should set them + if(!TimeExpression.CurrentTimeBase) + TimeExpression.initializeParameters(); + + + var parseTree:TtElement = null; + + dispatchEvent(new ParseEvent(ParseEvent.BEGIN, true, false, parseTree) ); + addEventListener(ParseEvent.PROGRESS, handleParseTtElement); + parseTree = parseTtElement(i_rawData); + + return _document; + } + + + private function handleParseTtElement(e:ParseEvent):void + { + if(e.data && e.data is TtElement){ + //trace(this+".handleParseTtElement("+e+")"); + removeEventListener(ParseEvent.PROGRESS, handleParseTtElement); + addEventListener(ParseEvent.PROGRESS, handleValitateTtElement); + + _ttElement = e.data as TtElement; + validateTtElement(_ttElement); + } + } + + private function handleValitateTtElement(e:ParseEvent):void + { + if(e.data && e.data is TtElement){ + //trace(this+".handleParseTtElement("+e+")"); + removeEventListener(ParseEvent.PROGRESS, handleValitateTtElement); + addEventListener(ParseEvent.PROGRESS, handleComputeTimeIntervals); + + _ttElement = e.data as TtElement; + computeTimeIntervals(_ttElement, _startTime, _endTime); + } + } + + private function handleComputeTimeIntervals(e:ParseEvent):void + { + if(e.data && e.data is TtElement){ + //trace(this+".handleComputeTimeIntervals("+e+")"); + removeEventListener(ParseEvent.PROGRESS, handleComputeTimeIntervals); + addEventListener(ParseEvent.PROGRESS, handleBuildDocumentTimeInterval); + + _ttElement = e.data as TtElement; + buildRegions(_ttElement); + } + } + + private function handleBuildDocumentTimeInterval(e:ParseEvent):void + { + if(e.data) + { + //trace(this+".handleBuildDocumentTimeInterval("+e+")"); + //removeEventListener(ParseEvent.PROGRESS, handleBuildDocumentTimeInterval); + //addEventListener(ParseEvent.PROGRESS, handleBuildCaptionsTimeInterval); + if(e.data is ParseEventData) + { + var ped:ParseEventData = ParseEventData(e.data); + if(e.data.timedTextElement != null) + { + // buildCaptions( ped.timedTextElement, ped.regionElementsHash, ped.captionRegionsHash, ped.timelineEventsHash ); + + if(!ASYNC_THREAD) + { + parseTime = getTimer(); + _captionElements = new Vector.(); + ASYNC_THREAD = AsyncThread.create( buildCaptions, + [ ped.timedTextElement, + ped.regionElementsHash, + ped.captionRegionsHash, + ped.timelineEventsHash ] ); + ASYNC_THREAD.addEventListener(Event.COMPLETE, asyncThread_completeHandler, false, 0, true); + ASYNC_THREAD.runEachFrame(50); + } else + { + if (!_captionElements) + _captionElements = new Vector.(); + AsyncThread.queue( buildCaptions, + [ ped.timedTextElement, + ped.regionElementsHash, + ped.captionRegionsHash, + ped.timelineEventsHash ] ); + } + + } else + { + removeEventListener(ParseEvent.PROGRESS, handleBuildDocumentTimeInterval); + + _regionElementsHash = ped.regionElementsHash; + _captionRegionsHash = ped.captionRegionsHash; + + var localParseTime:uint = parseTime; + debug(this+" handleBuildDocumentTimeInterval: "+(getTimer()-parseTime)/1000+"s"); + } + } + } + } + + private function asyncThread_completeHandler(event:Event):void + { + debug(event.target+" asyncThread_completeHandler: "+(getTimer()-parseTime)/1000+"s"); + ASYNC_THREAD.removeEventListener(Event.COMPLETE, asyncThread_completeHandler); + ASYNC_THREAD = null; + + _captionRegionsHash = null; + _regionElementsHash = null; + _captionElements = null; + startTime = null; + endTime = null; + + dispatchEvent(new ParseEvent(ParseEvent.COMPLETE, true, false, _document)); + } + + private function repairNamespaces(xml:XML):Namespace + { + + Namespaces.useLegacyNamespace(Namespaces.DEFAULT_TTML_NS); + + var newDefaultNS:Namespace = xml.namespace(); + if (newDefaultNS.uri.length==0) + { + var nsDeclarations:Array = xml.namespaceDeclarations(); + for each(var ns:Namespace in nsDeclarations) + { + if(ns.uri.match(Namespaces.TTML_NS_REGEXP)) + { + newDefaultNS = new Namespace(ns.uri.split("#")[0]); + break; + } + } + if(newDefaultNS.uri.length==0) + { + newDefaultNS = Namespaces.TTML_NS; + } + } + + xml.setNamespace(newDefaultNS); + + return newDefaultNS; + } + + private function stripSMPTETTNodes(xml:XML):XML + { + if(xml.namespace("smpte")) + { + var xmlList:XMLList = xml..smpte::*; + var len:uint = xmlList.length(); + for each(var node:XML in xmlList) + { + delete node.parent().*[node.childIndex()]; + } + } + return xml; + } + + private function parseTtElement(rawData:String):TtElement + { + parseTime = getTimer(); + + var parsetree:TtElement = null; + + // cache our original XML.ignoreWhitespace and XML.prettyPrinting settings + var saveXMLIgnoreWhitespace:Boolean = XML.ignoreWhitespace; + var saveXMLPrettyPrinting:Boolean = XML.prettyPrinting; + + // Remove line ending whitespaces + var xmlStr:String = rawData; //.replace(/\s+$/, ""); + + // Remove whitespaces between tags + xmlStr = xmlStr.replace(/(?\s+<(?!$1)|(?<=span)>\s*[\n\r\t]\s*<"); + + // Tell the XML class to show white space in text nodes + XML.ignoreWhitespace = false; + // Tell the XML class not to normalize white space for toString() method calls + XML.prettyPrinting = false; + + try { + var xml:XML = new XML(xmlStr); + + // this cleans up some namespace wierdness with legacy dfxp + // or ttml that omits the default namespace + var newNS:Namespace = repairNamespaces(xml); + + default xml namespace = newNS; + ns = xml.namespace(); + tts = xml.namespace("tts"); + ttm = xml.namespace("ttm"); + ttp = xml.namespace("ttp"); + smpte = xml.namespace("smpte"); + m608 = xml.namespace("m608"); + xml.addNamespace(Namespaces.XML_NS); + + // rewrite xml with corrected namespace + // xml = new XML(xmlStr); + // xml = stripSMPTETTNodes(xml); + + //parsetree = TimedTextElementBase.parse(xml) as TtElement; + //parsetree = XMLToTTElementParser.parse(xml) as TtElement; + var asyncParser:XMLToTTElementParser = XMLToTTElementParser.parse(xml); + asyncParser.addEventListener(ParseEvent.COMPLETE, onXMLToTTElementComplete); + + } catch (e:SMPTETTException) { + SMPTETTLogging.debugLog("Unhandled exception in TimedTextParser : "+e.message); + throw e; + } finally { + // restore our original XML.ignoreWhitespace and XML.prettyPrinting settings from cache + default xml namespace = Namespaces.XML_NS; + XML.ignoreWhitespace = saveXMLIgnoreWhitespace; + XML.prettyPrinting = saveXMLPrettyPrinting; + } + + return parsetree; + } + + private function onXMLToTTElementComplete(event:ParseEvent):void + { + var parsetree:TtElement = event.data as TtElement; + if (parsetree == null) + { + debug("No Parse tree returned"); + throw new SMPTETTException("No Parse tree returned"); + } + + debug(this+" parseTTElement: "+(getTimer()-parseTime)/1000+"s"); + + dispatchEvent(new ParseEvent(ParseEvent.PROGRESS, true, false, parsetree) ); + } + + private function validateTtElement(parsetree:TtElement):TtElement + { + parseTime = getTimer(); + + var isValid:Boolean = parsetree.valid(); + if (!isValid) + { + debug("Document is Well formed XML, but invalid Timed Text"); + throw new SMPTETTException("Document is Well formed XML, but invalid Timed Text"); + } + + debug(this+" validateTTElement(): "+isValid+ " "+(getTimer()-parseTime)/1000+"s"); + + dispatchEvent(new ParseEvent(ParseEvent.PROGRESS, true, false, parsetree) ); + return parsetree; + } + + private function computeTimeIntervals(parsetree:TtElement, i_startTime:TimeCode=null, i_endTime:TimeCode=null):TtElement + { + parseTime = getTimer(); + + if(!TimeExpression.CurrentTimeBase) + TimeExpression.initializeParameters(); + + var st:TimeCode = (i_startTime) ? i_startTime : new TimeCode(0,TimeExpression.CurrentSmpteFrameRate); + var et:TimeCode = (i_endTime) ? i_endTime : new TimeCode(TimeCode.maxValue(TimeExpression.CurrentSmpteFrameRate),TimeExpression.CurrentSmpteFrameRate); + + parsetree.computeTimeIntervals(TimeContainer.PAR, st, et); + + debug(this+" computeTimeIntervals("+st+", "+et+"): "+(getTimer()-parseTime)/1000+"s\n"/* +parsetree.events.toString() */); + + dispatchEvent(new ParseEvent(ParseEvent.PROGRESS, true, false, parsetree) ); + return parsetree; + } + + // private var regionElementsHash:Dictionary; + // private var captionRegionsHash:Dictionary; + + protected function buildRegions(document:TtElement):void + { + parseTime = getTimer(); + + var regionElementsHash:Dictionary = new Dictionary(); + var regionElements:Vector. = new Vector.(); + if(document.head != null) + { + for each(var i:TreeType in document.head.children) + { + if(i is LayoutElement) + { + for each(var r:RegionElement in i.children) + { + regionElementsHash[r.id] = r; + // trace(r.id); + } + } else if(i is TitleElement) + { + _document.title = TitleElement(i).text; + } else if(i is CopyrightElement) + { + _document.copyright = CopyrightElement(i).text; + } else if(i is DescElement) + { + _document.description = DescElement(i).text; + } + } + } + + var captionRegionsHash:Dictionary = new Dictionary(); + for each(var k:RegionElement in regionElementsHash) + { + var captionRegion:CaptionRegion = mapToCaptionRegion(k) as CaptionRegion; + captionRegionsHash[captionRegion.id] = captionRegion; + _document.addCaptionRegion(captionRegion); + } + + var timelineEventsHash:Dictionary = new Dictionary(); + + + // trace((++this._taskId) + " build Regions"); + if (document.body != null) + { + remainingNodeCount = document.totalNodeCount; + + debug(this+" buildRegions: "+(getTimer()-parseTime)/1000+"s"); + debug(this+" totalNodeCount: "+remainingNodeCount); + + var parseEvent:ParseEvent = new ParseEvent(ParseEvent.PROGRESS); + parseEvent.data = createParseEventData(document.body + ,regionElementsHash + ,captionRegionsHash + ,timelineEventsHash + ); + dispatchEvent( parseEvent ); + } + + //return regions; + } + + protected var parseTime:uint; + protected function buildCaptions(timedTextElement:TimedTextElementBase, regionElementsHash:Dictionary, captionRegionsHash:Dictionary, timelineEventsHash:Dictionary):void + { + var parseEvent:ParseEvent; + var pElement:PElement = timedTextElement as PElement; + if (pElement != null) + { + var regionNameAttribute:TimedTextAttributeBase; + for each(var i:TimedTextAttributeBase in timedTextElement.attributes) + { + if(i.localName=="region"){ + regionNameAttribute = i; + break; + } + } + var computedRegionName:String = pElement.getComputedStyle("region",null); + var regionName:String = (regionNameAttribute) + ? regionNameAttribute.value + : ((computedRegionName && computedRegionName!="") + ? computedRegionName + : RegionElement.DEFAULT_REGION_NAME); + var regionElement:RegionElement; + if (regionElementsHash[regionName] && captionRegionsHash[regionName]) + { + regionElement = regionElementsHash[regionName]; + + var captionElement:CaptionElement = mapToCaption(pElement, regionElement) as CaptionElement; + var captionRegion:CaptionRegion = captionRegionsHash[regionName]; + + captionElement.index = captionRegion.children.length; + + captionRegion.children.push(captionElement); + + var timecode:String = timedTextElement.begin.toString(); + if(timelineEventsHash[timecode]){ + CaptionElement(timelineEventsHash[timecode]).siblings.push(captionElement); + } else { + timelineEventsHash[timecode] = captionElement; + _captionElements.push(captionElement); + } + + _document.addCaptionElement(captionElement); + _document.captionRegionsHash[regionName].children.push(captionElement); + + } + } + else if (timedTextElement.children) + { + var count:uint = 0; + var children:Vector. = timedTextElement.children; + var j:TimedTextElementBase; + for each(j in children) + { + AsyncThread.queue(buildCaptions, [ j, regionElementsHash, captionRegionsHash, timelineEventsHash ] ); + } + } + if(remainingNodeCount<=0) + { + parseEvent = new ParseEvent(ParseEvent.PROGRESS); + parseEvent.data = createParseEventData(null, regionElementsHash, captionRegionsHash, timelineEventsHash); + + dispatchEvent( parseEvent ); + } else { + // trace(SMPTETTParser.REMAINING_NODE_COUNT); + } + } + + protected function mapToCaptionRegion(regionElement:RegionElement):CaptionRegion + { + var endTime:Number = (regionElement.end.totalSeconds >= TimeSpan.MAX_VALUE.totalSeconds) + ? TimeSpan.MAX_VALUE.totalSeconds + : regionElement.end.totalSeconds; + + var captionRegion:CaptionRegion = new CaptionRegion(regionElement.begin.totalSeconds, endTime, regionElement.id); + captionRegion.id = regionElement.id; + captionRegion.style = TimedTextStyleParser.mapStyle(regionElement, regionElement); + + for each (var element:TimedTextElementBase in regionElement.children) + { + + var child:TimedTextElement = buildTimedTextElements(element, regionElement); + + if (child && child is TimedTextAnimation) + { + captionRegion.animations.push(child); + } + } + return captionRegion; + } + + protected function mapToCaption(pElement:PElement, region:RegionElement):CaptionElement + { + var captionElement:CaptionElement = buildTimedTextElements(pElement, region) as CaptionElement; + captionElement.id = (pElement.id) ? pElement.id : getTimer().toString(); + return captionElement; + } + + private function buildTimedTextElements(element:TimedTextElementBase, region:RegionElement):TimedTextElement + { + // trace(region.id+" buildTimedTextElements: "+ element+" "+(element.hasOwnProperty("text") ? element["text"]:"")); + + var timedTextElement:TimedTextElement = createTimedTextElement(element, region); + + for each (var c:TimedTextElementBase in element.children) + { + var child:TimedTextElement = buildTimedTextElements(c, region); + if (!child) continue; + + child.parentElement = timedTextElement; + + if (child is TimedTextAnimation) + { + timedTextElement.animations.push(child); + } else if (child is CaptionElement) + { + CaptionElement(child).index = timedTextElement.children.length; + timedTextElement.children.push(child); + } + } + return timedTextElement; + } + + private function createTimedTextElement(element:TimedTextElementBase, region:RegionElement):TimedTextElement + { + var captionElement:TimedTextElement = (element is SetElement) + ? TimedTextElement(buildCaptionAnimationElement(element)) + : new CaptionElement(element.begin.totalSeconds, element.end.totalSeconds) as TimedTextElement; + + if (captionElement is CaptionElement && region) + { + CaptionElement(captionElement).regionId = region.id; + } + + // captionElement.end = element.end.totalSeconds; + // captionElement.begin = element.begin.totalSeconds; + + if (element is BrElement) + { + captionElement.captionElementType = TimedTextElementType.LineBreak; + } else if (element is AnonymousSpanElement) + { + var aSpan:AnonymousSpanElement = element as AnonymousSpanElement; + captionElement.captionElementType = TimedTextElementType.Text; + captionElement.content = aSpan.text; + + if (element.parent is SpanElement) + captionElement.style = TimedTextStyleParser.mapStyle(TimedTextElementBase(element.parent), region); + + remainingNodeCount--; + } + else if (!(element is SetElement)) + { + captionElement.captionElementType = (element is SpanElement) ? TimedTextElementType.SupParagraphGroupElement : TimedTextElementType.Container; + captionElement.style = TimedTextStyleParser.mapStyle(element, region); + } + return captionElement; + } + + private function buildCaptionAnimationElement(element:TimedTextElementBase):TimedTextAnimation + { + var propertyName:String; + + for each(var i:TimedTextAttributeBase in element.attributes) { + if(TimedTextStyleParser.isValidAnimationPropertyName(i.localName)){ + propertyName = i.localName; + break; + } + } + if(propertyName && propertyName.length>0) { + var tta:TimedTextAnimation = new TimedTextAnimation(element.begin.totalSeconds,element.end.totalSeconds); + tta.captionElementType = TimedTextElementType.Animation; + tta.propertyName = propertyName; + tta.style = TimedTextStyleParser.mapStyle(element, null); + return tta; + } else { + return null; + } + } + + protected function createParseEventData(i_timedTextElement:TimedTextElementBase=null, i_regionElementsHash:Dictionary=null, i_captionRegionsHash:Dictionary=null, i_timelineEventsHash:Dictionary=null):ParseEventData + { + return new ParseEventData(i_timedTextElement,i_regionElementsHash, i_captionRegionsHash, i_timelineEventsHash); + } + + /** + * @private + */ + private function debug(msg:String):void + { + if (DEBUG) + { + trace(msg); + if (ExternalInterface.available) + ExternalInterface.call("function(msg){ if (console && console.log) console.log(msg); }",msg); + } + } + } +} + +class ParseEventData +{ + import flash.utils.Dictionary; + + import org.osmf.smpte.tt.model.TimedTextElementBase; + + public var timedTextElement:TimedTextElementBase=null; + public var regionElementsHash:Dictionary=null; + public var captionRegionsHash:Dictionary=null; + public var timelineEventsHash:Dictionary=null; + + public function ParseEventData(i_timedTextElement:TimedTextElementBase=null, i_regionElementsHash:Dictionary=null, i_captionRegionsHash:Dictionary=null, i_timelineEventsHash:Dictionary=null) + { + if(i_timedTextElement) timedTextElement = i_timedTextElement; + if(i_regionElementsHash) regionElementsHash = i_regionElementsHash; + if(i_captionRegionsHash) captionRegionsHash = i_captionRegionsHash; + if(i_timelineEventsHash) timelineEventsHash = i_timelineEventsHash; + } +} diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/SMPTETTParserAsync.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/SMPTETTParserAsync.as new file mode 100644 index 0000000..b862978 --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/SMPTETTParserAsync.as @@ -0,0 +1,182 @@ +package org.osmf.smpte.tt.parsing +{ + import flash.utils.Dictionary; + import flash.utils.getTimer; + + import org.osmf.smpte.tt.captions.CaptionElement; + import org.osmf.smpte.tt.captions.CaptionRegion; + import org.osmf.smpte.tt.events.ParseEvent; + import org.osmf.smpte.tt.model.PElement; + import org.osmf.smpte.tt.model.RegionElement; + import org.osmf.smpte.tt.model.TimedTextAttributeBase; + import org.osmf.smpte.tt.model.TimedTextElementBase; + import org.osmf.smpte.tt.model.TtElement; + import org.osmf.smpte.tt.parsing.conditions.ParsingCondition; + import org.osmf.smpte.tt.parsing.conditions.ParsingConditionFactory; + import org.osmf.smpte.tt.timing.TimeExpression; + import org.osmf.smpte.tt.timing.TreeType; + import org.osmf.smpte.tt.utilities.AsyncThread; + + [Event(name="partial", type="org.osmf.smpte.tt.events.ParseEvent")] + + public class SMPTETTParserAsync extends SMPTETTParser + { + private var partialCriteriaMet:Boolean = false; + private var partialEventFired:Boolean = false; + + private var totalNodeCount:int; + private var documentDuration:Number; + private var _parsingCondition:ParsingCondition + + + public function SMPTETTParserAsync() + { + super(); + //trace("SMPTETTParserByNode"); + } + + + public function get parsingCondition():ParsingCondition + { + if (! _parsingCondition) + { + _parsingCondition = ParsingConditionFactory.getCondition(); + _parsingCondition.setDuration(documentDuration); + } + return _parsingCondition; + } + + public function set parsingCondition(value:ParsingCondition):void + { + _parsingCondition = value; + } + + protected override function buildRegions(document:TtElement):void + { + super.buildRegions(document); + totalNodeCount = document.totalNodeCount; + documentDuration = document.body.duration.duration + } + + + protected override function buildCaptions(timedTextElement:TimedTextElementBase, regionElementsHash:Dictionary, captionRegionsHash:Dictionary, timelineEventsHash:Dictionary):void + { + var pElement:PElement = timedTextElement as PElement; + if (pElement != null) + { + buildCaptionWithPElement(timedTextElement,pElement,regionElementsHash,captionRegionsHash,timelineEventsHash); + } + else if (timedTextElement.children) + { + buildCaptionWithChildren(timedTextElement,regionElementsHash,captionRegionsHash,timelineEventsHash); + } + + determineBuildCaptionProgress(timedTextElement,regionElementsHash,captionRegionsHash,timelineEventsHash); + } + + private function buildCaptionWithPElement(timedTextElement:TimedTextElementBase, pElement:PElement, regionElementsHash:Dictionary, captionRegionsHash:Dictionary, timelineEventsHash:Dictionary):void + { + //trace ("buildCaptionWithPElement: Start" + getTimer()) + var regionNameAttribute:TimedTextAttributeBase; + + //For each loop, looks like it has 5 nodes, and region is the first + for each(var i:TimedTextAttributeBase in timedTextElement.attributes) + { + if(i.localName=="region"){ + regionNameAttribute = i; + break; + } + } + + //get Computed Style has recursion + var computedRegionName:String = pElement.getComputedStyle("region",null); + + + var regionName:String = (regionNameAttribute) + ? regionNameAttribute.value + : ((computedRegionName && computedRegionName!="") + ? computedRegionName + : RegionElement.DEFAULT_REGION_NAME); + var regionElement:RegionElement; + if (regionElementsHash[regionName] && captionRegionsHash[regionName]) + { + regionElement = regionElementsHash[regionName]; + + //Map to Caption is the offender (2ms execution time) + var captionElement:CaptionElement = mapToCaption(pElement, regionElement) as CaptionElement; + var captionRegion:CaptionRegion = captionRegionsHash[regionName]; + + captionElement.index = captionRegion.children.length; + + captionRegion.children.push(captionElement); + + var timecode:String = timedTextElement.begin.toString(); + + if(timelineEventsHash[timecode]){ + CaptionElement(timelineEventsHash[timecode]).siblings.push(captionElement); + } else { + timelineEventsHash[timecode] = captionElement; + _captionElements.push(captionElement); + } + + _document.addCaptionElement(captionElement); + _document.captionRegionsHash[regionName].children.push(captionElement); + + //trace("buildCaptionWithPElement: end:" + getTimer()); + } + } + + private function buildCaptionWithChildren(timedTextElement:TimedTextElementBase, regionElementsHash:Dictionary, captionRegionsHash:Dictionary, timelineEventsHash:Dictionary):void + { + //trace("buildCaptionWithChildren:" + timedTextElement.children.length) + var count:uint = 0; + var children:Vector. = timedTextElement.children; + var j:TimedTextElementBase; + for each(j in children) + { + AsyncThread.queue(buildCaptions, [ j, regionElementsHash, captionRegionsHash, timelineEventsHash ] ); + } + } + + private function determineBuildCaptionProgress(timedTextElement:TimedTextElementBase, regionElementsHash:Dictionary, captionRegionsHash:Dictionary, timelineEventsHash:Dictionary):void + { + var parseEvent:ParseEvent; + if(isAllNodesProcessed()) + { + parseEvent = new ParseEvent(ParseEvent.PROGRESS); + parseEvent.data = createParseEventData(null, regionElementsHash, captionRegionsHash, timelineEventsHash); + + } + else if (isPartiallyProcessed(timedTextElement)) + { + // trace("determineBuildCaptionProgress: PARTIAL " + parsingCondition.debugString() + " @ " + (getTimer()-parseTime)/1000+"s") + parseEvent = new ParseEvent(ParseEvent.PARTIAL); + parseEvent.data = _document; + } + + if (parseEvent) + { + dispatchEvent(parseEvent); + } + } + + private function isAllNodesProcessed():Boolean + { + return remainingNodeCount<=0; + } + + private function isPartiallyProcessed(timedTextElement:TimedTextElementBase):Boolean + { + var rtn:Boolean = false; + + //Parsing conditions are only relevant to PElements + //All other incoming elements are structural, and not relevant to captions + if (timedTextElement is PElement) + { + rtn = parsingCondition.evaluate(timedTextElement); + } + return rtn; + } + + } +} diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/TimedTextStyleParser.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/TimedTextStyleParser.as old mode 100755 new mode 100644 index bf5a57e..aa0b4c5 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/TimedTextStyleParser.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/TimedTextStyleParser.as @@ -1,406 +1,423 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.parsing -{ - import flash.text.engine.FontPosture; - import flash.text.engine.FontWeight; - import flash.utils.Dictionary; - - import flashx.textLayout.formats.FormatValue; - import flashx.textLayout.formats.WhiteSpaceCollapse; - - import org.osmf.smpte.tt.captions.DisplayAlign; - import org.osmf.smpte.tt.captions.Length; - import org.osmf.smpte.tt.captions.Overflow; - import org.osmf.smpte.tt.captions.ShowBackground; - import org.osmf.smpte.tt.captions.TextAlignment; - import org.osmf.smpte.tt.captions.TimedTextStyle; - import org.osmf.smpte.tt.enums.Unit; - import org.osmf.smpte.tt.errors.SMPTETTException; - import org.osmf.smpte.tt.logging.SMPTETTLogging; - import org.osmf.smpte.tt.model.RegionElement; - import org.osmf.smpte.tt.model.TimedTextElementBase; - import org.osmf.smpte.tt.styling.AutoExtent; - import org.osmf.smpte.tt.styling.AutoOrigin; - import org.osmf.smpte.tt.styling.ColorExpression; - import org.osmf.smpte.tt.styling.Extent; - import org.osmf.smpte.tt.styling.FontSize; - import org.osmf.smpte.tt.styling.FontStyleAttributeValue; - import org.osmf.smpte.tt.styling.FontWeightAttributeValue; - import org.osmf.smpte.tt.styling.LineHeight; - import org.osmf.smpte.tt.styling.NormalHeight; - import org.osmf.smpte.tt.styling.NumberPair; - import org.osmf.smpte.tt.styling.Origin; - import org.osmf.smpte.tt.styling.PaddingThickness; - import org.osmf.smpte.tt.styling.TextDecorationAttributeValue; - import org.osmf.smpte.tt.styling.TextOutline; - import org.osmf.smpte.tt.styling.Visibility; - import org.osmf.smpte.tt.styling.WrapOption; - import org.osmf.smpte.tt.styling.WritingMode; - import org.osmf.smpte.tt.utilities.DictionaryUtils; - import org.osmf.smpte.tt.vocabulary.Styling; - - /** - * Parses style information about a timed text marker. - *

      Style information determines the appearance of the marker text. - * This class uses the style information defined in XML and creates corresponding - * TimedTextStyle objects.

      - *

      Styles are defined in the W3C TTAF 1.0 specification.

      - */ - public class TimedTextStyleParser - { - private static const defaultStyle:TimedTextStyle = new TimedTextStyle(); - - public function TimedTextStyleParser() - { - } - - internal static function isValidAnimationPropertyName(name:String):Boolean - { - var ret:Boolean = false; - switch (name) - { - case "backgroundColor": - ret = true; - break; - case "color": - ret = true; - break; - case "displayAlign": - ret = true; - break; - case "display": - ret = true; - break; - case "extent": - ret = true; - break; - case "fontFamily": - ret = true; - break; - case "fontSize": - ret = true; - break; - case "fontStyle": - ret = true; - break; - case "fontWeight": - ret = true; - break; - case "lineHeight": - ret = true; - break; - case "opacity": - ret = true; - break; - case "origin": - ret = true; - break; - case "overflow": - ret = true; - break; - case "padding": - ret = true; - break; - case "showBackground": - ret = true; - break; - case "textAlign": - ret = true; - break; - case "visibility": - ret = true; - break; - case "wrapOption": - ret = true; - break; - case "zIndex": - ret = true; - break; - } - return ret; - } - - private static var _numberPairXref:Dictionary = new Dictionary(); - public static function getNumberPair(value:String):NumberPair - { - if (DictionaryUtils.containsKey(_numberPairXref, value)) - { - return new NumberPair(_numberPairXref[value]); - } - else - { - var pair:NumberPair = new NumberPair(value); - _numberPairXref[value] = pair; - return pair; - } - } - - // captions will usually use a handful of colors, we'll cache them to reduce resource usage. - private static var _cachedBrushes:Dictionary = new Dictionary(); - public static function getCachedBrush(src:ColorExpression):ColorExpression - { - if (DictionaryUtils.containsKey(_cachedBrushes,src.argb)) - { - return _cachedBrushes[src.argb]; - } - else - { - _cachedBrushes[src.argb] = src; - return src; - } - } - - internal static function mapStyle(styleElement:TimedTextElementBase, region:RegionElement):TimedTextStyle - { - var style:TimedTextStyle = new TimedTextStyle(); - - if(styleElement.id){ - style.styleName = styleElement.id; - } - - // backgroundColor - var backgroundColor:ColorExpression = - styleElement.getComputedStyle(Styling.TTML_STYLING_BACKGROUNDCOLOR.localName, region) as ColorExpression; - style.backgroundColor = (backgroundColor!=null) - ? getCachedBrush(backgroundColor).color - : defaultStyle.backgroundColor; - style.backgroundAlpha = (backgroundColor!=null) - ? getCachedBrush(backgroundColor).alpha - : defaultStyle.backgroundAlpha; - - // color - var color:ColorExpression = - styleElement.getComputedStyle(Styling.TTML_STYLING_COLOR.localName, region) as ColorExpression; - style.color = (color!=null) - ? getCachedBrush(color).color - : defaultStyle.color; - style.textAlpha = (color!=null) - ? getCachedBrush(color).alpha - : defaultStyle.textAlpha; - - // direction - var direction:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_DIRECTION.localName, region) as String; - style.direction = (direction=="rtl") - ? direction - : defaultStyle.direction; - - // display - var display:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_DISPLAY.localName, region) as String; - style.display =(display!=null && display=="none") - ? display - : defaultStyle.display; - - // displayAlign - var displayAlign:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_DISPLAYALIGN.localName, region) as String; - var parsedDisplayAlign:DisplayAlign = DisplayAlign.parseConstant(displayAlign); - style.displayAlign = (parsedDisplayAlign!=null) - ? parsedDisplayAlign.value - : defaultStyle.displayAlign; - - // extent - var extent:org.osmf.smpte.tt.styling.Extent = - styleElement.getComputedStyle(Styling.TTML_STYLING_EXTENT.localName, region) as org.osmf.smpte.tt.styling.Extent; - if (extent!=null && !extent.isEmpty()) - { - style.extent = extent; - } else - { - style.extent = defaultStyle.extent; - } - - // fontFamily - var fontFamily:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_FONTFAMILY.localName, region) as String; - style.fontFamily = (fontFamily && fontFamily.length>0 && fontFamily!="default") - ? fontFamily - : defaultStyle.fontFamily; - - // fontSize - var ttFontSize:FontSize= - styleElement.getComputedStyle(Styling.TTML_STYLING_FONTSIZE.localName, region) as FontSize; - if(ttFontSize!=null && ttFontSize is FontSize) - { - style.ttFontSize = ttFontSize; - } else - { - style.ttFontSize = defaultStyle.ttFontSize; - } - - // fontStyle - var fontStyle:FontStyleAttributeValue = - styleElement.getComputedStyle(Styling.TTML_STYLING_FONTSTYLE.localName, region) as FontStyleAttributeValue; - if(fontStyle!=null && fontStyle is FontStyleAttributeValue) - { - style.fontStyle = (fontStyle == FontStyleAttributeValue.ITALIC || - fontStyle == FontStyleAttributeValue.OBLIQUE || - fontStyle == FontStyleAttributeValue.REVERSE_OBLIQUE) - ? FontPosture.ITALIC - : defaultStyle.fontStyle; - } else - { - style.fontStyle = defaultStyle.fontStyle; - } - - // fontWeight - var fontWeight:FontWeightAttributeValue = - styleElement.getComputedStyle(Styling.TTML_STYLING_FONTWEIGHT.localName, region) as FontWeightAttributeValue; - style.fontWeight = (fontWeight!=null && (fontWeight == FontWeightAttributeValue.BOLD)) - ? FontWeight.BOLD - : defaultStyle.fontWeight; - - // lineHeight - var ttLineHeight:LineHeight = - styleElement.getComputedStyle(Styling.TTML_STYLING_LINEHEIGHT.localName, region) as LineHeight; - - style.ttLineHeight = (ttLineHeight!=null && !(ttLineHeight is NormalHeight)) - ? ttLineHeight - : defaultStyle.ttLineHeight; - - // opacity - var opacity:Number = - styleElement.getComputedStyle(Styling.TTML_STYLING_OPACITY.localName, region) as Number; - style.opacity = (!isNaN(opacity) && opacity>=0) - ? opacity - : defaultStyle.opacity; - - // origin - var origin:org.osmf.smpte.tt.styling.Origin = - styleElement.getComputedStyle(Styling.TTML_STYLING_ORIGIN.localName, region) as org.osmf.smpte.tt.styling.Origin; - if(origin!=null && !origin.isEmpty()){ - style.origin = origin; - } else { - style.origin = defaultStyle.origin; - } - - // overflow - var overflow:String = styleElement.getComputedStyle(Styling.TTML_STYLING_OVERFLOW.localName, region) as String; - var parsedOverflow:Overflow = Overflow.parseConstant(overflow); - style.overflow = (parsedOverflow!=null) - ? parsedOverflow.value - : defaultStyle.overflow; - - var padding:org.osmf.smpte.tt.styling.PaddingThickness = - styleElement.getComputedStyle(Styling.TTML_STYLING_PADDING.localName, region) as org.osmf.smpte.tt.styling.PaddingThickness; - if(padding!=null && !padding.isEmpty()){ - style.padding = padding; - } else { - style.padding = defaultStyle.padding; - } - - var showBackground:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_SHOWBACKGROUND.localName, region) as String; - var parsedShowBackground:ShowBackground = ShowBackground.parseConstant(showBackground); - style.showBackground = parsedShowBackground!=null - ? parsedShowBackground.value - : defaultStyle.showBackground; - - var textAlign:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_TEXTALIGN.localName, region) as String; - var parsedTextAlign:TextAlignment = TextAlignment.parseConstant(textAlign); - style.textAlign = (parsedTextAlign!=null) - ? parsedTextAlign.value - : defaultStyle.textAlign; - - var textDecoration:TextDecorationAttributeValue = - styleElement.getComputedStyle(Styling.TTML_STYLING_TEXTDECORATION.localName, region) as TextDecorationAttributeValue; - if(textDecoration!=null) - { - switch(textDecoration.value){ - case "underline": - style.textDecoration = flashx.textLayout.formats.TextDecoration.UNDERLINE; - break; - case "noUnderline": - style.textDecoration = flashx.textLayout.formats.TextDecoration.NONE; - break; - case "throughline": - style.lineThrough = true; - break; - case "noLinethrough": - style.lineThrough = false; - break; - case "none" : - style.textDecoration = flashx.textLayout.formats.TextDecoration.NONE; - style.lineThrough = false; - break; - } - } - - var textOutline:TextOutline = - styleElement.getComputedStyle(Styling.TTML_STYLING_TEXTOUTLINE.localName, region) as TextOutline; - style.textOutline = (textOutline!=null) - ? textOutline - : defaultStyle.textOutline; - - - - var unicodeBidi:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_UNICODEBIDI.localName, region) as String; - style.unicodeBidi = (unicodeBidi!=null - && (unicodeBidi=="embed" || unicodeBidi=="bidiOverride")) - ? unicodeBidi - : defaultStyle.unicodeBidi; - var visibility:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_VISIBILITY.localName, region) as String; - style.visibility = (visibility!=null && visibility==Visibility.HIDDEN.value) - ? visibility - : defaultStyle.visibility; - style.whiteSpaceCollapse = - ((styleElement.getComputedStyle("space", region) as String)=="preserve") - ? WhiteSpaceCollapse.PRESERVE - : WhiteSpaceCollapse.COLLAPSE; - - var wrapOption:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_WRAPOPTION.localName, region) as String; - var parsedWrapOption:WrapOption = WrapOption.parseConstant(wrapOption); - style.wrapOption = (parsedWrapOption!=null) - ? parsedWrapOption.value - : defaultStyle.wrapOption; - - var writingMode:String = - styleElement.getComputedStyle(Styling.TTML_STYLING_WRITINGMODE.localName, region) as String; - var parsedWritingMode:WritingMode = WritingMode.parseConstant(writingMode); - style.writingMode = (parsedWritingMode!=null) - ? parsedWritingMode.value - : defaultStyle.writingMode; - var zIndex:* = styleElement.getComputedStyle(Styling.TTML_STYLING_ZINDEX.localName, region); - try - { - if (!(zIndex is String)) - { - var tmp:Number = Number(zIndex); - style.zIndex = int(tmp); - } - else - { - style.zIndex = 0; - } - } - catch(e:Error) - { - style.zIndex = 0; - } - return style; - } - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.parsing +{ + import flash.text.engine.FontPosture; + import flash.text.engine.FontWeight; + import flash.utils.Dictionary; + + import flashx.textLayout.formats.TextDecoration; + import flashx.textLayout.formats.WhiteSpaceCollapse; + + import org.osmf.smpte.tt.captions.DisplayAlign; + import org.osmf.smpte.tt.captions.Overflow; + import org.osmf.smpte.tt.captions.ShowBackground; + import org.osmf.smpte.tt.captions.TextAlignment; + import org.osmf.smpte.tt.captions.TimedTextStyle; + import org.osmf.smpte.tt.model.RegionElement; + import org.osmf.smpte.tt.model.TimedTextElementBase; + import org.osmf.smpte.tt.styling.ColorExpression; + import org.osmf.smpte.tt.styling.Extent; + import org.osmf.smpte.tt.styling.FontSize; + import org.osmf.smpte.tt.styling.FontStyleAttributeValue; + import org.osmf.smpte.tt.styling.FontWeightAttributeValue; + import org.osmf.smpte.tt.styling.LineHeight; + import org.osmf.smpte.tt.styling.NormalHeight; + import org.osmf.smpte.tt.styling.NumberPair; + import org.osmf.smpte.tt.styling.Origin; + import org.osmf.smpte.tt.styling.PaddingThickness; + import org.osmf.smpte.tt.styling.TextDecorationAttributeValue; + import org.osmf.smpte.tt.styling.TextOutline; + import org.osmf.smpte.tt.styling.Visibility; + import org.osmf.smpte.tt.styling.WrapOption; + import org.osmf.smpte.tt.styling.WritingMode; + import org.osmf.smpte.tt.vocabulary.Styling; + + /** + * Parses style information about a timed text marker. + *

      Style information determines the appearance of the marker text. + * This class uses the style information defined in XML and creates corresponding + * TimedTextStyle objects.

      + *

      Styles are defined in the W3C TTAF 1.0 specification.

      + */ + public class TimedTextStyleParser + { + private static const defaultStyle:TimedTextStyle = new TimedTextStyle(); + + public function TimedTextStyleParser() + { + } + + internal static function isValidAnimationPropertyName(name:String):Boolean + { + var ret:Boolean = false; + switch (name) + { + case "backgroundColor": + ret = true; + break; + case "color": + ret = true; + break; + case "displayAlign": + ret = true; + break; + case "display": + ret = true; + break; + case "extent": + ret = true; + break; + case "fontFamily": + ret = true; + break; + case "fontSize": + ret = true; + break; + case "fontStyle": + ret = true; + break; + case "fontWeight": + ret = true; + break; + case "lineHeight": + ret = true; + break; + case "lineThrough": + ret = true; + break; + case "opacity": + ret = true; + break; + case "origin": + ret = true; + break; + case "overflow": + ret = true; + break; + case "padding": + ret = true; + break; + case "showBackground": + ret = true; + break; + case "textAlign": + ret = true; + break; + case "textDecoration": + ret = true; + break; + case "textOutline": + ret = true; + break; + case "visibility": + ret = true; + break; + case "wrapOption": + ret = true; + break; + case "zIndex": + ret = true; + break; + } + return ret; + } + + private static var _numberPairXref:Dictionary = new Dictionary(); + public static function getNumberPair(value:String):NumberPair + { + if (_numberPairXref[value] !== undefined) + { + return new NumberPair(_numberPairXref[value]); + } + else + { + var pair:NumberPair = new NumberPair(value); + _numberPairXref[value] = pair; + return pair; + } + } + + // captions will usually use a handful of colors, we'll cache them to reduce resource usage. + private static var _cachedBrushes:Dictionary = new Dictionary(); + public static function getCachedBrush(src:ColorExpression):ColorExpression + { + if (_cachedBrushes[src.argb] !== undefined) + { + return _cachedBrushes[src.argb]; + } + else + { + _cachedBrushes[src.argb] = src; + return src; + } + } + + internal static function mapStyle(styleElement:TimedTextElementBase, region:RegionElement):TimedTextStyle + { + var style:TimedTextStyle = new TimedTextStyle(); + + if(styleElement.id) style.styleName = styleElement.id; + + // backgroundColor + var backgroundColor:ColorExpression = + styleElement.getComputedStyle(Styling.TTML_STYLING_BACKGROUNDCOLOR.localName, region) as ColorExpression; + style.backgroundColor = (backgroundColor!=null) + ? getCachedBrush(backgroundColor).color + : defaultStyle.backgroundColor; + style.backgroundAlpha = (backgroundColor!=null) + ? getCachedBrush(backgroundColor).alpha + : defaultStyle.backgroundAlpha; + + // color + var color:ColorExpression = + styleElement.getComputedStyle(Styling.TTML_STYLING_COLOR.localName, region) as ColorExpression; + style.color = (color!=null) + ? getCachedBrush(color).color + : defaultStyle.color; + style.textAlpha = (color!=null) + ? getCachedBrush(color).alpha + : defaultStyle.textAlpha; + + // direction + var direction:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_DIRECTION.localName, region) as String; + style.direction = (direction=="rtl") + ? direction + : defaultStyle.direction; + + // display + var display:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_DISPLAY.localName, region) as String; + style.display =(display!=null && display=="none") + ? display + : defaultStyle.display; + + // displayAlign + var displayAlign:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_DISPLAYALIGN.localName, region) as String; + var parsedDisplayAlign:DisplayAlign = DisplayAlign.parseConstant(displayAlign); + style.displayAlign = (parsedDisplayAlign!=null) + ? parsedDisplayAlign.value + : defaultStyle.displayAlign; + + // extent + var extent:org.osmf.smpte.tt.styling.Extent = + styleElement.getComputedStyle(Styling.TTML_STYLING_EXTENT.localName, region) as org.osmf.smpte.tt.styling.Extent; + if (extent!=null && !extent.isEmpty()) + { + style.extent = extent; + } else + { + style.extent = defaultStyle.extent; + } + + // fontFamily + var fontFamily:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_FONTFAMILY.localName, region) as String; + style.fontFamily = (fontFamily && fontFamily.length>0 && fontFamily!="default") + ? fontFamily + : defaultStyle.fontFamily; + + // fontSize + var ttFontSize:FontSize= + styleElement.getComputedStyle(Styling.TTML_STYLING_FONTSIZE.localName, region) as FontSize; + if(ttFontSize!=null && ttFontSize is FontSize) + { + style.ttFontSize = ttFontSize; + } else + { + style.ttFontSize = defaultStyle.ttFontSize; + } + + // fontStyle + var fontStyle:FontStyleAttributeValue = + styleElement.getComputedStyle(Styling.TTML_STYLING_FONTSTYLE.localName, region) as FontStyleAttributeValue; + if(fontStyle!=null && fontStyle is FontStyleAttributeValue) + { + style.fontStyle = (fontStyle == FontStyleAttributeValue.ITALIC || + fontStyle == FontStyleAttributeValue.OBLIQUE || + fontStyle == FontStyleAttributeValue.REVERSE_OBLIQUE) + ? FontPosture.ITALIC + : defaultStyle.fontStyle; + } else + { + style.fontStyle = defaultStyle.fontStyle; + } + + // fontWeight + var fontWeight:FontWeightAttributeValue = + styleElement.getComputedStyle(Styling.TTML_STYLING_FONTWEIGHT.localName, region) as FontWeightAttributeValue; + style.fontWeight = (fontWeight!=null && (fontWeight == FontWeightAttributeValue.BOLD)) + ? FontWeight.BOLD + : defaultStyle.fontWeight; + + // lineHeight + var ttLineHeight:LineHeight = + styleElement.getComputedStyle(Styling.TTML_STYLING_LINEHEIGHT.localName, region) as LineHeight; + + style.ttLineHeight = (ttLineHeight!=null && !(ttLineHeight is NormalHeight)) + ? ttLineHeight + : defaultStyle.ttLineHeight; + + // opacity + var opacity:Number = + styleElement.getComputedStyle(Styling.TTML_STYLING_OPACITY.localName, region) as Number; + style.opacity = (!isNaN(opacity) && opacity>=0) + ? opacity + : defaultStyle.opacity; + + // origin + var origin:org.osmf.smpte.tt.styling.Origin = + styleElement.getComputedStyle(Styling.TTML_STYLING_ORIGIN.localName, region) as org.osmf.smpte.tt.styling.Origin; + if(origin!=null && !origin.isEmpty()){ + style.origin = origin; + } else { + style.origin = defaultStyle.origin; + } + + // overflow + var overflow:String = styleElement.getComputedStyle(Styling.TTML_STYLING_OVERFLOW.localName, region) as String; + var parsedOverflow:Overflow = Overflow.parseConstant(overflow); + style.overflow = (parsedOverflow!=null) + ? parsedOverflow.value + : defaultStyle.overflow; + + var padding:org.osmf.smpte.tt.styling.PaddingThickness = + styleElement.getComputedStyle(Styling.TTML_STYLING_PADDING.localName, region) as org.osmf.smpte.tt.styling.PaddingThickness; + if(padding!=null && !padding.isEmpty()){ + style.padding = padding; + } else { + style.padding = defaultStyle.padding; + } + + // showBackground + var showBackground:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_SHOWBACKGROUND.localName, region) as String; + var parsedShowBackground:ShowBackground = ShowBackground.parseConstant(showBackground); + style.showBackground = parsedShowBackground!=null + ? parsedShowBackground.value + : defaultStyle.showBackground; + + // textAlign + var textAlign:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_TEXTALIGN.localName, region) as String; + var parsedTextAlign:TextAlignment = TextAlignment.parseConstant(textAlign); + style.textAlign = (parsedTextAlign!=null) + ? parsedTextAlign.value + : defaultStyle.textAlign; + + // textDecoration + var textDecoration:TextDecorationAttributeValue = + styleElement.getComputedStyle(Styling.TTML_STYLING_TEXTDECORATION.localName, region) as TextDecorationAttributeValue; + if(textDecoration) + { + switch(textDecoration) + { + case TextDecorationAttributeValue.UNDERLINE: + style.textDecoration = TextDecoration.UNDERLINE; + break; + case TextDecorationAttributeValue.NO_UNDERLINE: + style.textDecoration = TextDecoration.NONE; + break; + } + } + + var lineThrough:TextDecorationAttributeValue = + styleElement.getComputedStyle("lineThrough", region) as TextDecorationAttributeValue; + if(lineThrough) + { + switch(lineThrough) + { + case TextDecorationAttributeValue.LINE_THROUGH: + style.lineThrough = true; + break; + case TextDecorationAttributeValue.NO_LINE_THROUGH: + style.lineThrough = false; + break; + } + } + + // textOutline + var textOutline:TextOutline = + styleElement.getComputedStyle(Styling.TTML_STYLING_TEXTOUTLINE.localName, region) as TextOutline; + style.textOutline = (textOutline!=null) + ? textOutline + : defaultStyle.textOutline; + + // unicodeBidi + var unicodeBidi:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_UNICODEBIDI.localName, region) as String; + style.unicodeBidi = (unicodeBidi!=null + && (unicodeBidi=="embed" || unicodeBidi=="bidiOverride")) + ? unicodeBidi + : defaultStyle.unicodeBidi; + + // visiblility + var visibility:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_VISIBILITY.localName, region) as String; + style.visibility = (visibility && visibility==Visibility.HIDDEN.value) + ? visibility + : defaultStyle.visibility; + + // whiteSpaceCollapse + style.whiteSpaceCollapse = + ((styleElement.getComputedStyle("space", region) as String)=="preserve") + ? WhiteSpaceCollapse.PRESERVE + : WhiteSpaceCollapse.COLLAPSE; + + // wrapOption + var wrapOption:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_WRAPOPTION.localName, region) as String; + var parsedWrapOption:WrapOption = WrapOption.parseConstant(wrapOption); + style.wrapOption = (parsedWrapOption!=null) + ? parsedWrapOption.value + : defaultStyle.wrapOption; + + // writingMode + var writingMode:String = + styleElement.getComputedStyle(Styling.TTML_STYLING_WRITINGMODE.localName, region) as String; + var parsedWritingMode:WritingMode = WritingMode.parseConstant(writingMode); + style.writingMode = (parsedWritingMode!=null) + ? parsedWritingMode.value + : defaultStyle.writingMode; + + // zIndex + var zIndex:* = styleElement.getComputedStyle(Styling.TTML_STYLING_ZINDEX.localName, region); + try + { + if (!(zIndex is String)) + { + var tmp:Number = Number(zIndex); + style.zIndex = int(tmp); + } + else + { + style.zIndex = 0; + } + } + catch(e:Error) + { + style.zIndex = 0; + } + return style; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/XMLToTTElementParser.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/XMLToTTElementParser.as new file mode 100644 index 0000000..1a2c3de --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/XMLToTTElementParser.as @@ -0,0 +1,432 @@ +package org.osmf.smpte.tt.parsing +{ + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.utils.Dictionary; + + import org.osmf.smpte.tt.errors.SMPTETTException; + import org.osmf.smpte.tt.events.ParseEvent; + import org.osmf.smpte.tt.model.AnonymousSpanElement; + import org.osmf.smpte.tt.model.BodyElement; + import org.osmf.smpte.tt.model.HeadElement; + import org.osmf.smpte.tt.model.PElement; + import org.osmf.smpte.tt.model.SpanElement; + import org.osmf.smpte.tt.model.TimedTextAttributeBase; + import org.osmf.smpte.tt.model.TimedTextElementBase; + import org.osmf.smpte.tt.model.TtElement; + import org.osmf.smpte.tt.model.metadata.ActorElement; + import org.osmf.smpte.tt.model.metadata.AgentElement; + import org.osmf.smpte.tt.model.metadata.CopyrightElement; + import org.osmf.smpte.tt.model.metadata.DescElement; + import org.osmf.smpte.tt.model.metadata.NameElement; + import org.osmf.smpte.tt.model.metadata.TitleElement; + import org.osmf.smpte.tt.model.parameter.ExtensionElement; + import org.osmf.smpte.tt.model.parameter.FeatureElement; + import org.osmf.smpte.tt.model.parameter.ParameterElement; + import org.osmf.smpte.tt.timing.TimeExpression; + import org.osmf.smpte.tt.timing.TreeType; + import org.osmf.smpte.tt.utilities.AsyncThread; + import org.osmf.smpte.tt.utilities.StringUtils; + import org.osmf.smpte.tt.vocabulary.Namespaces; + + [Event(name="complete", type="org.osmf.smpte.tt.events.ParseEvent")] + public class XMLToTTElementParser extends EventDispatcher + { + + private static const MILLISECONDS_PER_FRAME_FOR_PARSING:int = 50; //Lower numbers take longer, but distrupt video playback less + + private var asyncThread:AsyncThread + private var nodeRecursiveTracker:Dictionary + private var rootNode:TimedTextElementBase + + public static function parse(timedTextData:XML):XMLToTTElementParser + { + var rtn:XMLToTTElementParser = new XMLToTTElementParser(); + return rtn.startParsing(timedTextData); + } + + public function startParsing(timedTextData:XML):XMLToTTElementParser + { + initializeDefaults(); + + asyncThread = AsyncThread.create(starterFunction,[]); + asyncThread.addEventListener(Event.COMPLETE, onAsyncComplete); + nodeRecursiveTracker = new Dictionary(true); + + rootNode = parseRecursive(timedTextData, null, false); + asyncThread.runEachFrame(MILLISECONDS_PER_FRAME_FOR_PARSING); + + return this; + } + + private function initializeDefaults():void + { + TimeExpression.initializeParameters(); + ParameterElement.initializeParameters(); + } + + private function onAsyncComplete(event:Event):void + { + trace(this + " onAsyncComplete"); + dispatchEvent(new ParseEvent(ParseEvent.COMPLETE,false,false,rootNode)); + } + + private function starterFunction():void + { + trace(this + " Starting AsyncThread"); + } + + /** + * Convert an XML object to the internal TimedText classes. + * + * @param timedTextData Raw XML construct + * @param root root element of the tree + * @returns tt_element hierachy + */ + private function parseRecursive(xmlElement:XML, root:TtElement, preserveContext:Boolean):TimedTextElementBase + { + + var xmlElementNameSpace:Namespace = xmlElement.namespace(); + var xmlElementNameSpaceURI:String = xmlElementNameSpace.uri; + + if (xmlElementNameSpaceURI.length==0) + { + xmlElementNameSpace = Namespaces.TTML_NS; + xmlElementNameSpaceURI = xmlElementNameSpace.uri; + xmlElement.setNamespace(xmlElementNameSpace); + } + + var parentNode:TimedTextElementBase = setParentNodeNamespace(root,xmlElementNameSpaceURI,xmlElementNameSpace,xmlElement); + + /// if node is still null, either we failed to implement the element + /// or its an element in a foreign namespace, either way we bail. + if (parentNode == null) return null; + + //{ region test if root element + var newRoot:TtElement = (root == null) ? parentNode as TtElement : root; + + // null should only occur in the first call, + if (newRoot == null) + { + error("tt not at root of document"); + } + parentNode.root = newRoot; + //} endregion + + var localPreserve:Boolean = preserveContext; // record whether xml:space=preserve is in effect + + parentNode.setLocalStyle("preserve",localPreserve); + + //{ region process raw xml attributes into timed text equivalents + parseAttributes(xmlElement,parentNode,xmlElementNameSpace,localPreserve); + + localPreserve = parentNode.getReferentStyle("preserve"); + + //{ region process child elements + var children:XMLList = xmlElement.children(); + var childNode:XML; + for each (childNode in children) + { + incrementRecursiveNodeCount(newRoot, "child :") + AsyncThread.queue(parseChild, [childNode, parentNode, newRoot, localPreserve]); + // parseChild(childNode, parentNode, newRoot, localPreserve); + } + return parentNode; + } + + protected function setParentNodeNamespace(root:TtElement, xmlElementNameSpaceURI:String, xmlElementNameSpace:Namespace, xmlElement:XML):TimedTextElementBase + { + if (root==null){ + if(xmlElementNameSpaceURI.match(Namespaces.TTML_NS_REGEXP)) + { + Namespaces.useLegacyNamespace(xmlElementNameSpace); + } + } + + var element:String = xmlElement.localName(); + + var nameSpace:String = namespaceFromTimedTextNamespace(xmlElementNameSpaceURI); + + var parentNode:TimedTextElementBase = null; + + if (!(!nameSpace || nameSpace.length==0)) + { + // To meet naming conventions, have to manipulate the name. + var conventionName:String = StringUtils.capitalize(element) + "Element"; + + // if there is a namespace, then its a timed text element + parentNode = TimedTextElementBase.getElementFromName(nameSpace + conventionName); + parentNode.localName = element; + parentNode.namespace = xmlElementNameSpace; + } + return parentNode; + } + + + private function incrementRecursiveNodeCount(rootNode:TimedTextElementBase, debugMsg:String =""):void + { + if (nodeRecursiveTracker[rootNode] == null) + { + nodeRecursiveTracker[rootNode] = 0; + } + nodeRecursiveTracker[rootNode]++; + //trace("incrementRecursiveNodeCount " + rootNode + "("+ nodeRecursiveTracker[rootNode] +") >" + debugMsg); + } + + private function decrementRecursiveNodeCount(rootNode:TimedTextElementBase, debugMsg:String =""):void + { + nodeRecursiveTracker[rootNode]-- + // trace("decrementRecursiveNodeCount " + rootNode + "("+ nodeRecursiveTracker[rootNode] +") >" + debugMsg); + } + + private function namespaceFromTimedTextNamespace(p:String):String + { + var nsPrefix:String = ""; + switch (p) + { // got to be a better way to do this using reflection? + case "http://www.w3.org/2006/02/ttaf1": + case "http://www.w3.org/2006/04/ttaf1": + case "http://www.w3.org/2006/10/ttaf1": + case "http://www.w3.org/ns/ttml": + nsPrefix = "org.osmf.smpte.tt.model."; + break; + case "http://www.w3.org/2006/02/ttaf1#metadata": + case "http://www.w3.org/2006/04/ttaf1#metadata": + case "http://www.w3.org/2006/10/ttaf1#metadata": + case "http://www.w3.org/ns/ttml#metadata": + nsPrefix = "org.osmf.smpte.tt.model.metadata."; + break; + case "http://www.w3.org/2006/02/ttaf1#style": + case "http://www.w3.org/2006/02/ttaf1#styling": + case "http://www.w3.org/2006/04/ttaf1#style": + case "http://www.w3.org/2006/04/ttaf1#styling": + case "http://www.w3.org/2006/10/ttaf1#style": + case "http://www.w3.org/2006/10/ttaf1#styling": + case "http://www.w3.org/ns/ttml#styling": + nsPrefix = "org.osmf.smpte.tt.styling."; + break; + case "http://www.w3.org/2006/02/ttaf1#parameter": + case "http://www.w3.org/2006/04/ttaf1#parameter": + case "http://www.w3.org/2006/10/ttaf1#parameter": + case "http://www.w3.org/ns/ttml#parameter": + case "http://www.w3.org/ns/ttml/profile": + nsPrefix = "org.osmf.smpte.tt.model.parameter."; + break; + default: + nsPrefix = ""; + break; + } + return nsPrefix; + } + + protected function parseAttributes(xmlElement:XML, parentNode:TimedTextElementBase, xmlElementNameSpace:Namespace, localPreserve:Boolean):void + { + var attributes:XMLList = xmlElement.attributes(); + var xmlAttribute:XML + var attribute:TimedTextAttributeBase + for each (xmlAttribute in attributes) + { + incrementRecursiveNodeCount(parentNode.root, "Attribute: ") + AsyncThread.queue(createAttributeElement, [xmlAttribute, parentNode, xmlElementNameSpace, localPreserve]); + // createAttributeElement(xmlAttribute, parentNode, xmlElementNameSpace, localPreserve); + localPreserve = parentNode.getReferentStyle("preserve"); + } + } + + + + protected function createAttributeElement(xmlAttribute:XML, parentNode:TimedTextElementBase, xmlElementNameSpace:Namespace, localPreserve:Boolean):void + { + // copy the attribute identity + var attribute:TimedTextAttributeBase = new TimedTextAttributeBase(); + attribute.parent = parentNode as TimedTextElementBase;; + attribute.localName = xmlAttribute.localName(); + attribute.value = xmlAttribute; + + // not sure if it is absolutely correct to move + // empty namespace elements into tt namespace but seems + // to work. + attribute.namespace = (!xmlAttribute.namespace()) ? xmlElementNameSpace : xmlAttribute.namespace(); + + if(!attribute.namespace.uri && attribute.parent.namespace) { + attribute.namespace = attribute.parent.namespace; + } + + // attach new attribute to current element + parentNode.attributes.push(attribute); + + // check whether we are changing the space preserve behaviour + if (attribute.isXmlAttribute() && attribute.localName == "space") + { + localPreserve = (attribute.value == "preserve"); + // record the type of preservation as a local style. + parentNode.setLocalStyle("preserve", localPreserve); + } + + decrementRecursiveNodeCount(parentNode.root ,"Attribute: ") + } + + private function parseChild(xmlNode:XML, parentNode:TimedTextElementBase, newRoot:TtElement, localPreserve:Boolean):void + { + + /*var xmlNode:XML = obj.xmlNode, + parentNode:TimedTextElementBase = obj.parentNode, + newRoot:TtElement = obj.newRoot, + localPreserve:Boolean = obj.localPreserve;*/ + + localPreserve = parentNode.getReferentStyle("preserve"); + + switch(xmlNode.nodeKind()) + { + //text, comment, processing-instruction, attribute, or element. + case "element": + + //{ region convert XML Element to Timed Text Element + parseChildElementType(xmlNode,parentNode,newRoot,localPreserve); + //} endregion + break; + + case "text": + + //{ region convert XML Text into an anonymous span element + parseChildTextType(xmlNode,parentNode,localPreserve); + break; + } + + decrementRecursiveNodeCount(parentNode.root, "Child: ") + } + + private function parseChildTextType(xmlNode:XML, parentNode:TimedTextElementBase, localPreserve:Boolean):void + { + if (isContentElement(parentNode)) + { + //{ region elements that admit PCDATA as children get anonymous spans + var text:AnonymousSpanElement; + if (!localPreserve) + { // squeeze out all the redundant whitespace + var normalized:String = normalizeWhitespace(xmlNode); + text = new AnonymousSpanElement(normalized); + } + else + { + // preserve the raw text as it came in + text = new AnonymousSpanElement(xmlNode.toString()); + } + parentNode.children.push(text as TreeType); + text.parent = parentNode; + if(!isMetadataContentElement(parentNode) + && !isParameterContentElement(parentNode)) + { + parentNode.root.totalNodeCount++; + } + } + else + { + //{ region test non content element for non-whitespace error. + if (normalizeWhitespace(xmlNode) != " ") + { + error("Use of non whitespace in " + parentNode); + } + } + } + + + private function parseChildElementType(xmlNode:XML, parentNode:TimedTextElementBase, newRoot:TtElement, localPreserve:Boolean):void + { + var child:TimedTextElementBase = parseRecursive(xmlNode, newRoot, localPreserve); + if (child != null) + { + parentNode.children.push(child as TreeType); + + if (child is BodyElement) + { + parentNode.body = child as BodyElement; + } + if (parentNode is TtElement) + { + var ttElement:TtElement = parentNode as TtElement; + if (child is HeadElement) + { + ttElement.head = child as HeadElement; + } + } + + child.parent = parentNode; + child.root = parentNode.root; + } + } + + + /** + * Is it a content element for purposes of parenting anonymous span's? + * + * @param node + */ + private function isContentElement(node:TimedTextElementBase):Boolean + { + if (node is PElement) return true; + if (node is SpanElement) return true; + if (isMetadataContentElement(node)) return true; + if (isParameterContentElement(node)) return true; + return false; + } + + /** + * Metadata items that admit PCDATA as content + * + * @param node + */ + private function isMetadataContentElement(node:TimedTextElementBase):Boolean + { + if (node is TitleElement) return true; + if (node is NameElement) return true; + if (node is DescElement) return true; + if (node is CopyrightElement) return true; + if (node is AgentElement) return true; + if (node is ActorElement) return true; + + return false; + } + + /** + * Parameter items that admit PCDATA as content + * + * @param node + */ + private function isParameterContentElement(node:TimedTextElementBase):Boolean + { + if (node is ExtensionElement) return true; + if (node is FeatureElement) return true; + return false; + } + + private static const WHITESPACE_REGEXP:RegExp = /[\n\r\t]/g; + private static const DOUBLESPACE_REGEXP:RegExp = /\ {2}/g; + + //{ region Helper Methods + /** + * convert newlines to space, and collpase runs of space to a single space + * + * @param n + */ + private function normalizeWhitespace(n:XML):String + { + var normalized:String = n.normalize().toString().replace(WHITESPACE_REGEXP, " "); + while (DOUBLESPACE_REGEXP.test(normalized)) + { + normalized = normalized.replace(DOUBLESPACE_REGEXP, " "); + } + return normalized; + } + + protected function error(message:String):void + { + trace("[ERROR] "+ " "+ message); + /*try { + throw new SMPTETTException(message); + } catch (err:SMPTETTException){ + trace("[ERROR] "+ err +" "+ err.message); + }*/ + } + } +} \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/ParsingCondition.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/ParsingCondition.as new file mode 100644 index 0000000..2e63ef7 --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/ParsingCondition.as @@ -0,0 +1,11 @@ +package org.osmf.smpte.tt.parsing.conditions +{ + import org.osmf.smpte.tt.model.TimedTextElementBase; + + public interface ParsingCondition + { + function evaluate(timedTextElement:TimedTextElementBase):Boolean; + function setDuration(v:Number):void; + function debugString():String; + } +} \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/ParsingConditionFactory.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/ParsingConditionFactory.as new file mode 100644 index 0000000..46dd764 --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/ParsingConditionFactory.as @@ -0,0 +1,30 @@ +package org.osmf.smpte.tt.parsing.conditions +{ + import org.osmf.smpte.tt.parsing.conditions.impl.ParsingCondition_Continous; + import org.osmf.smpte.tt.parsing.conditions.impl.ParsingCondition_PercentageIntervalByTime; + import org.osmf.smpte.tt.parsing.conditions.impl.ParsingCondition_SpecificTimings; + + public class ParsingConditionFactory + { + public static function getCondition():ParsingCondition + { + return atDefinedDurations(); + } + + private static function every10PercentDuration():ParsingCondition + { + return new ParsingCondition_PercentageIntervalByTime(10); + } + + private static function atDefinedDurations():ParsingCondition + { + var definedDurationsInSeconds:Array=[100,200,300,400,500,600,700,800,900,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3100,3200,3300,3400,3500,3600,3700,3800,3900,4000,4100,4200,4300,4400,4500,4600,4700,4800,4900,5000,5100,5200,5300,5400,5500,5600,5700,5800,5900,6000,6100,6200,6300,6400,6500,6600,6700,6800,6900,7000,7100,7200]; + return new ParsingCondition_SpecificTimings(definedDurationsInSeconds); + } + + private static function continously():ParsingCondition + { + return new ParsingCondition_Continous(); + } + } +} diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_Continous.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_Continous.as new file mode 100644 index 0000000..d275d59 --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_Continous.as @@ -0,0 +1,26 @@ +package org.osmf.smpte.tt.parsing.conditions.impl +{ + import org.osmf.smpte.tt.model.TimedTextElementBase; + import org.osmf.smpte.tt.parsing.conditions.ParsingCondition; + + public class ParsingCondition_Continous implements ParsingCondition + { + public function ParsingCondition_Continous() + { + } + + public function evaluate(timedTextElement:TimedTextElementBase):Boolean + { + return true; + } + + public function setDuration(v:Number):void + { + } + + public function debugString():String + { + return this + "always true"; + } + } +} \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_PercentageIntervalByTime.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_PercentageIntervalByTime.as new file mode 100644 index 0000000..12813c5 --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_PercentageIntervalByTime.as @@ -0,0 +1,44 @@ +package org.osmf.smpte.tt.parsing.conditions.impl +{ + import org.osmf.smpte.tt.model.TimedTextElementBase; + import org.osmf.smpte.tt.parsing.conditions.ParsingCondition; + + public class ParsingCondition_PercentageIntervalByTime implements ParsingCondition + { + private var _duration:Number; + private var _percentageInterval:Number; + private var _debugOutput:String + private var _lastPercentage:Number = 0; + + public function ParsingCondition_PercentageIntervalByTime(percentageIntervalAsInt:Number=10) + { + _percentageInterval = percentageIntervalAsInt; + + } + + public function evaluate(timedTextElement:TimedTextElementBase):Boolean + { + var endTime:Number = timedTextElement.end.duration; + var pct:Number = Math.round(endTime/_duration*100); + _debugOutput = String(pct); + var condition:Boolean = pct % _percentageInterval == 0 + if (condition && pct != _lastPercentage) + { + _lastPercentage = pct; + return condition; + } + return false; + } + + public function setDuration(v:Number):void + { + _duration = v; + } + + + public function debugString():String + { + return this + "pct=" +_debugOutput; + } + } +} \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_SpecificTimings.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_SpecificTimings.as new file mode 100644 index 0000000..464c439 --- /dev/null +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/parsing/conditions/impl/ParsingCondition_SpecificTimings.as @@ -0,0 +1,43 @@ +package org.osmf.smpte.tt.parsing.conditions.impl +{ + import org.osmf.smpte.tt.model.TimedTextElementBase; + import org.osmf.smpte.tt.parsing.conditions.ParsingCondition; + + public class ParsingCondition_SpecificTimings implements ParsingCondition + { + private var timings:Array /*durations in seconds */ + private var _debugOutput:String + + public function ParsingCondition_SpecificTimings(timings:Array/*durations in seconds*/ = null) + { + this.timings = (timings)? timings:[]; + } + + public function evaluate(timedTextElement:TimedTextElementBase):Boolean + { + var rtn:Boolean = false; + var beginTime:Number = timedTextElement.begin.duration; + if (timings.length > 0) + { + var nextRequestedTime:Number = timings[0]; + if (beginTime >= nextRequestedTime) + { + rtn = true; + var lastTiming:Number =timings.shift(); + _debugOutput = String(lastTiming); + } + } + return rtn; + } + + public function setDuration(v:Number):void + { + } + + + public function debugString():String + { + return this + "timing target=" +_debugOutput; + } + } +} \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/primitives/Size.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/primitives/Size.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/primitives/Thickness.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/primitives/Thickness.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/rendering/IRenderObject.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/rendering/IRenderObject.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/rendering/Unicode.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/rendering/Unicode.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/AutoExtent.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/AutoExtent.as old mode 100755 new mode 100644 index c3bdd72..0f4f4b3 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/AutoExtent.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/AutoExtent.as @@ -21,9 +21,33 @@ package org.osmf.smpte.tt.styling { public class AutoExtent extends Extent { - public function AutoExtent() + private static var _instance:AutoExtent; + + public static function get instance():AutoExtent { - super(-1,-1); + if( _instance == null ) _instance = new AutoExtent( new SingletonLock() ); + return _instance; + } + + public function AutoExtent( lock:SingletonLock ) + { + // Verify that the lock is the correct class reference. + if ( lock is SingletonLock ) + { + super(-1,-1); + } else + { + throw new Error( "Invalid Singleton access. Use AutoExtent.instance." ); + } } } -} \ No newline at end of file +} + +/** + * This is a private class declared outside of the package + * that is only accessible to classes inside of the AutoExtent.as + * file. Because of that, no outside code is able to get a + * reference to this class to pass to the constructor, which + * enables us to prevent outside instantiation. + */ +internal class SingletonLock{}; \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/AutoOrigin.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/AutoOrigin.as old mode 100755 new mode 100644 index 14df1e2..b80c740 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/AutoOrigin.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/AutoOrigin.as @@ -1,29 +1,54 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.styling -{ - public class AutoOrigin extends Origin - { - public function AutoOrigin() - { - super(-1,-1); - } - } -} \ No newline at end of file +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.styling +{ + public class AutoOrigin extends Origin + { + private static var _instance:AutoOrigin; + + public static function get instance():AutoOrigin + { + if( _instance == null ) _instance = new AutoOrigin( new SingletonLock() ); + return _instance; + } + + public function AutoOrigin( lock:SingletonLock ) + { + // Verify that the lock is the correct class reference. + if ( lock is SingletonLock ) + { + super(-1,-1); + } else + { + throw new Error( "Invalid Singleton access. Use AutoOrigin.instance." ); + } + + } + } +} + +/** + * This is a private class declared outside of the package + * that is only accessible to classes inside of the AutoOrigin.as + * file. Because of that, no outside code is able to get a + * reference to this class to pass to the constructor, which + * enables us to prevent outside instantiation. + */ +internal class SingletonLock{}; \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/ColorExpression.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/ColorExpression.as old mode 100755 new mode 100644 index 3f4605e..f8ce457 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/ColorExpression.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/ColorExpression.as @@ -1,213 +1,226 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.styling -{ - import org.osmf.smpte.tt.errors.SMPTETTException; - import org.osmf.smpte.tt.utilities.StringUtils; - - public class ColorExpression - { - private static const hexRegExp:RegExp = /^\s*(?:#|0x)([\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f][\dA-Fa-f])([\dA-Fa-f][\dA-Fa-f])?\s*$/; - private static const rgbaRegExp:RegExp = /^\s*rgb(a)?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\)|(?:\s*,\s*(\d+(?:.?\d+)*)\)))\s*$/; - - private var _color:uint = 0x000000; - public function get color():uint - { - return _color; - } - public function set color(p_color:uint):void - { - _color = p_color; - } - - private var _alpha:Number = 1; - public function get alpha():Number { - return _alpha; - } - public function set alpha(p_alpha:Number):void { - _alpha = p_alpha; - } - - public function get argb():uint - { - //newAlpha has to be in the 0 to 255 range - var a:uint = Math.round(_alpha*0xFF); - var argb:uint = (a<<24) | _color; - return argb; - } - public function set argb(value:uint):void - { - _color = 0xFFFFFF & value; - _alpha = parseInt(String((value>>24)&0xFF),10) / 0xFF; - } - - - public static function parse(p_colorExpression:String):ColorExpression - { - var input:String = StringUtils.trim(p_colorExpression), - m:Array, - c:uint, - a:Number=1, - ce:ColorExpression; - try { - if(hexRegExp.test(input)) - { - m=hexRegExp.exec(input); - c=parseInt(m[1],16);/* rgb */ - a=(m[2]) ? parseInt(m[2],16)/255 : 1;/* (alpha) ? alpha : 1 */ - ce = new ColorExpression(c,a); - } else if(rgbaRegExp.test(input)) - { - m=rgbaRegExp.exec(input); - c=(parseInt(m[2]) << 16) + (parseInt(m[3]) << 8) + parseInt(m[4]);/* rgb */ - if(m[5]) - { - if(parseInt(m[5])>1 && parseInt(m[5])<=255) - { - a = parseInt(m[5])/255; /* sRGB alpha */ - } else if(parseFloat(m[5])>=0 && parseFloat(m[5])<=1) - { - a = Math.max(0, Math.min(parseFloat(m[5]),1)); /* CSS-style alpha */ - } - } - ce = new ColorExpression(c,a); - } else { - ce = namedColor(input); - } - } catch(err:Error){ - throw(new SMPTETTException("Invalid colour format string: "+input)); - } - return ce; - } - - private static function namedColor(p_input:String):ColorExpression{ - var ce:ColorExpression; - switch(p_input){ - case "transparent": - ce = new ColorExpression(0,0); - break; - case "black": - ce = new ColorExpression(0x000000,1); - break; - case "silver": - ce = new ColorExpression(0xc0c0c0,1); - break; - case "gray": - ce = new ColorExpression(0x808080,1); - break; - case "white": - ce = new ColorExpression(0xffffff,1); - break; - case "maroon": - ce = new ColorExpression(0x800000,1); - break; - case "red": - ce = new ColorExpression(0xff0000,1); - break; - case "purple": - ce = new ColorExpression(0x800080,1); - break; - case "fuchsia": - ce = new ColorExpression(0xff00ff,1); - break; - case "magenta": - ce = new ColorExpression(0xff00ff,1); - break; - case "green": - ce = new ColorExpression(0x008000,1); - break; - case "lime": - ce = new ColorExpression(0x00ff00,1); - break; - case "olive": - ce = new ColorExpression(0x808000,1); - break; - case "yellow": - ce = new ColorExpression(0xffff00,1); - break; - case "navy": - ce = new ColorExpression(0x000080,1); - break; - case "blue": - ce = new ColorExpression(0x0000ff,1); - break; - case "teal": - ce = new ColorExpression(0x008080,1); - break; - case "aqua": - ce = new ColorExpression(0xff00ff,1); - break; - case "cyan": - ce = new ColorExpression(0x00ffff,1); - break; - } - if(ce) return ce; - throw(new SMPTETTException("named colour " + p_input + " not allowed")); - return null; - } - - public function toString():String - { - return "0x"+(((argb>>24) != 0)?Number(argb>>>24).toString(16):"")+Number(argb&0xFFFFFF).toString(16); - } - - /** - * Test the color parser. - * - * @return Boolean - * - */ - public static function UnitTests():Boolean - { - var reference:ColorExpression = new ColorExpression(0xff0000,1); - var pass:Number = 1; - - var tests:Array = [ - "transparent", - "red", - "rgb(255,00,00)", - "rgb(255,00,00,255)", - "rgba(255,00,00,255)", - "#ff0000", - "#FF0000", - "#ff0000ff", - "#fF0000fF" - ]; - - for(var i:uint=0; i>24)&0xFF),10) / 0xFF; + } + + + public static function parse(p_colorExpression:String):ColorExpression + { + var input:String = StringUtils.trim(p_colorExpression), + m:Array, + c:uint, + a:Number=1, + ce:ColorExpression; + + if (_cache[input]) + { + return _cache[input] + } + + try { + if(hexRegExp.test(input)) + { + m=hexRegExp.exec(input); + c=parseInt(m[1],16);/* rgb */ + a=(m[2]) ? parseInt(m[2],16)/255 : 1;/* (alpha) ? alpha : 1 */ + ce = new ColorExpression(c,a); + } else if(rgbaRegExp.test(input)) + { + m=rgbaRegExp.exec(input); + c=(parseInt(m[2]) << 16) + (parseInt(m[3]) << 8) + parseInt(m[4]);/* rgb */ + if(m[5]) + { + if(parseInt(m[5])>1 && parseInt(m[5])<=255) + { + a = parseInt(m[5])/255; /* sRGB alpha */ + } else if(parseFloat(m[5])>=0 && parseFloat(m[5])<=1) + { + a = Math.max(0, Math.min(parseFloat(m[5]),1)); /* CSS-style alpha */ + } + } + ce = new ColorExpression(c,a); + } else { + ce = namedColor(input); + } + } catch(err:Error){ + throw(new SMPTETTException("Invalid colour format string: "+input)); + } + + _cache[input] = ce; + return ce; + } + + private static function namedColor(p_input:String):ColorExpression + { + var ce:ColorExpression; + switch(p_input){ + case "transparent": + ce = new ColorExpression(0,0); + break; + case "black": + ce = new ColorExpression(0x000000,1); + break; + case "silver": + ce = new ColorExpression(0xc0c0c0,1); + break; + case "gray": + ce = new ColorExpression(0x808080,1); + break; + case "white": + ce = new ColorExpression(0xffffff,1); + break; + case "maroon": + ce = new ColorExpression(0x800000,1); + break; + case "red": + ce = new ColorExpression(0xff0000,1); + break; + case "purple": + ce = new ColorExpression(0x800080,1); + break; + case "fuchsia": + ce = new ColorExpression(0xff00ff,1); + break; + case "magenta": + ce = new ColorExpression(0xff00ff,1); + break; + case "green": + ce = new ColorExpression(0x008000,1); + break; + case "lime": + ce = new ColorExpression(0x00ff00,1); + break; + case "olive": + ce = new ColorExpression(0x808000,1); + break; + case "yellow": + ce = new ColorExpression(0xffff00,1); + break; + case "navy": + ce = new ColorExpression(0x000080,1); + break; + case "blue": + ce = new ColorExpression(0x0000ff,1); + break; + case "teal": + ce = new ColorExpression(0x008080,1); + break; + case "aqua": + ce = new ColorExpression(0xff00ff,1); + break; + case "cyan": + ce = new ColorExpression(0x00ffff,1); + break; + } + if(ce) return ce; + throw(new SMPTETTException("named colour " + p_input + " not allowed")); + return null; + } + + public function toString():String + { + return "0x"+(((argb>>24) != 0)?Number(argb>>>24).toString(16):"")+Number(argb&0xFFFFFF).toString(16); + } + + /** + * Test the color parser. + * + * @return Boolean + * + */ + public static function UnitTests():Boolean + { + var reference:ColorExpression = new ColorExpression(0xff0000,1); + var pass:Number = 1; + + var tests:Array = [ + "transparent", + "red", + "rgb(255,00,00)", + "rgb(255,00,00,255)", + "rgba(255,00,00,255)", + "#ff0000", + "#FF0000", + "#ff0000ff", + "#fF0000fF" + ]; + + for(var i:uint=0; i[\+|\-]?)(?P[0-9]+(?:\.[0-9]*)?)(?P%|px|em|c)?\s*?/gi; - */ - private static const paddingRegExp:RegExp = /(?:[\+|\-]?)(?:[0-9]+(?:\.[0-9]*)?)(?:%|px|em|c)?\s*?/gi; - - public var p1:NumberPair; - public var p2:NumberPair; - - public function get widthBefore():Number - { - return p1.first; - } - public function get widthBeforeUnit():Unit - { - return p1.unitMeasureHorizontal; - } - public function get widthAfter():Number - { - return p1.second; - } - public function get widthAfterUnit():Unit - { - return p1.unitMeasureVertical; - } - public function get widthStart():Number - { - return p2.first; - } - public function get widthStartUnit():Unit - { - return p2.unitMeasureHorizontal; - } - public function get widthEnd():Number - { - return p2.second; - } - public function get widthEndUnit():Unit - { - return p2.unitMeasureVertical; - } - - /** - * % sizes are not valid unless this has been set. - * - * @param p_width - * @param p_height - * - * @langversion ActionScript 3.0 - * @playerversion Flash 9.0 - * @tiptext - */ - public function setContext(p_width:Number, p_height:Number):void - { - p1.setContext(p_height,p_height); - p2.setContext(p_width,p_width); - } - - /** - * em sizes are not valid unless this has been set. - * - * @param p_width - * @param p_height - * - * @langversion ActionScript 3.0 - * @playerversion Flash 9.0 - * @tiptext - */ - public function setFontContext(p_width:Number, p_height:Number):void - { - p1.setFontContext(p_height,p_height); - p2.setFontContext(p_width,p_width); - } - - /** - * Parse a padding thickness expression - * - * @param p_expression - * - * @langversion ActionScript 3.0 - * @playerversion Flash 9.0 - * @tiptext - */ - public function PaddingThickness(p_expression:String) - { - var matches:Array = [], - match:Object; - while(match = PaddingThickness.paddingRegExp.exec(p_expression)){ - matches.push(match) - } - if(matches.length==4) - { - // If four specifications are provided, then they apply to before, end, after, and start edges, respectively. - p1 = new NumberPair(matches[0] + " " + matches[2]); - p2 = new NumberPair(matches[3] + " " + matches[1]); - } else if(matches.length == 3) - { - // If three specifications are provided, then the first applies to the - // before edge, the second applies to the start and end edges, and the third - // applies to the after edge - p1 = new NumberPair(matches[0] + " " + matches[2]); - p2 = new NumberPair(matches[1] + " " + matches[1]); - } else if(matches.length == 2) - { - // If the value consists of two specifications, then the first applies - // to the before and after edges, and the second applies to the start and end edges - p1 = new NumberPair(matches[0] + " " + matches[0]); - p2 = new NumberPair(matches[1] + " " + matches[1]); - } else if(matches.length == 1) - { - p1 = new NumberPair(matches[0] + " " + matches[0]); - p2 = new NumberPair(matches[0] + " " + matches[0]); - } else { - throw new org.osmf.smpte.tt.errors.SMPTETTException("Invalid padding expression"); - } - } - - public function isEmpty():Boolean - { - return(p1.isEmpty() && p2.isEmpty()); - } - - public function toString():String - { - var expression:String = "["+( typeof this) +" "+flash.utils.getQualifiedClassName(this)+"] "; - if(p1.isEmpty() && p2.isEmpty()) - { - return expression; - } else - { - return expression+p1.toString()+" "+p2.toString(); - } - } - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.styling +{ + import flash.utils.Dictionary; + import flash.utils.getQualifiedClassName; + + import org.osmf.smpte.tt.enums.Unit; + import org.osmf.smpte.tt.errors.SMPTETTException; + + public class PaddingThickness + { + private static var _cache:Dictionary = new Dictionary(); + public static function getPaddingThickness(value:*):PaddingThickness + { + if (_cache[value] !== undefined) + { + return _cache[value]; + } + else + { + var paddingThickness:PaddingThickness = new PaddingThickness(value); + _cache[value] = paddingThickness; + return paddingThickness; + } + } + + /* MORE GROUPS + /(?P[\+|\-]?)(?P[0-9]+(?:\.[0-9]*)?)(?P%|px|em|c)?\s*?/gi; + */ + private static const paddingRegExp:RegExp = /(?:[\+|\-]?)(?:[0-9]+(?:\.[0-9]*)?)(?:%|px|em|c)?\s*?/gi; + + public var p1:NumberPair; + public var p2:NumberPair; + + public function get widthBefore():Number + { + return p1.first; + } + public function get widthBeforeUnit():Unit + { + return p1.unitMeasureHorizontal; + } + public function get widthAfter():Number + { + return p1.second; + } + public function get widthAfterUnit():Unit + { + return p1.unitMeasureVertical; + } + public function get widthStart():Number + { + return p2.first; + } + public function get widthStartUnit():Unit + { + return p2.unitMeasureHorizontal; + } + public function get widthEnd():Number + { + return p2.second; + } + public function get widthEndUnit():Unit + { + return p2.unitMeasureVertical; + } + + /** + * % sizes are not valid unless this has been set. + * + * @param p_width + * @param p_height + * + * @langversion ActionScript 3.0 + * @playerversion Flash 9.0 + * @tiptext + */ + public function setContext(p_width:Number, p_height:Number):void + { + p1.setContext(p_height,p_height); + p2.setContext(p_width,p_width); + } + + /** + * em sizes are not valid unless this has been set. + * + * @param p_width + * @param p_height + * + * @langversion ActionScript 3.0 + * @playerversion Flash 9.0 + * @tiptext + */ + public function setFontContext(p_width:Number, p_height:Number):void + { + p1.setFontContext(p_height,p_height); + p2.setFontContext(p_width,p_width); + } + + /** + * Parse a padding thickness expression + * + * @param p_expression + * + * @langversion ActionScript 3.0 + * @playerversion Flash 9.0 + * @tiptext + */ + public function PaddingThickness(p_expression:String) + { + var matches:Array = [], + match:Object; + while(match = PaddingThickness.paddingRegExp.exec(p_expression)){ + matches.push(match) + } + if(matches.length==4) + { + // If four specifications are provided, then they apply to before, end, after, and start edges, respectively. + p1 = new NumberPair(matches[0] + " " + matches[2]); + p2 = new NumberPair(matches[3] + " " + matches[1]); + } else if(matches.length == 3) + { + // If three specifications are provided, then the first applies to the + // before edge, the second applies to the start and end edges, and the third + // applies to the after edge + p1 = new NumberPair(matches[0] + " " + matches[2]); + p2 = new NumberPair(matches[1] + " " + matches[1]); + } else if(matches.length == 2) + { + // If the value consists of two specifications, then the first applies + // to the before and after edges, and the second applies to the start and end edges + p1 = new NumberPair(matches[0] + " " + matches[0]); + p2 = new NumberPair(matches[1] + " " + matches[1]); + } else if(matches.length == 1) + { + p1 = new NumberPair(matches[0] + " " + matches[0]); + p2 = new NumberPair(matches[0] + " " + matches[0]); + } else { + throw new org.osmf.smpte.tt.errors.SMPTETTException("Invalid padding expression"); + } + } + + public function isEmpty():Boolean + { + return(p1.isEmpty() && p2.isEmpty()); + } + + public function toString():String + { + var expression:String = "["+( typeof this) +" "+flash.utils.getQualifiedClassName(this)+"] "; + if(p1.isEmpty() && p2.isEmpty()) + { + return expression; + } else + { + return expression+p1.toString()+" "+p2.toString(); + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/TextDecorationAttributeValue.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/TextDecorationAttributeValue.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/TextOutline.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/TextOutline.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/Visibility.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/Visibility.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/WrapOption.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/WrapOption.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/WritingMode.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/styling/WritingMode.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/AbsoluteTimeHelper.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/AbsoluteTimeHelper.as old mode 100755 new mode 100644 index 199e89d..7757c0b --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/AbsoluteTimeHelper.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/AbsoluteTimeHelper.as @@ -1,63 +1,68 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.timing -{ - import org.osmf.smpte.tt.enums.NumberType; - import org.osmf.smpte.tt.timing.TimeCode; - - public class AbsoluteTimeHelper - { - public function AbsoluteTimeHelper(value:Number, numberType:NumberType=null) - { - switch(numberType){ - case NumberType.ULONG : - _time27Mhz = value; - _timeAsFloat = TimeCode.ticks27MhzToAbsoluteTime(value); - _pcrTime = TimeCode.ticks27MhzToPcrTb(value); - break; - default: - _timeAsFloat = value; - _time27Mhz = TimeCode.absoluteTimeToTicks27Mhz(this); - _pcrTime = TimeCode.absoluteTimeToTicksPcrTb(this); - break; - } - } - - private var _timeAsFloat:Number; - public function get timeAsFloat():Number - { - return _timeAsFloat; - } - public function get timeAsDouble():Number - { - return _timeAsFloat; - } - private var _pcrTime:Number; - public function get pcrTime():Number - { - return _pcrTime; - } - private var _time27Mhz:Number; - public function get time27Mhz():Number - { - return _time27Mhz; - } - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.timing +{ + import org.osmf.smpte.tt.enums.NumberType; + import org.osmf.smpte.tt.timing.TimeCode; + + public class AbsoluteTimeHelper + { + public function AbsoluteTimeHelper(value:Number, numberType:NumberType=null) + { + switch(numberType){ + case NumberType.ULONG : + _time27Mhz = value; + _timeAsFloat = TimeCode.ticks27MhzToAbsoluteTime(value); + _pcrTime = TimeCode.ticks27MhzToPcrTb(value); + break; + default: + _timeAsFloat = value; + _time27Mhz = TimeCode.absoluteTimeToTicks27Mhz(this); + _pcrTime = TimeCode.absoluteTimeToTicksPcrTb(this); + break; + } + } + + private var _timeAsFloat:Number; + public function get timeAsFloat():Number + { + return _timeAsFloat; + } + public function get timeAsDouble():Number + { + return _timeAsFloat; + } + private var _pcrTime:Number; + public function get pcrTime():Number + { + return _pcrTime; + } + private var _time27Mhz:Number; + public function get time27Mhz():Number + { + return _time27Mhz; + } + + public function toString():String + { + return String(_timeAsFloat); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/ClockMode.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/ClockMode.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/Metric.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/Metric.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/SmpteFrameRate.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/SmpteFrameRate.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/SmpteMode.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/SmpteMode.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeBase.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeBase.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeCode.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeCode.as old mode 100755 new mode 100644 index b6eeb28..b130401 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeCode.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeCode.as @@ -1,1784 +1,1894 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.timing -{ - import org.osmf.smpte.tt.enums.NumberType; - import org.osmf.smpte.tt.utilities.StringUtils; - - /** - * Represents a SMPTE 12M standard time code and provides conversion operations to various SMPTE time code formats and rates. - * - * Framerates supported by the TimeCode class include, 23.98 IVTC Film Sync, 24fps Film Sync, 25fps PAL, 29.97 drop frame, - * 29.97 Non drop, and 30fps. - */ - public class TimeCode - { - /** - * Regular expression string used for parsing out the timecode. - */ - public static const SMPTEREGEXSTRING:String = "^(?:(?P\d+):)?(?P2[1-3]|[0-1]\d):(?P[0-5]\d]):(?P[0-5]\d)(?::|;)(?P[0-2]\d)$"; - - /** - * Regular expression object used for validating timecode. - */ - public static const _validateTimecode:RegExp = /^(?:(?P\d+):)?(?P2[1-3]|[0-1]\d):(?P[0-5]\d):(?P[0-5]\d)(?::|;)(?P[0-2]\d)$/; - - private var _absoluteTime:AbsoluteTimeHelper; - - /** - * The frame rate for this instance. - */ - private var _frameRate:SmpteFrameRate; - - /** - * The TimeCode can be created from several different sets of parameters. - * - *

      With 5 or 6 parameters, initializes a new instance of the TimeCode structure - * to a specified number of days, hours, minutes, and seconds.

      - * - * @param days:int - Number of days. (optional) - * @param hours:int - Number of hours. - * @param minutes:int - Number of minutes. - * @param seconds:int - Number of seconds. - * @param frames:int - Number of frames. - * @param rate:SmpteFrameRate - The SMPTE frame rate. - * - *

      With 3 parameters, initializes a new instance of the TimeCode structure using - * either an absolute time value or a value of a 27 Mhz clock, and the SMPTE framerate.

      - * - * @param absoluteTime:Number - The double that represents the absolute time value. - * or - * @param ticks27Mhz:Number - The long value in 27 Mhz clock ticks. - * @param rate:SmpteFrameRate - The SMPTE framerate that this instance should use. - * @param numberType:NumberType - The datatype of the first parameter NumberType.DOUBLE for absoluteTime or NumberType.Long for ticks27Mhz. - * - *

      With 2 parameters, initializes a new instance of the TimeCode structure using - * either the totalSeconds of a TimeSpan object or an SMPTE 12m time code string, - * and either an SMPTE framerate or a decimal rate.

      - * - * @param timeSpan:TimeSpan - The TimeSpan to be used for the new timecode.. - * or - * @param timeCode:String - The SMPTE 12m time code string. - * and - * @param rate:SmpteFrameRate - The SMPTE framerate that this instance should use. - * or - * @param rate:Number - The Smpte frame rate. - * - *

      With 1 parameter, initializes a new instance of the TimeCode structure - * using a time code string that contains the framerate at the end of the string.

      - * - *

      Pass in a timecode in the format "timecode@framrate". - * Supported rates include @23.98, @24, @25, @29.97, @30

      - * - *

      For example:
      - * "00:01:00:00@29.97" is equivalent to 29.97 non drop frame.
      - * "00:01:00;00@29.97" is equivalent to 29.97 drop frame.

      - * - * @param timeCodeAndRate:String - The SMPTE 12m time code string. - */ - public function TimeCode(...args:*) - { - var len:uint = args.length, - days:Number, - hours:Number, - minutes:Number, - seconds:Number, - frames:Number, - timeCode:String="", - i:uint; - switch(len){ - case 6: - case 5: - var actualRate:Number; - if(args[(len-1)] is SmpteFrameRate){ - this.frameRate = args[(len-1)]; - for(i=0; i<(len-1); i++){ - if(args[i] is int){ - timeCode += (i==0 && len==6) ? args[i] : TimeCode.twoDigits(args[i]); - if(i 23) throw new Error("hours cannot be greater than 23"); - if (args[2] > 59) throw new Error("minutes cannot be greater than 59"); - if (args[3] > 59) throw new Error("seconds cannot be greater than 59"); - if (args[4] >= actualRate) throw new Error("frames cannot be greater than rate"); - days = args[0]; - hours = args[1]; - minutes = args[2]; - seconds = args[3]; - frames = args[4]; - if(this.frameRate!=SmpteFrameRate.UNKNOWN) - { - for(i=0; i<(len-1); i++){ - if(args[i] is int){ - timeCode += (i==0 && len==6) ? args[i] : TimeCode.twoDigits(args[i]); - if(i 23) throw new Error("hours cannot be greater than 23"); - if (args[1] > 59)throw new Error("minutes cannot be greater than 59"); - if (args[2] > 59) throw new Error("seconds cannot be greater than 59"); - if (args[3] >= actualRate) throw new Error("frames cannot be greater than rate"); - hours = args[0]; - minutes = args[1]; - seconds = args[2]; - frames = args[3]; - if(this.frameRate!=SmpteFrameRate.UNKNOWN) - { - for(i=0; i<(len-1); i++){ - if(args[i] is int){ - timeCode += (i==0 && len==6) ? args[i] : TimeCode.twoDigits(args[i]); - if(i -1) - { - this.frameRate = SmpteFrameRate.SMPTE_2997_DROP; - } - else if (rate == "29.97" && time.indexOf(';') == -1) - { - this.frameRate = SmpteFrameRate.SMPTE_2997_NONDROP; - } - else if (rate == "25") - { - this.frameRate = SmpteFrameRate.SMPTE_25; - } - else if (rate == "23.98") - { - this.frameRate = SmpteFrameRate.SMPTE_2398; - } - else if (rate == "24") - { - this.frameRate = SmpteFrameRate.SMPTE_24; - } - else if (rate == "30") - { - this.frameRate = SmpteFrameRate.SMPTE_30; - } - - this._absoluteTime = TimeCode.smpte12mToAbsoluteTime(time, this.frameRate); - break; - } - // trace("new TimeCode("+args.toString()+") \n\t{ time27Mhz: "+absoluteTime.time27Mhz+", timeAsFloat: "+absoluteTime.timeAsFloat+", pcrTime: "+absoluteTime.pcrTime+" }\n"); - } - - /** - * Convert an integer value into two digits. - */ - private static function twoDigits(p_value:int):String - { - var result:Array = []; - result[0] = ((p_value / 10) + int('0')).toString(16); - result[1] = ((p_value % 10) + int('0')).toString(16); - return result.join(''); - } - - - /** - * The number of milliseconds in one day - */ - public static const MILLISECONDS_PER_DAY:Number = 86400000; - - /** - * The number of milliseconds in one hour - */ - public static const MILLISECONDS_PER_HOUR:Number = 3600000; - - /** - * The number of milliseconds in one minute - */ - public static const MILLISECONDS_PER_MINUTE:Number = 60000; - - /** - * The number of milliseconds in one second - */ - public static const MILLISECONDS_PER_SECOND:Number = 1000; - - /** - * The number of ticks in one millisecond - */ - public static const TICKS_PER_MILLISECOND:Number = 10000; - - /** - * The number of absolute time ticks in 1 millisecond. This field is constant. - */ - public static const TICKS_PER_MILLISECOND_ABSOLUTE_TIME:Number = 0.001; - - /** - * The number of ticks in one second - */ - public static const TICKS_PER_SECOND:Number = 10000000; - - /** - * The number of absolute time ticks in one second - */ - public static const TICKS_PER_SECOND_ABSOLUTE_TIME:Number = 1; - - /** - * The number of ticks in one minute - */ - public static const TICKS_PER_MINUTE:Number = 600000000; - - /** - * The number of absolute time ticks in one minute - */ - public static const TICKS_PER_MINUTE_ABSOLUTE_TIME:Number = 60; - - /** - * The number of ticks in one hour - */ - public static const TICKS_PER_HOUR:Number = 36000000000; - - /** - * The number of absolute time ticks in 1 hour. - */ - public static const TICKS_PER_HOUR_ABSOLUTE_TIME:Number = 3600; - - /** - * The number of ticks in one day - */ - public static const TICKS_PER_DAY:Number = 864000000000; - - /** - * The number of absolute time ticks in 1 day. - */ - public static const TICKS_PER_DAY_ABSOLUTE_TIME:Number = 86400; - - /** - * The minimum TimeCode value. This field is read-only. - */ - public static const MIN_VALUE:Number = 0; - - /** - * Gets the absolute time in seconds of the current TimeCode object. - */ - public function get duration():Number - { - return this.absoluteTime.timeAsDouble; - } - - /** - * Gets or sets the current SMPTE framerate for this TimeCode instance. - */ - public function get frameRate():SmpteFrameRate - { - return _frameRate; - } - public function set frameRate(p_frameRate:SmpteFrameRate):void - { - _frameRate = p_frameRate; - } - - /** - * Gets the number of whole hours represented by the current TimeCode structure. - * - * @returns The hour component of the current TimeCode structure. The return value ranges from 0 through 23. - */ - public function get hoursSegment():int - { - var timeCode:String = TimeCode.absoluteTimeToSmpte12M(this.absoluteTime, this.frameRate); - var hours:String = timeCode.substring(0, 2); - return parseInt(hours); - } - - /** - * Gets the number of whole minutes represented by the current TimeCode structure. - * - * @returns The minute component of the current TimeCode structure. The return value ranges from 0 through 59. - */ - public function get minutesSegment():int - { - var timeCode:String = TimeCode.absoluteTimeToSmpte12M(this.absoluteTime, this.frameRate); - var minutes:String = timeCode.substring(3, 2); - return parseInt(minutes); - } - - /** - * Gets the number of whole seconds represented by the current TimeCode structure. - * - * @returns The seconds component of the current TimeCode structure. The return value ranges from 0 through 59. - */ - public function get secondsSegment():int - { - var timeCode:String = TimeCode.absoluteTimeToSmpte12M(this.absoluteTime, this.frameRate); - var seconds:String = timeCode.substring(6, 2); - return parseInt(seconds); - } - - /** - * Gets the number of whole frames represented by the current TimeCode structure. - * - * @returns The frame component of the current TimeCode structure. The return value depends on the framerate selected for this instance. All frame counts start at zero. - */ - public function get framesSegment():int - { - var timeCode:String = TimeCode.absoluteTimeToSmpte12M(this.absoluteTime, this.frameRate); - var frames:String = timeCode.substring(9, 2); - return parseInt(frames); - } - - /** - * Gets the value of the current TimeCode structure expressed in whole and fractional days. - * - * @returns The total number of days represented by this instance. - */ - public function get totalDays():Number - { - var framecount:Number = TimeCode.absoluteTimeToFrames(this.absoluteTime, this.frameRate); - return (framecount / 108000) / 24; - } - - /** - * Gets the value of the current TimeCode structure expressed in whole - * and fractional hours. - * - * @returns The total number of hours represented by this instance. - */ - public function get totalHours():Number - { - var framecount:Number = TimeCode.absoluteTimeToFrames(this.absoluteTime, this.frameRate); - - var hours:Number; - - switch (this.frameRate) - { - case SmpteFrameRate.SMPTE_2398: - case SmpteFrameRate.SMPTE_24: - hours = framecount / 86400; - break; - case SmpteFrameRate.SMPTE_25: - hours = framecount / 90000; - break; - case SmpteFrameRate.SMPTE_2997_DROP: - hours = framecount / 107892; - break; - case SmpteFrameRate.SMPTE_2997_NONDROP: - case SmpteFrameRate.SMPTE_30: - hours = framecount / 108000; - break; - default: - hours = framecount / 108000; - break; - } - - return hours; - } - - /** - * Gets the value of the current TimeCode structure expressed in whole - * and fractional minutes. - * - * @returns The total number of minutes represented by this instance. - */ - public function get totalMinutes():Number - { - - var framecount:Number = TimeCode.absoluteTimeToFrames(this.absoluteTime, this.frameRate); - - var minutes:Number; - - switch (this.frameRate) - { - case SmpteFrameRate.SMPTE_2398: - case SmpteFrameRate.SMPTE_24: - minutes = framecount / 1400; - break; - case SmpteFrameRate.SMPTE_25: - minutes = framecount / 1500; - break; - case SmpteFrameRate.SMPTE_2997_DROP: - case SmpteFrameRate.SMPTE_2997_NONDROP: - case SmpteFrameRate.SMPTE_30: - minutes = framecount / 1800; - break; - default: - minutes = framecount / 1800; - break; - } - - return minutes; - - } - - /** - * Gets the value of the current TimeCode structure expressed in whole - * and fractional seconds. Not as Precise as the TotalSecondsPrecision. - * - * @returns The total number of seconds represented by this instance. - */ - public function get totalSeconds():Number - { - return this.absoluteTime.timeAsDouble; - } - - /** - * Gets the value of the current TimeCode structure expressed in whole - * and fractional seconds. This is returned as a for greater precision. - * - * @returns The total number of seconds represented by this instance. - */ - public function get totalSecondsPrecision():Number - { - return this.absoluteTime.timeAsFloat; - } - - /** - * Gets the value of the current TimeCode structure expressed in frames. - * - * @returns The total number of frames represented by this instance. - */ - public function get totalFrames():Number - { - return TimeCode.absoluteTimeToFrames(this.absoluteTime, this.frameRate); - } - - /** - * The private Timespan used to track absolute time for this instance. - */ - private function get absoluteTime():AbsoluteTimeHelper - { - if (_absoluteTime == null) - { - _absoluteTime = new AbsoluteTimeHelper(0); - } - - return _absoluteTime; - } - private function set absoluteTime(p_absoluteTime:AbsoluteTimeHelper):void - { - _absoluteTime = p_absoluteTime; - } - - /** - * Returns a SMPTE 12M formatted time code string from a 27Mhz ticks value. - * - * @param ticks27Mhz 27Mhz ticks value. - * @param rate The SMPTE time code framerate desired. - * @returns A SMPTE 12M formatted time code string. - */ - public static function ticks27MhzToSmpte12M(ticks27Mhz:Number, rate:SmpteFrameRate):String - { - var s:String = TimeCode.ticks27MhzToSmpte12M_30fps(ticks27Mhz); - switch (rate) - { - case SmpteFrameRate.SMPTE_2398: - s = TimeCode.ticks27MhzToSmpte12M_23_98fps(ticks27Mhz); - break; - case SmpteFrameRate.SMPTE_24: - s = TimeCode.ticks27MhzToSmpte12M_24fps(ticks27Mhz); - break; - case SmpteFrameRate.SMPTE_25: - s = TimeCode.ticks27MhzToSmpte12M_25fps(ticks27Mhz); - break; - case SmpteFrameRate.SMPTE_2997_DROP: - s = TimeCode.ticks27MhzToSmpte12M_29_27_Drop(ticks27Mhz); - break; - case SmpteFrameRate.SMPTE_2997_NONDROP: - s = TimeCode.ticks27MhzToSmpte12M_29_27_NonDrop(ticks27Mhz); - break; - case SmpteFrameRate.SMPTE_30: - s = TimeCode.ticks27MhzToSmpte12M_30fps(ticks27Mhz); - break; - default: - s = TimeCode.ticks27MhzToSmpte12M_30fps(ticks27Mhz); - break; - } - return s; - } - - /** - * Subtracts a specified TimeCode from this TimeCode. - * - * @param t2 The TimeCode to subtract. - * - * @returns A TimeCode whose value is the result of the value of this minus the value of t2. - */ - public function minus(t2:TimeCode):TimeCode - { - - var frames:Number = this.totalFrames - t2.totalFrames; - var t3:TimeCode = TimeCode.fromFrames(frames, this.frameRate); - - if (t3.totalSecondsPrecision < TimeCode.MIN_VALUE) - { - throw new Error("MinValueSmpte12MOverflowException"); - } - - return t3; - } - - /** - * Adds a specified TimeCode to this TimeCode. - * - * @param t2 The TimeCode to add. - * - * @returns A TimeCode whose value is the result of the value of this plus the value of t2. - */ - public function plus(t2:TimeCode):TimeCode - { - var frames:Number = this.totalFrames + t2.totalFrames; - var t3:TimeCode = TimeCode.fromFrames(frames, this.frameRate); - - return t3; - } - - /** - * Indicates whether this TimeCode is less than another given TimeCode. - * - * @param t2 The TimeCode to compare. - * - * @returns true if the value of this is less than the value of t2; otherwise, false. - */ - public function lessThan(t2:TimeCode):Boolean - { - if(TimeCode.Compare(this,t2)==-1) - { - return true; - } - return false; - } - - /** - * Indicates whether this TimeCode is less than or equal to another given TimeCode. - * - * @param t2 The TimeCode to compare. - * - * @returns true if the value of this is less than or equal to the value of t2; otherwise, false. - */ - public function lessThanOrEqualTo(t2:TimeCode):Boolean - { - var compare:int = TimeCode.Compare(this,t2); - if(compare==-1 || compare==0) - { - return true; - } - return false; - } - - /** - * Indicates whether this TimeCode is not equal to another given TimeCode. - * - * @param t2 The TimeCode to compare. - * - * @returns true if the value of this is not equal to the value of t2; otherwise, false. - */ - public function notEqualTo(t2:TimeCode):Boolean - { - return !this.equalTo(t2); - } - - /** - * Indicates whether this TimeCode is equal to another given TimeCode. - * - * @param t2 The TimeCode to compare. - * - * @returns true if the value of this is equal to the value of t2; otherwise, false. - */ - public function equalTo(t2:TimeCode):Boolean - { - if(TimeCode.Compare(this,t2)==0) - { - return true; - } - return false; - } - - /** - * Indicates whether this TimeCode equals another given TimeCode. - * - * @param t2 The TimeCode to compare. - * - * @returns true if the value of this equals the value of t2; otherwise, false. - */ - public function equals(t2:Object):Boolean - { - if (!(t2 is TimeCode)) - { - throw new ArgumentError("Object to compare must be a TimeCode"); - } - return this.equalTo(t2 as TimeCode); - } - - /** - * Indicates whether this TimeCode is greater than or equal to another given TimeCode. - * - * @param t2 The TimeCode to compare. - * - * @returns true if the value of this is greater than or equal to the value of t2; otherwise, false. - */ - public function greaterThanOrEqualTo(t2:TimeCode):Boolean - { - var compare:int = TimeCode.Compare(this,t2); - if(compare==1 || compare==0) - { - return true; - } - return false; - } - - /** - * Indicates whether this TimeCode is greater than another given TimeCode. - * - * @param t2 The TimeCode to compare. - * - * @returns true if the value of this is greater than the value of t2; otherwise, false. - */ - public function greaterThan(t2:TimeCode):Boolean - { - if(TimeCode.Compare(this,t2)==1) - { - return true; - } - return false; - } - - /** - * Compares two TimeCode values and returns an integer that indicates their relationship. - * - * @param t1 The first TimeCode. - * @param t2 The second TimeCode. - * - * @returns Value Condition -1 t1 is less than t2, 0 t1 is equal to t2, 1 t1 is greater than t2. - */ - public static function Compare(t1:TimeCode,t2:TimeCode):int - { - // trace("Compare: "+t1.absoluteTime.timeAsDouble +" to "+ t2.absoluteTime.timeAsDouble); - var timeCode1:TimeCode = new TimeCode(t1.absoluteTime.timeAsDouble, SmpteFrameRate.SMPTE_30, NumberType.DOUBLE); - var timeCode2:TimeCode = new TimeCode(t2.absoluteTime.timeAsDouble, SmpteFrameRate.SMPTE_30, NumberType.DOUBLE); - - if (timeCode1.totalFrames < timeCode2.totalFrames) - { - return -1; - } else if(timeCode1.totalFrames == timeCode2.totalFrames){ - return 0; - } - - return 1; - } - - /** - * Returns a value indicating whether two specified instances of TimeCode - * are equal. - * - * @param t1 The first TimeCode. - * @param t2 The second TimeCode. - * - * @returns true if the values of t1 and t2 are equal; otherwise, false. - */ - public static function Equals(t1:TimeCode,t2:TimeCode):Boolean - { - return t1.equals(t2); - } - - /** - * Returns a TimeCode that represents a specified number of days, where the specification is accurate to the nearest millisecond. - * - * @param value A number of days accurate to the nearest millisecond. - * @param rate The desired SmpteFrameRate framerate for this instance. - * @returns A TimeCode that represents value. - */ - public static function fromDays(value:Number, rate:SmpteFrameRate):TimeCode - { - var absoluteTime:Number = value * TimeCode.TICKS_PER_DAY_ABSOLUTE_TIME; - return new TimeCode(absoluteTime, rate, NumberType.DOUBLE); - } - - /** - * Returns a TimeCode that represents a specified number of hours, where the specification is accurate to the nearest millisecond. - * - * @param value A number of hours accurate to the nearest millisecond. - * @param rate The desired SmpteFrameRate framerate for this instance. - * @returns A TimeCode that represents value. - */ - public static function fromHours(value:Number, rate:SmpteFrameRate):TimeCode - { - var absoluteTime:Number = value * TimeCode.TICKS_PER_HOUR_ABSOLUTE_TIME; - return new TimeCode(absoluteTime, rate, NumberType.DOUBLE); - } - - /** - * Returns a TimeCode that represents a specified number of minutes, where the specification is accurate to the nearest millisecond. - * - * @param value A number of minutes accurate to the nearest millisecond. - * @param rate The desired SmpteFrameRate framerate for this instance. - * @returns A TimeCode that represents value. - */ - public static function fromMinutes(value:Number, rate:SmpteFrameRate):TimeCode - { - var absoluteTime:Number = value * TimeCode.TICKS_PER_MINUTE_ABSOLUTE_TIME; - return new TimeCode(absoluteTime, rate, NumberType.DOUBLE); - } - - /** - * Returns a TimeCode that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. - * - * @param value A number of seconds accurate to the nearest millisecond. - * @param rate The desired SmpteFrameRate framerate for this instance. - * @returns A TimeCode that represents value. - */ - public static function fromSeconds(value:Number, rate:SmpteFrameRate):TimeCode - { - var absoluteTime:Number = value * TimeCode.TICKS_PER_SECOND_ABSOLUTE_TIME; - return new TimeCode(absoluteTime, rate, NumberType.DOUBLE); - } - - /** - * Returns a TimeCode that represents a specified number of frames. - * - * @param value A number of frames. - * @param rate The framerate of the Timecode. - * @returns A TimeCode that represents value. - */ - public static function fromFrames(value:Number, rate:SmpteFrameRate):TimeCode - { - var ticks27Mhz:Number = TimeCode.framesToTicks27Mhz(value, rate); - return new TimeCode(ticks27Mhz, rate, NumberType.ULONG); - } - - /** - * Returns a TimeCode that represents a specified time, where the specification is in units of ticks. - * - * @param ticks A number of ticks that represent a time. - * @param rate The Smpte framerate. - * @returns A TimeCode with a value of value. - */ - public static function fromTicks(ticks:Number, rate:SmpteFrameRate):TimeCode - { - var absoluteTime:Number = Math.pow(10, -7) * ticks; - return new TimeCode(absoluteTime, rate, NumberType.DOUBLE); - } - - /** - * Returns a TimeCode that represents a specified time, where the specification is in units of 27 Mhz clock ticks. - * - * @param value A number of ticks in 27 Mhz clock format. - * @param rate A Smpte framerate. - * @returns A TimeCode. - */ - public static function fromTicks27Mhz(value:Number, rate:SmpteFrameRate):TimeCode - { - return new TimeCode(value, rate, NumberType.ULONG); - } - - /** - * Returns a TimeCode that represents a specified time, where the specification is in units of absolute time. - * - * @param value The absolute time in 100 nanosecond units. - * @param rate The SMPTE framerate. - * @returnss A TimeCode. - */ - public static function fromAbsoluteTime(value:Number, rate:SmpteFrameRate):TimeCode - { - return new TimeCode(value, rate, NumberType.DOUBLE); - } - - /** - * Returns a TimeCode that represents a specified time, where the specification is in units of absolute time. - * - * @param value The TimeSpan object. - * @param rate The SMPTE framerate. - * @returnss A TimeCode. - */ - public static function fromTimeSpan(value:TimeSpan, rate:SmpteFrameRate):TimeCode - { - return new TimeCode(value.totalSeconds, rate); - } - - /** - * Validates that the string provided is in the correct format for SMPTE 12M time code. - * - * @param timeCode String that is the time code. - * @returns True if this is a valid SMPTE 12M time code string. - */ - public static function validateSmpte12MTimecode(timeCode:String):Boolean - { - return TimeCode._validateTimecode.test(timeCode); - } - - /** - * Returns the value of the provided time code string and framerate in 27Mhz ticks. - * - * @param timeCode The SMPTE 12M formatted time code string. - * @param rate The SMPTE framerate. - * @returns A number that represents the value of the time code in 27Mhz ticks. - */ - public static function smpte12MToTicks27Mhz(timeCode:String, rate:SmpteFrameRate):Number - { - var t:Number = TimeCode.smpte12M_30fpsToTicks27Mhz(timeCode); - switch (rate) - { - case SmpteFrameRate.SMPTE_2398: - t = TimeCode.smpte12M_23_98fpsToTicks27Mhz(timeCode); - break; - case SmpteFrameRate.SMPTE_24: - t = TimeCode.smpte12M_24fpsToTicks27Mhz(timeCode); - break; - case SmpteFrameRate.SMPTE_25: - t = TimeCode.smpte12M_25fpsToTicks27Mhz(timeCode); - break; - case SmpteFrameRate.SMPTE_2997_DROP: - t = TimeCode.smpte12M_29_27_DropToTicks27Mhz(timeCode); - break; - case SmpteFrameRate.SMPTE_2997_NONDROP: - t = TimeCode.smpte12M_29_27_NonDropToTicks27Mhz(timeCode); - break; - case SmpteFrameRate.SMPTE_30: - t = TimeCode.smpte12M_30fpsToTicks27Mhz(timeCode); - break; - default: - t = TimeCode.smpte12M_30fpsToTicks27Mhz(timeCode); - break; - } - return t; - } - - /** - * Parses a framerate value as double and converts it to a member of the SmpteFrameRate enumeration. - * - * @param rate Double value of the framerate. - * @returns A SmpteFrameRate enumeration value that matches the incoming rates. - */ - public static function parseFramerate(rate:Number):SmpteFrameRate - { - var rateRounded:int = Math.floor(rate); - var s:SmpteFrameRate = SmpteFrameRate.UNKNOWN - switch (rateRounded) - { - case 23: s = SmpteFrameRate.SMPTE_2398; - break; - case 24: s = SmpteFrameRate.SMPTE_24; - break; - case 25: s = SmpteFrameRate.SMPTE_25; - break; - case 29: s = SmpteFrameRate.SMPTE_2997_NONDROP; - break; - case 30: s = SmpteFrameRate.SMPTE_30; - break; - case 50: s = SmpteFrameRate.SMPTE_25; - break; - case 60: s = SmpteFrameRate.SMPTE_30; - break; - case 59: s = SmpteFrameRate.SMPTE_2997_NONDROP; - break; - } - - return s; - } - - /** - * Adds the specified TimeCode to this instance. - * - * @param ts A TimeCode. - * @returns A TimeCode that represents the value of this instance plus the value of ts. - */ - public function add(ts:TimeCode):TimeCode - { - return this.plus(ts); - } - - /** - * Compares this instance to a specified object and returns an indication of their relative values. - * - * @param value An object to compare, or null. - * @returns Value Condition -1 The value of this instance is less than the value of value. 0 The value of this instance is equal to the value of value. 1 The value of this instance is greater than the value of value.-or- value is null. - */ - public function compareTo(value:Object):int - { - if (!(value is TimeCode)) - { - throw new Error("Object to compare must be a TimeCode"); - } - - var t1:TimeCode = value as TimeCode; - - return TimeCode.Compare(this,t1); - } - - /** - * Subtracts the specified TimeCode from this instance. - * - * @param ts A TimeCode. - * @returns A TimeCode whose value is the result of the value of this instance minus the value of ts. - */ - public function subtract(ts:TimeCode):TimeCode - { - return this.minus(ts); - } - - /** - * Returns the SMPTE 12M string representation of the value of this instance. - * - * @returns A string that represents the value of this instance. The return value is - * of the form: hh:mm:ss:ff for non-drop frame and hh:mm:ss;ff for drop frame code - * with "hh" hours, ranging from 0 to 23, "mm" minutes - * ranging from 0 to 59, "ss" seconds ranging from 0 to 59, and "ff" based on the - * chosen framerate to be used by the time code instance. - */ - public function toString():String - { - return TimeCode.absoluteTimeToSmpte12M(this.absoluteTime, this.frameRate); - } - - /** - * Returns the SMPTE 12M string representation of the value of this instance. - * - * @returns A string that represents the value of this instance. The return value is - * of the form: hh:mm:ss:ff for non-drop frame and hh:mm:ss;ff for drop frame code - * with "hh" hours, ranging from 0 to 23, "mm" minutes - * ranging from 0 to 59, "ss" seconds ranging from 0 to 59, and "ff" based on the - * chosen framerate to be used by the time code instance. - */ - public function toStringAtFramerate(rate:SmpteFrameRate=null):String - { - return TimeCode.absoluteTimeToSmpte12M(this.absoluteTime, ((rate!=null) ? rate : this.frameRate)); - } - - /** - * Returns the value of this instance in 27 Mhz ticks. - * - * @returns A ulong value that is in 27 Mhz ticks. - */ - public function toTicks27Mhz():Number - { - return TimeCode.absoluteTimeToTicks27Mhz(this.absoluteTime); - } - - /** - * Returns the value of this instance in MPEG 2 PCR time base (PcrTb) format. - * - * @returns A Number value that is in PcrTb. - */ - public function toTicksPcrTb():Number - { - return TimeCode.absoluteTimeToTicksPcrTb(this.absoluteTime); - } - - /** - * Converts a SMPTE timecode to absolute time. - * - * @param timeCodeThe timecode to convert from. - * @param rate The SmpteFrameRate of the timecode. - * @returns An AbsoluteTimeHelper with the absolute time. - */ - private static function smpte12mToAbsoluteTime(timeCode:String, rate:SmpteFrameRate):AbsoluteTimeHelper - { - var ath:AbsoluteTimeHelper = new AbsoluteTimeHelper(0); - - switch (rate) - { - case SmpteFrameRate.SMPTE_2398: - ath = TimeCode.smpte12M_23_98_ToAbsoluteTime(timeCode); - break; - case SmpteFrameRate.SMPTE_24: - ath = TimeCode.smpte12M_24_ToAbsoluteTime(timeCode); - break; - case SmpteFrameRate.SMPTE_25: - ath = TimeCode.smpte12M_25_ToAbsoluteTime(timeCode); - break; - case SmpteFrameRate.SMPTE_2997_DROP: - ath = TimeCode.smpte12M_29_97_Drop_ToAbsoluteTime(timeCode); - break; - case SmpteFrameRate.SMPTE_2997_NONDROP: - ath = TimeCode.smpte12M_29_97_NonDrop_ToAbsoluteTime(timeCode); - break; - case SmpteFrameRate.SMPTE_30: - ath = TimeCode.smpte12M_30_ToAbsoluteTime(timeCode); - break; - } - - return ath; - } - - /** - * Parses a timecode string for the different parts of the timecode. - * - * @param timeCode The source timecode to parse. - */ - private static function parseTimecodeString(timeCode:String):TimeCodeComponents - { - if (!TimeCode.validateSmpte12MTimecode(timeCode)) - { - throw new Error(timeCode+" is not a valid SMPTE 12M timecode"); - } - var out:TimeCodeComponents = new TimeCodeComponents(); - out.days = 0; - - var times:Array = timeCode.match(TimeCode._validateTimecode); - - if (times.Days!=null) - { - out.days = parseInt(times.Days,10); - } - - out.hours = parseInt(times.Hours,10); - out.minutes = parseInt(times.Minutes,10); - out.seconds = parseInt(times.Seconds,10); - out.frames = parseInt(times.Frames,10); - - return out; - } - - /** - * Generates a string representation of the timecode. - * - * @param days The Days section from the timecode. - * @param hours The Hours section from the timecode. - * @param minutes The Minutes section from the timecode. - * @param seconds The Seconds section from the timecode. - * @param frames The frames section from the timecode. - * @param dropFrame Indicates whether the timecode is drop frame or not. - * @returns The timecode in string format. - */ - private static function formatTimeCodeString(days:int=0, hours:int=0, minutes:int=0, seconds:int=0, frames:int=0, dropFrame:Boolean = false):String - { - var h:String = TimeCode.twoDigits(hours), - m:String = TimeCode.twoDigits(minutes), - s:String = TimeCode.twoDigits(seconds), - f:String = TimeCode.twoDigits(frames), - framesSeparator:String = (dropFrame) ? ";" : ":"; - - if (days > 0) - { - return StringUtils.formatString("{0}:{1}:{2}:{3}{5}{4}", days, h, m, s, f, framesSeparator); - } - - return StringUtils.formatString("{0}:{1}:{2}{4}{3}", h, m, s, f, framesSeparator); - } - - /** - * Converts to Absolute time from SMPTE 12M 23.98. - * - * @param timeCode The timecode to parse. - * @returns An AbsoluteTimeHelper that contains the absolute duration. - */ - private static function smpte12M_23_98_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper - { - var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); - var days:int = obj.days, - hours:int = obj.hours, - minutes:int = obj.minutes, - seconds:int = obj.seconds, - frames:int = obj.frames; - - if (frames >= 24) - { - throw new Error("Timecode frame value is not in the expected range for SMPTE 23.98 IVTC."); - } - - var framesHertz:Number = Math.ceil(1001 * (15 / 4) * frames); - var secondsHertz:int = 90090 * seconds; - var minutesHertz:int = 5405400 * minutes; - var hoursHertz:Number = 324324000 * hours; - var daysHertz:Number = 7783776000 * days; - - var pcrTb:Number = framesHertz + secondsHertz + minutesHertz + hoursHertz + daysHertz; - - var ticks27Mhz:Number = pcrTb * 300; - - return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); - } - - /** - * Converts to Absolute time from SMPTE 12M 24. - * - * @param timeCode The timecode to parse. - * @returns An AbsoluteTimeHelper that contains the absolute duration. - */ - private static function smpte12M_24_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper - { - var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); - var days:int = obj.days, - hours:int = obj.hours, - minutes:int = obj.minutes, - seconds:int = obj.seconds, - frames:int = obj.frames; - - if (frames >= 24) - { - throw new Error("Timecode frame value is not in the expected range for SMPTE 24fps Film Sync."); - } - ; - var ticks27Mhz:Number = ((3750 * frames) + (90000 * seconds) + (5400000 * minutes) + (324000000 * hours) + (7776000000 * days)) * 300; - - var ath:AbsoluteTimeHelper = new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); - - return ath; - } - - /** - * Converts to Absolute time from SMPTE 12M 25. - * - * @param timeCode The timecode to parse. - * @returns An AbsoluteTimeHelper that contains the absolute duration. - */ - private static function smpte12M_25_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper - { - var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); - var days:int = obj.days, - hours:int = obj.hours, - minutes:int = obj.minutes, - seconds:int = obj.seconds, - frames:int = obj.frames; - - if (frames >= 25) - { - throw new Error("Timecode frame value is not in the expected range for SMPTE 25fps PAL."); - } - - var ticks27Mhz:Number = ((3600 * frames) + (90000 * seconds) + (5400000 * minutes) + (324000000 * hours) + (7776000000 * days)) * 300; - return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); - } - - /** - * Converts to Absolute time from SMPTE 12M 29.97 Drop frame. - * - * @param timeCode The timecode to parse. - * @returns An AbsoluteTimeHelper that contains the absolute duration. - */ - private static function smpte12M_29_97_Drop_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper - { - var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); - var days:int = obj.days, - hours:int = obj.hours, - minutes:int = obj.minutes, - seconds:int = obj.seconds, - frames:int = obj.frames; - - if (frames >= 30) - { - throw new Error("Timecode frame value is not in the expected range for SMPTE 29.97 DropFrame."); - } - - var time:Number = (1001 / 30000) * (frames + (30 * seconds) + (1798 * minutes) + ((2 * (minutes / 10)) + (107892 * hours) + (2589408 * days))); - return new AbsoluteTimeHelper(time,NumberType.DOUBLE); - } - - /** - * Converts to Absolute time from SMPTE 12M 29.97 Non Drop. - * - * @param timeCode The timecode to parse. - * @returns An AbsoluteTimeHelper that contains the absolute duration. - */ - private static function smpte12M_29_97_NonDrop_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper - { - var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); - var days:int = obj.days, - hours:int = obj.hours, - minutes:int = obj.minutes, - seconds:int = obj.seconds, - frames:int = obj.frames; - - if (frames >= 30) - { - throw new Error("Timecode frame value is not in the expected range for SMPTE 29.97 NonDrop."); - } - - var ticks27Mhz:Number = ((3003 * frames) + (90090 * seconds) + (5405400 * minutes) + (324324000 * hours) + (7783776000 * days)) * 300; - return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); - } - - - /** - * Converts to Absolute time from SMPTE 12M 30. - * - * @param timeCode The timecode to parse. - * @returns An AbsoluteTimeHelper that contains the absolute duration. - */ - private static function smpte12M_30_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper - { - var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); - var days:int = obj.days, - hours:int = obj.hours, - minutes:int = obj.minutes, - seconds:int = obj.seconds, - frames:int = obj.frames; - - if (frames >= 30) - { - throw new Error("Timecode frame value is not in the expected range for SMPTE 30fps."); - } - - var ticks27Mhz:Number = ((3000 * frames) + (90000 * seconds) + (5400000 * minutes) + (324000000 * hours) + (7776000000 * days)) * 300; - return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); - } - - /** - * Converts from 27Mhz ticks to PCRTb. - * - * @param ticks27Mhz >The number of 27Mhz ticks to convert from. - * @returns A Number with the PCRTb. - */ - internal static function ticks27MhzToPcrTb(ticks27Mhz:Number):Number - { - return ticks27Mhz / 300; - } - - /** - * Converts the provided absolute time to PCRTb. - * - * @param time Absolute time to be converted. - * @returns The number of PCRTb ticks. - */ - internal static function absoluteTimeToTicksPcrTb(time:AbsoluteTimeHelper):Number - { - return Math.round(time.timeAsDouble * 90000); - } - - /** - * Converts the specified absolute time to 27 mhz ticks. - * - * @param time Absolute time to be converted. - * @returns The number of 27Mhz ticks. - */ - internal static function absoluteTimeToTicks27Mhz(time:AbsoluteTimeHelper):Number - { - return TimeCode.absoluteTimeToTicksPcrTb(time) * 300; - } - - /** - * Converts the specified absolute time to absolute time. - * - * @param ticksPcrTb Ticks PCRTb to be converted. - * @returns The absolute time. - */ - internal static function ticksPcrTbToAbsoluteTime(ticksPcrTb:Number):Number - { - return ticksPcrTb / 90000; - } - - /** - * Converts the specified absolute time to absolute time. - * - * @param ticks27Mhz Ticks 27Mhz to be converted. - * @returns The absolute time. - */ - internal static function ticks27MhzToAbsoluteTime(ticks27Mhz:Number):Number - { - var ticksPcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); - return TimeCode.ticksPcrTbToAbsoluteTime(ticksPcrTb); - } - - /** - * Converts to SMPTE 12M. - * - * @param time The absolute time to convert from. - * @param rate The SMPTE frame rate. - * @returns A string in SMPTE 12M format. - */ - private static function absoluteTimeToSmpte12M(time:AbsoluteTimeHelper, rate:SmpteFrameRate):String - { - var timeCode:String = ""; - - if (rate == SmpteFrameRate.SMPTE_2398) - { - timeCode = TimeCode.absoluteTimeToSmpte12M_23_98fps(time); - } - else if (rate == SmpteFrameRate.SMPTE_24) - { - timeCode = TimeCode.absoluteTimeToSmpte12M_24fps(time); - } - else if (rate == SmpteFrameRate.SMPTE_25) - { - timeCode = TimeCode.absoluteTimeToSmpte12M_25fps(time); - } - else if (rate == SmpteFrameRate.SMPTE_2997_DROP) - { - timeCode = TimeCode.absoluteTimeToSmpte12M_29_97_Drop(time); - } - else if (rate == SmpteFrameRate.SMPTE_2997_NONDROP) - { - timeCode = TimeCode.absoluteTimeToSmpte12M_29_97_NonDrop(time); - } - else if (rate == SmpteFrameRate.SMPTE_30) - { - timeCode = TimeCode.absoluteTimeToSmpte12M_30fps(time); - } - - return timeCode; - } - - /** - * Returns the absolute time. - * - * @param frames The number of frames. - * @param rate The SMPTE frame rate to use for the conversion. - * @returns The absolute time. - */ - private static function framesToAbsoluteTime(frames:Number, rate:SmpteFrameRate):Number - { - var absoluteTimeInDecimal:Number; - - if (rate == SmpteFrameRate.SMPTE_2398) - { - absoluteTimeInDecimal = frames / 24 / (1000 / 1001); - } - else if (rate == SmpteFrameRate.SMPTE_24) - { - absoluteTimeInDecimal = frames / 24; - } - else if (rate == SmpteFrameRate.SMPTE_25) - { - absoluteTimeInDecimal = frames / 25; - } - else if (rate == SmpteFrameRate.SMPTE_2997_DROP || rate == SmpteFrameRate.SMPTE_2997_NONDROP) - { - absoluteTimeInDecimal = frames / 30 / (1000 / 1001); - } - else if (rate == SmpteFrameRate.SMPTE_30) - { - absoluteTimeInDecimal = frames / 30; - } - else - { - absoluteTimeInDecimal = frames / 30; - } - - return absoluteTimeInDecimal; - } - - /** - * Returns the absolute time. - * - * @param frames The number of frames. - * @param rate The SMPTE frame rate to use for the conversion. - * @returns The absolute time. - */ - private static function framesToTicks27Mhz(frames:Number, rate:SmpteFrameRate):Number - { - var ticks27Mhz:Number; - - if (rate == SmpteFrameRate.SMPTE_2398) - { - ticks27Mhz = Math.ceil(1001 * (15 / 4) * frames) * 300; - } - else if (rate == SmpteFrameRate.SMPTE_24) - { - ticks27Mhz = (3750 * frames) * 300; - } - else if (rate == SmpteFrameRate.SMPTE_25) - { - ticks27Mhz = (3600 * frames) * 300; - } - else if (rate == SmpteFrameRate.SMPTE_2997_DROP || rate == SmpteFrameRate.SMPTE_2997_NONDROP) - { - ticks27Mhz = (3003 * frames) * 300; - } - else if (rate == SmpteFrameRate.SMPTE_30) - { - ticks27Mhz = (3000 * frames) * 300; - } - else - { - ticks27Mhz = (3000 * frames) * 300; - } - - return ticks27Mhz; - } - - /** - * Returns the absolute time. - * - * @param absoluteTime The number of frames. - * @param rate The SMPTE frame rate to use for the conversion. - * @returns The absolute time. - */ - private static function absoluteTimeToFrames(absoluteTime:AbsoluteTimeHelper, rate:SmpteFrameRate):Number - { - var frames:Number; - - if (rate == SmpteFrameRate.SMPTE_2398) - { - frames = ((4 / 15) * (absoluteTime.pcrTime / 1001)); - return frames; - } - - if (rate == SmpteFrameRate.SMPTE_24) - { - frames = (absoluteTime.pcrTime / 3750); - return frames; - } - - if (rate == SmpteFrameRate.SMPTE_25) - { - frames = (absoluteTime.pcrTime / 3600); - return frames; - } - - if (rate == SmpteFrameRate.SMPTE_2997_DROP || rate == SmpteFrameRate.SMPTE_2997_NONDROP) - { - frames = (absoluteTime.pcrTime / 3003); - return frames; - } - - if (rate == SmpteFrameRate.SMPTE_30) - { - frames = (absoluteTime.pcrTime / 3000); - return frames; - } - - return (absoluteTime.pcrTime / 3003); - } - - /** - * Returns the SMPTE 12M 23.98 timecode. - * - * @param absoluteTime The absolute time to convert from. - * @returns A string that contains the correct format. - */ - private static function absoluteTimeToSmpte12M_23_98fps(absoluteTime:AbsoluteTimeHelper):String - { - return TimeCode.ticks27MhzToSmpte12M_23_98fps(absoluteTime.time27Mhz); - } - - /** - * Converts to SMPTE 12M 24fps. - * - * @param absoluteTime The absolute time to convert from. - * @returns A string that contains the correct format. - */ - private static function absoluteTimeToSmpte12M_24fps(absoluteTime:AbsoluteTimeHelper):String - { - return TimeCode.ticks27MhzToSmpte12M_24fps(absoluteTime.time27Mhz); - } - - /** - * Converts to SMPTE 12M 25fps. - * - * @param absoluteTime The absolute time to convert from. - * @returns A string that contains the correct format. - */ - private static function absoluteTimeToSmpte12M_25fps(absoluteTime:AbsoluteTimeHelper):String - { - return TimeCode.ticks27MhzToSmpte12M_25fps(absoluteTime.time27Mhz); - } - - /** - * Converts to SMPTE 12M 29.97fps Drop. - * - * @param absoluteTime The absolute time to convert from. - * @returns A string that contains the correct format. - */ - private static function absoluteTimeToSmpte12M_29_97_Drop(absoluteTime:AbsoluteTimeHelper):String - { - return TimeCode.ticks27MhzToSmpte12M_29_27_Drop(absoluteTime.time27Mhz); - } - - /** - * Converts to SMPTE 12M 29.97fps Non Drop. - * - * @param absoluteTime The absolute time to convert from. - * @returns A string that contains the correct format. - */ - private static function absoluteTimeToSmpte12M_29_97_NonDrop(absoluteTime:AbsoluteTimeHelper):String - { - return TimeCode.ticks27MhzToSmpte12M_29_27_NonDrop(absoluteTime.time27Mhz); - } - - /** - * Converts to SMPTE 12M 30fps. - * - * @param absoluteTime The absolute time to convert from. - * @returns A string that contains the correct format. - */ - private static function absoluteTimeToSmpte12M_30fps(absoluteTime:AbsoluteTimeHelper):String - { - return TimeCode.ticks27MhzToSmpte12M_30fps(absoluteTime.time27Mhz); - } - - /** - * Converts to Ticks 27Mhz. - * - * @param timeCode The timecode to convert from. - * @returns The number of 27Mhz ticks. - */ - private static function smpte12M_30fpsToTicks27Mhz(timeCode:String):Number - { - var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_30); - var ticksPcrTb:Number = Math.ceil((t.framesSegment * 3000) + (90000 * t.secondsSegment) + (5400000 * t.minutesSegment) + (324000000 * t.hoursSegment)); - return ticksPcrTb * 300; - } - - /** - * Converts to Ticks 27Mhz. - * - * @param timeCode The timecode to convert from. - * @returns The number of 27Mhz ticks. - */ - private static function smpte12M_23_98fpsToTicks27Mhz(timeCode:String):Number - { - var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_2398); - var ticksPcrTb:Number = Math.ceil((Math.ceil(1001 * (15 / 4) * t.framesSegment) + (90090 * t.secondsSegment) + (5405400 * t.minutesSegment) + (324324000 * t.hoursSegment))); - return ticksPcrTb * 300; - } - - /** - * Converts to Ticks 27Mhz. - * - * @param timeCode The timecode to convert from. - * @returns The number of 27Mhz ticks. - */ - private static function smpte12M_24fpsToTicks27Mhz(timeCode:String):Number - { - var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_24); - var ticksPcrTb:Number = Math.ceil((t.framesSegment * 3750) + (90000 * t.secondsSegment) + (5400000 * t.minutesSegment) + (324000000 * t.hoursSegment)); - return ticksPcrTb * 300; - } - - /** - * Converts to Ticks 27Mhz. - * - * @param timeCode The timecode to convert from. - * @returns The number of 27Mhz ticks. - */ - private static function smpte12M_25fpsToTicks27Mhz(timeCode:String):Number - { - var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_25); - var ticksPcrTb:Number = Math.ceil((t.framesSegment * 3600) + (90000 * t.secondsSegment) + (5400000 * t.minutesSegment) + (324000000 * t.hoursSegment)); - return ticksPcrTb * 300; - } - - /** - * Converts to Ticks 27Mhz. - * - * @param timeCode The timecode to convert from. - * @returns The number of 27Mhz ticks. - */ - private static function smpte12M_29_27_NonDropToTicks27Mhz(timeCode:String):Number - { - var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_2997_DROP); - var ticksPcrTb:Number = Math.ceil((t.framesSegment * 3003) + (90090 * t.secondsSegment) + (5405400 * t.minutesSegment) + (324324000 * t.hoursSegment)); - return ticksPcrTb * 300; - } - - /** - * Converts to Ticks 27Mhz. - * - * @param timeCode The timecode to convert from. - * @returns The number of 27Mhz ticks. - */ - private static function smpte12M_29_27_DropToTicks27Mhz(timeCode:String):Number - { - var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_2997_NONDROP); - var ticksPcrTb:Number = Math.ceil((3003 * t.framesSegment) + (90090 * t.secondsSegment) + (5399394 * t.minutesSegment) + (6006 * int(t.minutesSegment / 10)) + (323999676 * t.hoursSegment)); - return ticksPcrTb * 300; - } - - /** - * Converts to SMPTE 12M 29.27fps Non Drop. - * - * @param ticks27Mhz The number of 27Mhz ticks to convert from. - * @returns A string that contains the correct format. - */ - private static function ticks27MhzToSmpte12M_29_27_NonDrop(ticks27Mhz:Number):String - { - var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); - var framecount:int = int(pcrTb / 3003); - var hours:int = int(framecount / 108000); - var minutes:int = int((framecount - (108000 * hours)) / 1800); - var seconds:int = int((framecount - (1800 * minutes) - (108000 * hours)) / 30); - var frames:int = framecount - (30 * seconds) - (1800 * minutes) - (108000 * hours); - - var days:int = hours / 24; - hours = hours % 24; - - return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); - } - - /** - * Converts to SMPTE 12M 29.27fps Non Drop. - * - * @param ticks27Mhz The number of 27Mhz ticks to convert from. - * @returns A string that contains the correct format. - */ - private static function ticks27MhzToSmpte12M_29_27_Drop(ticks27Mhz:Number):String - { - var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); - var framecount:int = int(pcrTb / 3003); - var hours:int = int(framecount / 107892); - var minutes:int = int((framecount + (2 * int((framecount - (107892 * hours)) / 1800)) - (2 * int((framecount - (107892 * hours)) / 18000)) - (107892 * hours)) / 1800); - var seconds:int = int((framecount - (1798 * minutes) - (2 * int(minutes / 10)) - (107892 * hours)) / 30); - var frames:int = framecount - (30 * seconds) - (1798 * minutes) - (2 * int(minutes / 10)) - (107892 * hours); - - var days:int = hours / 24; - hours = hours % 24; - - return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, true); - } - - /** - * Converts to SMPTE 12M 23.98fps. - * - * @param ticks27Mhz The number of 27Mhz ticks to convert from. - * @returns A string that contains the correct format. - */ - private static function ticks27MhzToSmpte12M_23_98fps(ticks27Mhz:Number):String - { - var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); - var framecount:int =int((4 / 15) * (pcrTb / 1001)); - var days:int = int((framecount / 86400) / 24); - var hours:int = int((framecount / 86400) % 24); - var minutes:int = int((framecount - (86400 * hours)) / 1440) % 60; - var seconds:int = int((framecount - (1440 * minutes) - (86400 * hours)) / 24) % 60; - var frames:int = (framecount - (24 * seconds) - (1440 * minutes) - (86400 * hours)) % 24; - - return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); - } - - /** - * Converts to SMPTE 12M 24fps. - * - * @param ticks27Mhz The number of 27Mhz ticks to convert from. - * @returns A string that contains the correct format. - */ - private static function ticks27MhzToSmpte12M_24fps(ticks27Mhz:Number):String - { - var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); - var framecount:int =int(pcrTb / 3750); - var days:int = int((framecount / 86400) / 24); - var hours:int = int((framecount / 86400) % 24); - var minutes:int = int((framecount - (86400 * hours)) / 1440) % 60; - var seconds:int = int((framecount - (1440 * minutes) - (86400 * hours)) / 24) % 60; - var frames:int = (framecount - (24 * seconds) - (1440 * minutes) - (86400 * hours)) % 24; - - return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); - } - - /** - * Converts to SMPTE 12M 25fps. - * - * @param ticks27Mhz The number of 27Mhz ticks to convert from. - * @returns A string that contains the correct format. - */ - private static function ticks27MhzToSmpte12M_25fps(ticks27Mhz:Number):String - { - var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); - var framecount:int =int(pcrTb / 3600); - var days:int = int((framecount / 90000) / 24); - var hours:int = int((framecount / 90000) % 24); - var minutes:int = int((framecount - (90000 * hours)) / 1500) % 60; - var seconds:int = int((framecount - (1500 * minutes) - (90000 * hours)) / 25) % 60; - var frames:int = (framecount - (25 * seconds) - (1500 * minutes) - (90000 * hours)) % 25; - - return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); - } - - /** - * Converts to SMPTE 12M 30fps. - * - * @param ticks27Mhz The number of 27Mhz ticks to convert from. - * @returns A string that contains the correct format. - */ - private static function ticks27MhzToSmpte12M_30fps(ticks27Mhz:Number):String - { - var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); - var framecount:int =int(pcrTb / 3000); - var days:int = int((framecount / 108000) / 24); - var hours:int = int((framecount / 108000) % 24); - var minutes:int = int((framecount - (108000 * hours)) / 1800) % 60; - var seconds:int = int((framecount - (1800 * minutes) - (108000 * hours)) / 30) % 60; - var frames:int = (framecount - (30 * seconds) - (1800 * minutes) - (108000 * hours)) % 30; - - return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); - } - } -} +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.timing +{ + import org.osmf.smpte.tt.enums.NumberType; + import org.osmf.smpte.tt.utilities.StringUtils; + + /** + * Represents a SMPTE 12M standard time code and provides conversion operations to various SMPTE time code formats and rates. + * + * Framerates supported by the TimeCode class include, 23.98 IVTC Film Sync, 24fps Film Sync, 25fps PAL, 29.97 drop frame, + * 29.97 Non drop, and 30fps. + */ + public class TimeCode + { + /** + * Regular expression object used for validating timecode. + */ + public static const SMPTEREGEXP:RegExp = /^(?:(?P\d+):)?(?P2[0-3]|[0-1]\d):(?P[0-5]\d):(?P[0-5]\d)(?::|;)(?P[0-2]\d)$/; + + /** + * The absolute time for this instance. + */ + private var _absoluteTime:AbsoluteTimeHelper; + + /** + * The frame rate for this instance. + */ + private var _frameRate:SmpteFrameRate; + + /** + * The TimeCode can be created from several different sets of parameters. + * + *

      With 5 or 6 parameters, initializes a new instance of the TimeCode structure + * to a specified number of days, hours, minutes, and seconds.

      + * + * @param days:int - Number of days. (optional) + * @param hours:int - Number of hours. + * @param minutes:int - Number of minutes. + * @param seconds:int - Number of seconds. + * @param frames:int - Number of frames. + * @param rate:SmpteFrameRate - The SMPTE frame rate. + * + *

      With 3 parameters, initializes a new instance of the TimeCode structure using + * a value of a 27 Mhz clock, and the SMPTE framerate, the third parameter is a + * Boolean to indicate that the first numeric parameter represents a value of 27 Mhz clock ticks.

      + * + * @param ticks27Mhz:Number - The value in 27 Mhz clock ticks. + * @param rate:SmpteFrameRate - The SMPTE framerate that this instance should use. + * @param isTicks27Mhz:Boolean - Boolean to indicate ticks of 27Mhz clock. + * + *

      With 2 parameters, initializes a new instance of the TimeCode structure using + * either an absolute time value, the totalSeconds of a TimeSpan object, + * or an SMPTE 12m time code string, + * and either an SMPTE framerate or a decimal rate.

      + * + * @param timeSpan:TimeSpan - The TimeSpan to be used for the new timecode.. + * or + * @param timeCode:String - The SMPTE 12m time code string. + * and + * @param rate:SmpteFrameRate - The SMPTE framerate that this instance should use. + * + *

      With 1 parameter, initializes a new instance of the TimeCode structure + * using a time code string that contains the framerate at the end of the string.

      + * + *

      Pass in a timecode in the format "timecode@framerate". + * Supported rates include @23.98, @24, @25, @29.97, @30

      + * + *

      For example:
      + * "00:01:00:00@29.97" is equivalent to 29.97 non drop frame.
      + * "00:01:00;00@29.97" is equivalent to 29.97 drop frame.

      + * + * @param timeCodeAndRate:String - The SMPTE 12m time code string. + */ + public function TimeCode(...args:*) + { + var len:uint = args.length, + days:Number, + hours:Number, + minutes:Number, + seconds:Number, + frames:Number, + timeCode:String="", + i:uint; + switch(len){ + case 6: + case 5: + initDaysHoursMinutesSecondsFramesRate.apply(null, args); + break; + case 3: + if(args[0] is Number + && args[1] is SmpteFrameRate + && args[2] is NumberType) + { + initTicks27Mhz.apply(null, args); + } else { + throw new Error("Parameters do not seem to combine to form a valid TimeCode: ["+args.toString()+"]"); + } + break; + case 2: + if(args[0] is TimeSpan) + { + initTimeSpan.apply(null, args); + } else if(args[0] is String + && args[1] is SmpteFrameRate) + { + initTimeCode.apply(null, args); + } else if(args[0] is Number + && args[1] is SmpteFrameRate) + { + initAbsoluteTime.apply(null, args); + } else + { + throw new Error("Parameters do not seem to combine to form a valid TimeCode: ["+args.toString()+"]"); + } + break; + case 1: + if(args[0] is String) + { + initTimeAndRate(args[0]); + } else + { + throw new Error("Parameter does not seem to represent a valid TimeCode: ["+args.toString()+"]"); + } + break; + } + // trace("new TimeCode("+args.toString()+") \n\t{ time27Mhz: "+absoluteTime.time27Mhz+", timeAsFloat: "+absoluteTime.timeAsFloat+", pcrTime: "+absoluteTime.pcrTime+" }\n"); + } + + /** + * Initializes a the TimeCode to a specified number of days, hours, minutes, and seconds. + * + * @param days:int - Number of days. (optional) + * @param hours:int - Number of hours. + * @param minutes:int - Number of minutes. + * @param seconds:int - Number of seconds. + * @param frames:int - Number of frames. + * @param rate:SmpteFrameRate - The SMPTE frame rate. + */ + private function initDaysHoursMinutesSecondsFramesRate(...args:*):void + { + var len:uint = args.length; + var lastIndex:uint = (len-1); + var days:Number = (len == 6) ? args[0] : 0; + var hours:Number = args[(lastIndex-4)]; + var minutes:Number = args[(lastIndex-3)]; + var seconds:Number = args[(lastIndex-2)]; + var frames:Number = args[(lastIndex-1)]; + + if (hours > 23) throw new Error("hours cannot be greater than 23"); + if (minutes > 59) throw new Error("minutes cannot be greater than 59"); + if (seconds > 59) throw new Error("seconds cannot be greater than 59"); + + _frameRate = (args[lastIndex] is SmpteFrameRate) ? args[lastIndex] : parseFramerate(args[lastIndex]); + + if(_frameRate != SmpteFrameRate.UNKNOWN) + { + var smpte12m:String = ""; + for(var i:uint=0; i= actualRate) throw new Error("frames cannot be greater than rate"); + _absoluteTime = new AbsoluteTimeHelper((1 / actualRate) * frames + seconds + (60 * minutes) + (3600 * hours),NumberType.DOUBLE); + } else + { + throw new Error("Parameters do not seem to combine to form a valid TimeCode: ["+args.toString()+"]"); + } + } + + /** + * Initializes a new instance of the TimeCode with a value of a 27 Mhz clock and the SMPTE frame rate. + * + * @param value The value in 27 Mhz clock ticks. + * @param rate The SMPTE framerate to use for this instance. + * @param numberType + */ + private function initTicks27Mhz(value:Number, rate:SmpteFrameRate, numberType:NumberType):void + { + _frameRate = rate; + _absoluteTime = new AbsoluteTimeHelper(value, numberType); + } + + /** + * Initializes a new instance of the TimeCode struct using the TotalSeconds in the supplied TimeSpan. + * + * @param timeSpan The TimeSpan to be used for the new timecode. + * @param rate The SMPTE frame rate. + */ + private function initTimeSpan(timeSpan:TimeSpan, rate:Object):void + { + if (rate is SmpteFrameRate) + { + _frameRate = SmpteFrameRate(rate); + _absoluteTime = TimeCode.fromTimeSpan(timeSpan, _frameRate).absoluteTime; + } else if (rate is Number) + { + _frameRate = parseFramerate(Number(rate)); + _absoluteTime = new AbsoluteTimeHelper(timeSpan.totalSeconds, NumberType.DOUBLE); + } else + { + throw new Error("Parameters do not seem to combine to form a valid TimeCode: ["+arguments.toString()+"]"); + } + } + + /** + * Initializes a new instance of the TimeCode using a time code string and a SMPTE framerate. + * + * @param timeCode The SMPTE 12m time code string. + * @param rate The SMPTE framerate to use for this instance. + */ + private function initTimeCode(smpte12M:String, rate:SmpteFrameRate):void + { + _frameRate = rate; + _absoluteTime = TimeCode.smpte12mToAbsoluteTime(smpte12M, _frameRate); + } + + /** + * Initializes a new instance of the TimeCode struct using an absolute time value, and the SMPTE framerate. + * + * @param value The absolute time value. + * @param rate The SMPTE framerate to use for this instance. + */ + private function initAbsoluteTime(value:Number, rate:SmpteFrameRate):void + { + _frameRate = rate; + _absoluteTime = new AbsoluteTimeHelper(value, NumberType.DOUBLE); + } + + /** + * Initializes a new instance of the TimeCode using a time code string that contains the framerate at the end of the string. + *

      + * Pass in a timecode in the format "timecode@framerate". + * Supported rates include @23.98, @24, @25, @29.97, @30 + *

      + * + *

      For example:
      + * "00:01:00:00@29.97" is equivalent to 29.97 non drop frame.
      + * "00:01:00;00@29.97" is equivalent to 29.97 drop frame. + *

      + * + * @param timeCodeAndRate The SMPTE 12m time code string. + */ + private function initTimeAndRate(timeCodeAndRate:String):void + { + var timeAndRate:Array = timeCodeAndRate.split("@"); + + var time:String = ""; + var rate:String = ""; + + if (timeAndRate.length == 1) + { + time = timeAndRate[0]; + rate = "29.97"; + } + else if (timeAndRate.length == 2) + { + time = timeAndRate[0]; + rate = timeAndRate[1]; + } + + switch (rate) + { + case "29.97": + _frameRate = (time.indexOf(';') != -1) ? SmpteFrameRate.SMPTE_2997_DROP : SmpteFrameRate.SMPTE_2997_NONDROP; + break; + case "25": + _frameRate = SmpteFrameRate.SMPTE_25; + break; + case "23.98": + _frameRate = SmpteFrameRate.SMPTE_2398; + break; + case "24": + _frameRate = SmpteFrameRate.SMPTE_24; + break; + case "30": + _frameRate = SmpteFrameRate.SMPTE_30; + break; + default: + _frameRate = SmpteFrameRate.SMPTE_2997_NONDROP; + break; + } + + _absoluteTime = TimeCode.smpte12mToAbsoluteTime(time, _frameRate); + } + + /** + * Convert an integer value into two digits. + * + * @param value An integer. + * @return a string with a leading zero for integers less than 10 + */ + private static function twoDigits(value:int):String + { + return (value / 10).toString(16) + (value % 10).toString(16); + } + + + /** + * The number of milliseconds in one day + */ + public static const MILLISECONDS_PER_DAY:Number = 86400000; + + /** + * The number of milliseconds in one hour + */ + public static const MILLISECONDS_PER_HOUR:Number = 3600000; + + /** + * The number of milliseconds in one minute + */ + public static const MILLISECONDS_PER_MINUTE:Number = 60000; + + /** + * The number of milliseconds in one second + */ + public static const MILLISECONDS_PER_SECOND:Number = 1000; + + /** + * The number of ticks in one millisecond + */ + public static const TICKS_PER_MILLISECOND:Number = 10000; + + /** + * The number of absolute time ticks in 1 millisecond. This field is constant. + */ + public static const TICKS_PER_MILLISECOND_ABSOLUTE_TIME:Number = 0.001; + + /** + * The number of ticks in one second + */ + public static const TICKS_PER_SECOND:Number = 10000000; + + /** + * The number of absolute time ticks in one second + */ + public static const TICKS_PER_SECOND_ABSOLUTE_TIME:Number = 1; + + /** + * The number of ticks in one minute + */ + public static const TICKS_PER_MINUTE:Number = 600000000; + + /** + * The number of absolute time ticks in one minute + */ + public static const TICKS_PER_MINUTE_ABSOLUTE_TIME:Number = 60; + + /** + * The number of ticks in one hour + */ + public static const TICKS_PER_HOUR:Number = 36000000000; + + /** + * The number of absolute time ticks in 1 hour. + */ + public static const TICKS_PER_HOUR_ABSOLUTE_TIME:Number = 3600; + + /** + * The number of ticks in one day + */ + public static const TICKS_PER_DAY:Number = 864000000000; + + /** + * The number of absolute time ticks in 1 day. + */ + public static const TICKS_PER_DAY_ABSOLUTE_TIME:Number = 86400; + + /** + * The minimum TimeCode value. This field is read-only. + */ + public static const MIN_VALUE:Number = 0; + + /** + * Gets the absolute time in seconds of the current TimeCode object. + */ + public function get duration():Number + { + return _absoluteTime.timeAsDouble; + } + + /** + * Gets or sets the current SMPTE framerate for this TimeCode instance. + */ + public function get frameRate():SmpteFrameRate + { + return _frameRate; + } + public function set frameRate(value:SmpteFrameRate):void + { + _frameRate = value; + } + + /** + * Gets the number of whole hours represented by the current TimeCode structure. + * + * @returns The hour component of the current TimeCode structure. The return value ranges from 0 through 23. + */ + public function get hoursSegment():int + { + var timeCode:String = TimeCode.absoluteTimeToSmpte12M(_absoluteTime, _frameRate); + var hours:String = timeCode.substring(0, 2); + return parseInt(hours); + } + + /** + * Gets the number of whole minutes represented by the current TimeCode structure. + * + * @returns The minute component of the current TimeCode structure. The return value ranges from 0 through 59. + */ + public function get minutesSegment():int + { + var timeCode:String = TimeCode.absoluteTimeToSmpte12M(this.absoluteTime, this.frameRate); + var minutes:String = timeCode.substring(3, 2); + return parseInt(minutes); + } + + /** + * Gets the number of whole seconds represented by the current TimeCode structure. + * + * @returns The seconds component of the current TimeCode structure. The return value ranges from 0 through 59. + */ + public function get secondsSegment():int + { + var timeCode:String = TimeCode.absoluteTimeToSmpte12M(_absoluteTime, _frameRate); + var seconds:String = timeCode.substring(6, 2); + return parseInt(seconds); + } + + /** + * Gets the number of whole frames represented by the current TimeCode structure. + * + * @returns The frame component of the current TimeCode structure. The return value depends on the framerate selected for this instance. All frame counts start at zero. + */ + public function get framesSegment():int + { + var timeCode:String = TimeCode.absoluteTimeToSmpte12M(_absoluteTime, _frameRate); + var frames:String = timeCode.substring(9, 2); + return parseInt(frames); + } + + /** + * Gets the value of the current TimeCode structure expressed in whole and fractional days. + * + * @returns The total number of days represented by this instance. + */ + public function get totalDays():Number + { + var framecount:Number = TimeCode.absoluteTimeToFrames(_absoluteTime, _frameRate); + return (framecount / 108000) / 24; + } + + /** + * Gets the value of the current TimeCode structure expressed in whole + * and fractional hours. + * + * @returns The total number of hours represented by this instance. + */ + public function get totalHours():Number + { + var framecount:Number = TimeCode.absoluteTimeToFrames(_absoluteTime, _frameRate); + + var hours:Number; + + switch (_frameRate) + { + case SmpteFrameRate.SMPTE_2398: + case SmpteFrameRate.SMPTE_24: + hours = framecount / 86400; + break; + case SmpteFrameRate.SMPTE_25: + hours = framecount / 90000; + break; + case SmpteFrameRate.SMPTE_2997_DROP: + hours = framecount / 107892; + break; + case SmpteFrameRate.SMPTE_2997_NONDROP: + case SmpteFrameRate.SMPTE_30: + hours = framecount / 108000; + break; + default: + hours = framecount / 108000; + break; + } + + return hours; + } + + /** + * Gets the value of the current TimeCode structure expressed in whole + * and fractional minutes. + * + * @returns The total number of minutes represented by this instance. + */ + public function get totalMinutes():Number + { + var framecount:Number = TimeCode.absoluteTimeToFrames(_absoluteTime, _frameRate); + + var minutes:Number; + + switch (_frameRate) + { + case SmpteFrameRate.SMPTE_2398: + case SmpteFrameRate.SMPTE_24: + minutes = framecount / 1400; + break; + case SmpteFrameRate.SMPTE_25: + minutes = framecount / 1500; + break; + case SmpteFrameRate.SMPTE_2997_DROP: + case SmpteFrameRate.SMPTE_2997_NONDROP: + case SmpteFrameRate.SMPTE_30: + minutes = framecount / 1800; + break; + default: + minutes = framecount / 1800; + break; + } + + return minutes; + } + + /** + * Gets the value of the current TimeCode structure expressed in whole + * and fractional seconds. Not as Precise as the TotalSecondsPrecision. + * + * @returns The total number of seconds represented by this instance. + */ + public function get totalSeconds():Number + { + return _absoluteTime.timeAsDouble; + } + + /** + * Gets the value of the current TimeCode structure expressed in whole + * and fractional seconds. This is returned as a for greater precision. + * + * @returns The total number of seconds represented by this instance. + */ + public function get totalSecondsPrecision():Number + { + return _absoluteTime.timeAsFloat; + } + + /** + * Gets the value of the current TimeCode structure expressed in frames. + * + * @returns The total number of frames represented by this instance. + */ + public function get totalFrames():Number + { + return TimeCode.absoluteTimeToFrames(_absoluteTime, _frameRate); + } + + /** + * Gets the maximum TimeCode value of a known frame rate. The Max value for Timecode. + * + * @param frameRate The frame rate to get the max value. + * @return The maximum TimeCode value for the given frame rate. + */ + public static function maxValue(frameRate:SmpteFrameRate):Number + { + var value:Number = 86399; + switch (frameRate) + { + case SmpteFrameRate.SMPTE_2398: + value = 86486.35829166667; + break; + case SmpteFrameRate.SMPTE_24: + value = 86399.95833333333; + break; + case SmpteFrameRate.SMPTE_25: + value = 86399.96; + break; + case SmpteFrameRate.SMPTE_2997_DROP: + value = 86399.88023333333; + break; + case SmpteFrameRate.SMPTE_2997_NONDROP: + value = 86486.36663333333; + break; + case SmpteFrameRate.SMPTE_30: + value = 86399.96666666667; + break; + default: + value = 86399; + break; + } + return value; + } + + /** + * The private Timespan used to track absolute time for this instance. + */ + private function get absoluteTime():AbsoluteTimeHelper + { + if (!_absoluteTime) + _absoluteTime = new AbsoluteTimeHelper(0); + + return _absoluteTime; + } + private function set absoluteTime(value:AbsoluteTimeHelper):void + { + _absoluteTime = value; + } + + /** + * Returns a SMPTE 12M formatted time code string from a 27Mhz ticks value. + * + * @param ticks27Mhz 27Mhz ticks value. + * @param rate The SMPTE time code framerate desired. + * @returns A SMPTE 12M formatted time code string. + */ + public static function ticks27MhzToSmpte12M(ticks27Mhz:Number, rate:SmpteFrameRate):String + { + var s:String = TimeCode.ticks27MhzToSmpte12M_30fps(ticks27Mhz); + + switch (rate) + { + case SmpteFrameRate.SMPTE_2398: + s = TimeCode.ticks27MhzToSmpte12M_23_98fps(ticks27Mhz); + break; + case SmpteFrameRate.SMPTE_24: + s = TimeCode.ticks27MhzToSmpte12M_24fps(ticks27Mhz); + break; + case SmpteFrameRate.SMPTE_25: + s = TimeCode.ticks27MhzToSmpte12M_25fps(ticks27Mhz); + break; + case SmpteFrameRate.SMPTE_2997_DROP: + s = TimeCode.ticks27MhzToSmpte12M_29_27_Drop(ticks27Mhz); + break; + case SmpteFrameRate.SMPTE_2997_NONDROP: + s = TimeCode.ticks27MhzToSmpte12M_29_27_NonDrop(ticks27Mhz); + break; + case SmpteFrameRate.SMPTE_30: + s = TimeCode.ticks27MhzToSmpte12M_30fps(ticks27Mhz); + break; + } + + return s; + } + + /** + * Subtracts a specified TimeCode from this TimeCode. + * + * @param t2 The TimeCode to subtract. + * + * @returns A TimeCode whose value is the result of the value of this minus the value of t2. + */ + public function minus(t2:TimeCode):TimeCode + { + + var frames:Number = totalFrames - t2.totalFrames; + var t3:TimeCode = TimeCode.fromFrames(frames, _frameRate); + + if (t3.totalSecondsPrecision < TimeCode.MIN_VALUE) + { + throw new Error("MinValueSmpte12MOverflowException"); + } + + return t3; + } + + /** + * Adds a specified TimeCode to this TimeCode. + * + * @param t2 The TimeCode to add. + * + * @returns A TimeCode whose value is the result of the value of this plus the value of t2. + */ + public function plus(t2:TimeCode):TimeCode + { + var frames:Number = totalFrames + t2.totalFrames; + var t3:TimeCode = TimeCode.fromFrames(frames, _frameRate); + + return t3; + } + + /** + * Indicates whether this TimeCode is less than another given TimeCode. + * + * @param t2 The TimeCode to compare. + * + * @returns true if the value of this is less than the value of t2; otherwise, false. + */ + public function lessThan(t2:TimeCode):Boolean + { + if(TimeCode.Compare(this,t2)==-1) + { + return true; + } + return false; + } + + /** + * Indicates whether this TimeCode is less than or equal to another given TimeCode. + * + * @param t2 The TimeCode to compare. + * + * @returns true if the value of this is less than or equal to the value of t2; otherwise, false. + */ + public function lessThanOrEqualTo(t2:TimeCode):Boolean + { + var compare:int = TimeCode.Compare(this,t2); + if(compare==-1 || compare==0) + { + return true; + } + return false; + } + + /** + * Indicates whether this TimeCode is not equal to another given TimeCode. + * + * @param t2 The TimeCode to compare. + * + * @returns true if the value of this is not equal to the value of t2; otherwise, false. + */ + public function notEqualTo(t2:TimeCode):Boolean + { + return !this.equalTo(t2); + } + + /** + * Indicates whether this TimeCode is equal to another given TimeCode. + * + * @param t2 The TimeCode to compare. + * + * @returns true if the value of this is equal to the value of t2; otherwise, false. + */ + public function equalTo(t2:TimeCode):Boolean + { + if(TimeCode.Compare(this,t2)==0) + { + return true; + } + return false; + } + + /** + * Indicates whether this TimeCode equals another given TimeCode. + * + * @param t2 The TimeCode to compare. + * + * @returns true if the value of this equals the value of t2; otherwise, false. + */ + public function equals(t2:Object):Boolean + { + if (!(t2 is TimeCode)) + { + throw new ArgumentError("Object to compare must be a TimeCode"); + } + return this.equalTo(t2 as TimeCode); + } + + /** + * Indicates whether this TimeCode is greater than or equal to another given TimeCode. + * + * @param t2 The TimeCode to compare. + * + * @returns true if the value of this is greater than or equal to the value of t2; otherwise, false. + */ + public function greaterThanOrEqualTo(t2:TimeCode):Boolean + { + var compare:int = TimeCode.Compare(this,t2); + if(compare==1 || compare==0) + { + return true; + } + return false; + } + + /** + * Indicates whether this TimeCode is greater than another given TimeCode. + * + * @param t2 The TimeCode to compare. + * + * @returns true if the value of this is greater than the value of t2; otherwise, false. + */ + public function greaterThan(t2:TimeCode):Boolean + { + if(TimeCode.Compare(this,t2)==1) + { + return true; + } + return false; + } + + /** + * Compares two TimeCode values and returns an integer that indicates their relationship. + * + * @param t1 The first TimeCode. + * @param t2 The second TimeCode. + * + * @returns Value Condition -1 t1 is less than t2, 0 t1 is equal to t2, 1 t1 is greater than t2. + */ + public static function Compare(t1:TimeCode,t2:TimeCode):int + { + // trace("Compare: "+t1.absoluteTime.timeAsDouble +" to "+ t2.absoluteTime.timeAsDouble); + var timeCode1:TimeCode = new TimeCode(t1.absoluteTime.timeAsDouble, SmpteFrameRate.SMPTE_30, NumberType.DOUBLE); + var timeCode2:TimeCode = new TimeCode(t2.absoluteTime.timeAsDouble, SmpteFrameRate.SMPTE_30, NumberType.DOUBLE); + + if (timeCode1.totalFrames < timeCode2.totalFrames) + { + return -1; + } else if(timeCode1.totalFrames == timeCode2.totalFrames){ + return 0; + } + + return 1; + } + + /** + * Returns a value indicating whether two specified instances of TimeCode + * are equal. + * + * @param t1 The first TimeCode. + * @param t2 The second TimeCode. + * + * @returns true if the values of t1 and t2 are equal; otherwise, false. + */ + public static function Equals(t1:TimeCode,t2:TimeCode):Boolean + { + return t1.equals(t2); + } + + /** + * Returns a TimeCode that represents a specified number of days, where the specification is accurate to the nearest millisecond. + * + * @param value A number of days accurate to the nearest millisecond. + * @param rate The desired SmpteFrameRate framerate for this instance. + * @returns A TimeCode that represents value. + */ + public static function fromDays(value:Number, rate:SmpteFrameRate):TimeCode + { + var ticks:Number = value * TimeCode.TICKS_PER_DAY_ABSOLUTE_TIME; + return new TimeCode(ticks, rate, NumberType.DOUBLE); + } + + /** + * Returns a TimeCode that represents a specified number of hours, where the specification is accurate to the nearest millisecond. + * + * @param value A number of hours accurate to the nearest millisecond. + * @param rate The desired SmpteFrameRate framerate for this instance. + * @returns A TimeCode that represents value. + */ + public static function fromHours(value:Number, rate:SmpteFrameRate):TimeCode + { + var ticks:Number = value * TimeCode.TICKS_PER_HOUR_ABSOLUTE_TIME; + return new TimeCode(ticks, rate, NumberType.DOUBLE); + } + + /** + * Returns a TimeCode that represents a specified number of minutes, where the specification is accurate to the nearest millisecond. + * + * @param value A number of minutes accurate to the nearest millisecond. + * @param rate The desired SmpteFrameRate framerate for this instance. + * @returns A TimeCode that represents value. + */ + public static function fromMinutes(value:Number, rate:SmpteFrameRate):TimeCode + { + var ticks:Number = value * TimeCode.TICKS_PER_MINUTE_ABSOLUTE_TIME; + return new TimeCode(ticks, rate, NumberType.DOUBLE); + } + + /** + * Returns a TimeCode that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. + * + * @param value A number of seconds accurate to the nearest millisecond. + * @param rate The desired SmpteFrameRate framerate for this instance. + * @returns A TimeCode that represents value. + */ + public static function fromSeconds(value:Number, rate:SmpteFrameRate):TimeCode + { + var ticks:Number = value * TimeCode.TICKS_PER_SECOND_ABSOLUTE_TIME; + return new TimeCode(ticks, rate, NumberType.DOUBLE); + } + + /** + * Returns a TimeCode that represents a specified number of frames. + * + * @param value A number of frames. + * @param rate The framerate of the Timecode. + * @returns A TimeCode that represents value. + */ + public static function fromFrames(value:Number, rate:SmpteFrameRate):TimeCode + { + var ticks27Mhz:Number = TimeCode.framesToTicks27Mhz(value, rate); + return new TimeCode(ticks27Mhz, rate, NumberType.ULONG); + } + + /** + * Returns a TimeCode that represents a specified time, where the specification is in units of ticks. + * + * @param ticks A number of ticks that represent a time. + * @param rate The Smpte framerate. + * @returns A TimeCode with a value of value. + */ + public static function fromTicks(ticks:Number, rate:SmpteFrameRate):TimeCode + { + var value:Number = 1e-7 * ticks; + return new TimeCode(value, rate, NumberType.DOUBLE); + } + + /** + * Returns a TimeCode that represents a specified time, where the specification is in units of 27 Mhz clock ticks. + * + * @param value A number of ticks in 27 Mhz clock format. + * @param rate A Smpte framerate. + * @returns A TimeCode. + */ + public static function fromTicks27Mhz(value:Number, rate:SmpteFrameRate):TimeCode + { + return new TimeCode(value, rate, NumberType.ULONG); + } + + /** + * Returns a TimeCode that represents a specified time, where the specification is in units of absolute time. + * + * @param value The absolute time in 100 nanosecond units. + * @param rate The SMPTE framerate. + * @returnss A TimeCode. + */ + public static function fromAbsoluteTime(value:Number, rate:SmpteFrameRate):TimeCode + { + return new TimeCode(value, rate, NumberType.DOUBLE); + } + + /** + * Returns a TimeCode that represents a specified time, where the specification is in units of absolute time. + * + * @param value The TimeSpan object. + * @param rate The SMPTE framerate. + * @returnss A TimeCode. + */ + public static function fromTimeSpan(value:TimeSpan, rate:SmpteFrameRate):TimeCode + { + return new TimeCode(value.totalSeconds, rate); + } + + /** + * Validates that the string provided is in the correct format for SMPTE 12M time code. + * + * @param timeCode String that is the time code. + * @returns True if this is a valid SMPTE 12M time code string. + */ + public static function validateSmpte12MTimecode(timeCode:String):Boolean + { + return TimeCode.SMPTEREGEXP.test(timeCode); + } + + /** + * Returns the value of the provided time code string and framerate in 27Mhz ticks. + * + * @param timeCode The SMPTE 12M formatted time code string. + * @param rate The SMPTE framerate. + * @returns A number that represents the value of the time code in 27Mhz ticks. + */ + public static function smpte12MToTicks27Mhz(timeCode:String, rate:SmpteFrameRate):Number + { + var t:Number = TimeCode.smpte12M_30fpsToTicks27Mhz(timeCode); + + switch (rate) + { + case SmpteFrameRate.SMPTE_2398: + t = TimeCode.smpte12M_23_98fpsToTicks27Mhz(timeCode); + break; + case SmpteFrameRate.SMPTE_24: + t = TimeCode.smpte12M_24fpsToTicks27Mhz(timeCode); + break; + case SmpteFrameRate.SMPTE_25: + t = TimeCode.smpte12M_25fpsToTicks27Mhz(timeCode); + break; + case SmpteFrameRate.SMPTE_2997_DROP: + t = TimeCode.smpte12M_29_27_DropToTicks27Mhz(timeCode); + break; + case SmpteFrameRate.SMPTE_2997_NONDROP: + t = TimeCode.smpte12M_29_27_NonDropToTicks27Mhz(timeCode); + break; + case SmpteFrameRate.SMPTE_30: + t = TimeCode.smpte12M_30fpsToTicks27Mhz(timeCode); + break; + default: + t = TimeCode.smpte12M_30fpsToTicks27Mhz(timeCode); + break; + } + + return t; + } + + /** + * Parses a framerate value as double and converts it to a member of the SmpteFrameRate enumeration. + * + * @param rate Double value of the framerate. + * @returns A SmpteFrameRate enumeration value that matches the incoming rates. + */ + public static function parseFramerate(rate:Number):SmpteFrameRate + { + var rateFloored:int = Math.floor(rate); + var s:SmpteFrameRate = SmpteFrameRate.UNKNOWN; + + switch (rateFloored) + { + case 23: + s = SmpteFrameRate.SMPTE_2398; + break; + case 24: + s = SmpteFrameRate.SMPTE_24; + break; + case 25: + s = SmpteFrameRate.SMPTE_25; + break; + case 29: + s = SmpteFrameRate.SMPTE_2997_NONDROP; + break; + case 30: + s = SmpteFrameRate.SMPTE_30; + break; + case 50: + s = SmpteFrameRate.SMPTE_25; + break; + case 60: + s = SmpteFrameRate.SMPTE_30; + break; + case 59: + s = SmpteFrameRate.SMPTE_2997_NONDROP; + break; + } + + return s; + } + + /** + * Adds the specified TimeCode to this instance. + * + * @param ts A TimeCode. + * @returns A TimeCode that represents the value of this instance plus the value of ts. + */ + public function add(ts:TimeCode):TimeCode + { + return this.plus(ts); + } + + /** + * Compares this instance to a specified object and returns an indication of their relative values. + * + * @param value An object to compare, or null. + * @returns Value Condition -1 The value of this instance is less than the value of value. 0 The value of this instance is equal to the value of value. 1 The value of this instance is greater than the value of value.-or- value is null. + */ + public function compareTo(value:Object):int + { + if (!(value is TimeCode)) + { + throw new Error("Object to compare must be a TimeCode"); + } + + var t1:TimeCode = value as TimeCode; + + return TimeCode.Compare(this,t1); + } + + /** + * Subtracts the specified TimeCode from this instance. + * + * @param ts A TimeCode. + * @returns A TimeCode whose value is the result of the value of this instance minus the value of ts. + */ + public function subtract(ts:TimeCode):TimeCode + { + return this.minus(ts); + } + + /** + * Returns the SMPTE 12M string representation of the value of this instance. + * + * @return A string that represents the value of this instance. The return value is + * of the form: hh:mm:ss:ff for non-drop frame and hh:mm:ss;ff for drop frame code + * with "hh" hours, ranging from 0 to 23, "mm" minutes + * ranging from 0 to 59, "ss" seconds ranging from 0 to 59, and "ff" based on the + * chosen framerate to be used by the time code instance. + * + */ + public function toString():String + { + return TimeCode.absoluteTimeToSmpte12M(_absoluteTime, _frameRate); + } + + /** + * Returns the SMPTE 12M string representation of the value of this instance. + * + * @returns A string that represents the value of this instance. The return value is + * of the form: hh:mm:ss:ff for non-drop frame and hh:mm:ss;ff for drop frame code + * with "hh" hours, ranging from 0 to 23, "mm" minutes + * ranging from 0 to 59, "ss" seconds ranging from 0 to 59, and "ff" based on the + * chosen framerate to be used by the time code instance. + */ + public function toStringAtFramerate(rate:SmpteFrameRate=null):String + { + return TimeCode.absoluteTimeToSmpte12M(_absoluteTime, ((rate!=null) ? rate : _frameRate)); + } + + /** + * Returns the value of this instance in 27 Mhz ticks. + * + * @returns A ulong value that is in 27 Mhz ticks. + */ + public function toTicks27Mhz():Number + { + return TimeCode.absoluteTimeToTicks27Mhz(_absoluteTime); + } + + /** + * Returns the value of this instance in MPEG 2 PCR time base (PcrTb) format. + * + * @returns A Number value that is in PcrTb. + */ + public function toTicksPcrTb():Number + { + return TimeCode.absoluteTimeToTicksPcrTb(_absoluteTime); + } + + /** + * Converts a SMPTE timecode to absolute time. + * + * @param timeCodeThe timecode to convert from. + * @param rate The SmpteFrameRate of the timecode. + * @returns An AbsoluteTimeHelper with the absolute time. + */ + private static function smpte12mToAbsoluteTime(timeCode:String, rate:SmpteFrameRate):AbsoluteTimeHelper + { + var absoluteTimeHelper:AbsoluteTimeHelper = new AbsoluteTimeHelper(0); + + switch (rate) + { + case SmpteFrameRate.SMPTE_2398: + absoluteTimeHelper = TimeCode.smpte12M_23_98_ToAbsoluteTime(timeCode); + break; + case SmpteFrameRate.SMPTE_24: + absoluteTimeHelper = TimeCode.smpte12M_24_ToAbsoluteTime(timeCode); + break; + case SmpteFrameRate.SMPTE_25: + absoluteTimeHelper = TimeCode.smpte12M_25_ToAbsoluteTime(timeCode); + break; + case SmpteFrameRate.SMPTE_2997_DROP: + absoluteTimeHelper = TimeCode.smpte12M_29_97_Drop_ToAbsoluteTime(timeCode); + break; + case SmpteFrameRate.SMPTE_2997_NONDROP: + absoluteTimeHelper = TimeCode.smpte12M_29_97_NonDrop_ToAbsoluteTime(timeCode); + break; + case SmpteFrameRate.SMPTE_30: + absoluteTimeHelper = TimeCode.smpte12M_30_ToAbsoluteTime(timeCode); + break; + } + return absoluteTimeHelper; + } + + /** + * Parses a timecode string for the different parts of the timecode. + * + * @param timeCode The source timecode to parse. + */ + private static function parseTimecodeString(timeCode:String):TimeCodeComponents + { + var times:Array = timeCode.match(TimeCode.SMPTEREGEXP); + + if (!times || times.length==0) + { + throw new Error(timeCode+" is not a valid SMPTE 12M timecode"); + } + + var out:TimeCodeComponents = new TimeCodeComponents(); + out.days = 0; + + if (times.Days!=null) + { + out.days = parseInt(times.Days,10); + } + + out.hours = parseInt(times.Hours,10); + out.minutes = parseInt(times.Minutes,10); + out.seconds = parseInt(times.Seconds,10); + out.frames = parseInt(times.Frames,10); + + return out; + } + + /** + * Generates a string representation of the timecode. + * + * @param days The Days section from the timecode. + * @param hours The Hours section from the timecode. + * @param minutes The Minutes section from the timecode. + * @param seconds The Seconds section from the timecode. + * @param frames The frames section from the timecode. + * @param dropFrame Indicates whether the timecode is drop frame or not. + * @returns The timecode in string format. + */ + private static function formatTimeCodeString(days:int=0, hours:int=0, minutes:int=0, seconds:int=0, frames:int=0, dropFrame:Boolean = false):String + { + var h:String = TimeCode.twoDigits(hours), + m:String = TimeCode.twoDigits(minutes), + s:String = TimeCode.twoDigits(seconds), + f:String = TimeCode.twoDigits(frames), + framesSeparator:String = (dropFrame) ? ";" : ":"; + + if (days > 0) + { + return StringUtils.formatString("{0}:{1}:{2}:{3}{5}{4}", days, h, m, s, f, framesSeparator); + } + + return StringUtils.formatString("{0}:{1}:{2}{4}{3}", h, m, s, f, framesSeparator); + } + + /** + * Converts to Absolute time from SMPTE 12M 23.98. + * + * @param timeCode The timecode to parse. + * @returns An AbsoluteTimeHelper that contains the absolute duration. + */ + private static function smpte12M_23_98_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper + { + var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); + var days:int = obj.days, + hours:int = obj.hours, + minutes:int = obj.minutes, + seconds:int = obj.seconds, + frames:int = obj.frames; + + if (frames >= 24) + { + throw new Error("Timecode frame value is not in the expected range for SMPTE 23.98 IVTC."); + } + + var framesHertz:Number = Math.ceil(3753.75 * frames); + var secondsHertz:int = 90090 * seconds; + var minutesHertz:int = 5405400 * minutes; + var hoursHertz:Number = 324324000 * hours; + var daysHertz:Number = 7783776000 * days; + + var pcrTb:Number = framesHertz + secondsHertz + minutesHertz + hoursHertz + daysHertz; + + var ticks27Mhz:Number = pcrTb * 300; + + return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); + } + + /** + * Converts to Absolute time from SMPTE 12M 24. + * + * @param timeCode The timecode to parse. + * @returns An AbsoluteTimeHelper that contains the absolute duration. + */ + private static function smpte12M_24_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper + { + var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); + var days:int = obj.days, + hours:int = obj.hours, + minutes:int = obj.minutes, + seconds:int = obj.seconds, + frames:int = obj.frames; + + if (frames >= 24) + { + throw new Error("Timecode frame value is not in the expected range for SMPTE 24fps Film Sync."); + } + + var ticks27Mhz:Number = ( (3750 * frames) + + (90000 * seconds) + + (5400000 * minutes) + + (324000000 * hours) + + (7776000000 * days) ) * 300; + return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); + } + + /** + * Converts to Absolute time from SMPTE 12M 25. + * + * @param timeCode The timecode to parse. + * @returns An AbsoluteTimeHelper that contains the absolute duration. + */ + private static function smpte12M_25_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper + { + var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); + var days:int = obj.days, + hours:int = obj.hours, + minutes:int = obj.minutes, + seconds:int = obj.seconds, + frames:int = obj.frames; + + if (frames >= 25) + { + throw new Error("Timecode frame value is not in the expected range for SMPTE 25fps PAL."); + } + + var ticks27Mhz:Number = ( (3600 * frames) + + (90000 * seconds) + + (5400000 * minutes) + + (324000000 * hours) + + (7776000000 * days) ) * 300; + return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); + } + + /** + * Converts to Absolute time from SMPTE 12M 29.97 Drop frame. + * + * @param timeCode The timecode to parse. + * @returns An AbsoluteTimeHelper that contains the absolute duration. + */ + private static function smpte12M_29_97_Drop_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper + { + var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); + var days:int = obj.days, + hours:int = obj.hours, + minutes:int = obj.minutes, + seconds:int = obj.seconds, + frames:int = obj.frames; + + if (frames >= 30) + { + throw new Error("Timecode frame value is not in the expected range for SMPTE 29.97 DropFrame."); + } + + var time:Number = (1001 / 30000) * (frames + (30 * seconds) + (1798 * minutes) + ((2 * (minutes / 10)) + (107892 * hours) + (2589408 * days))); + return new AbsoluteTimeHelper(time,NumberType.DOUBLE); + } + + /** + * Converts to Absolute time from SMPTE 12M 29.97 Non Drop. + * + * @param timeCode The timecode to parse. + * @returns An AbsoluteTimeHelper that contains the absolute duration. + */ + private static function smpte12M_29_97_NonDrop_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper + { + var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); + var days:int = obj.days, + hours:int = obj.hours, + minutes:int = obj.minutes, + seconds:int = obj.seconds, + frames:int = obj.frames; + + if (frames >= 30) + { + throw new Error("Timecode frame value is not in the expected range for SMPTE 29.97 NonDrop."); + } + + var ticks27Mhz:Number = ( (3003 * frames) + + (90090 * seconds) + + (5405400 * minutes) + + (324324000 * hours) + + (7783776000 * days) ) * 300; + return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); + } + + /** + * Converts to Absolute time from SMPTE 12M 30. + * + * @param timeCode The timecode to parse. + * @returns An AbsoluteTimeHelper that contains the absolute duration. + */ + private static function smpte12M_30_ToAbsoluteTime(timeCode:String):AbsoluteTimeHelper + { + var obj:TimeCodeComponents = TimeCode.parseTimecodeString(timeCode); + var days:int = obj.days, + hours:int = obj.hours, + minutes:int = obj.minutes, + seconds:int = obj.seconds, + frames:int = obj.frames; + + if (frames >= 30) + { + throw new Error("Timecode frame value is not in the expected range for SMPTE 30fps."); + } + + var ticks27Mhz:Number = ( (3000 * frames) + + (90000 * seconds) + + (5400000 * minutes) + + (324000000 * hours) + + (7776000000 * days) ) * 300; + return new AbsoluteTimeHelper(ticks27Mhz,NumberType.ULONG); + } + + /** + * Converts from 27Mhz ticks to PCRTb. + * + * @param ticks27Mhz >The number of 27Mhz ticks to convert from. + * @returns A Number with the PCRTb. + */ + internal static function ticks27MhzToPcrTb(ticks27Mhz:Number):Number + { + return ticks27Mhz / 300; + } + + /** + * Converts the provided absolute time to PCRTb. + * + * @param time Absolute time to be converted. + * @returns The number of PCRTb ticks. + */ + internal static function absoluteTimeToTicksPcrTb(time:AbsoluteTimeHelper):Number + { + return Math.round(time.timeAsDouble * 90000); + } + + /** + * Converts the specified absolute time to 27 mhz ticks. + * + * @param time Absolute time to be converted. + * @returns The number of 27Mhz ticks. + */ + internal static function absoluteTimeToTicks27Mhz(time:AbsoluteTimeHelper):Number + { + return TimeCode.absoluteTimeToTicksPcrTb(time) * 300; + } + + /** + * Converts the specified absolute time to absolute time. + * + * @param ticksPcrTb Ticks PCRTb to be converted. + * @returns The absolute time. + */ + internal static function ticksPcrTbToAbsoluteTime(ticksPcrTb:Number):Number + { + return ticksPcrTb / 90000; + } + + /** + * Converts the specified absolute time to absolute time. + * + * @param ticks27Mhz Ticks 27Mhz to be converted. + * @returns The absolute time. + */ + internal static function ticks27MhzToAbsoluteTime(ticks27Mhz:Number):Number + { + var ticksPcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); + return TimeCode.ticksPcrTbToAbsoluteTime(ticksPcrTb); + } + + /** + * Converts to SMPTE 12M. + * + * @param time The absolute time to convert from. + * @param rate The SMPTE frame rate. + * @returns A string in SMPTE 12M format. + */ + private static function absoluteTimeToSmpte12M(time:AbsoluteTimeHelper, rate:SmpteFrameRate):String + { + var timeCode:String = ""; + + switch(rate) + { + case SmpteFrameRate.SMPTE_2398: + timeCode = TimeCode.absoluteTimeToSmpte12M_23_98fps(time); + break; + case SmpteFrameRate.SMPTE_24: + timeCode = TimeCode.absoluteTimeToSmpte12M_24fps(time); + break; + case SmpteFrameRate.SMPTE_25: + timeCode = TimeCode.absoluteTimeToSmpte12M_25fps(time); + break; + case SmpteFrameRate.SMPTE_2997_DROP: + timeCode = TimeCode.absoluteTimeToSmpte12M_29_97_Drop(time); + break; + case SmpteFrameRate.SMPTE_2997_NONDROP: + timeCode = TimeCode.absoluteTimeToSmpte12M_29_97_NonDrop(time); + break; + case SmpteFrameRate.SMPTE_30: + default: + timeCode = TimeCode.absoluteTimeToSmpte12M_30fps(time); + break; + } + + return timeCode; + } + + /** + * Returns the absolute time. + * + * @param frames The number of frames. + * @param rate The SMPTE frame rate to use for the conversion. + * @returns The absolute time. + */ + private static function framesToAbsoluteTime(frames:Number, rate:SmpteFrameRate):Number + { + var absoluteTimeInDecimal:Number; + + switch(rate) + { + case SmpteFrameRate.SMPTE_2398: + absoluteTimeInDecimal = frames / 24 / (1000 / 1001); + break; + case SmpteFrameRate.SMPTE_24: + absoluteTimeInDecimal = frames / 24; + break; + case SmpteFrameRate.SMPTE_25: + absoluteTimeInDecimal = frames / 25; + break; + case SmpteFrameRate.SMPTE_2997_DROP: + case SmpteFrameRate.SMPTE_2997_NONDROP: + absoluteTimeInDecimal = frames / 30 / (1000 / 1001); + break; + case SmpteFrameRate.SMPTE_30: + default: + absoluteTimeInDecimal = frames / 30; + break; + } + + return absoluteTimeInDecimal; + } + + /** + * Returns the absolute time. + * + * @param frames The number of frames. + * @param rate The SMPTE frame rate to use for the conversion. + * @returns The absolute time. + */ + private static function framesToTicks27Mhz(frames:Number, rate:SmpteFrameRate):Number + { + var ticks27Mhz:Number; + + switch(rate) + { + case SmpteFrameRate.SMPTE_2398: + ticks27Mhz = frames * 3753.75 * 300; + break; + case SmpteFrameRate.SMPTE_24: + ticks27Mhz = frames * 3750 * 300; + break; + case SmpteFrameRate.SMPTE_25: + ticks27Mhz = frames * 3600 * 300; + break; + case SmpteFrameRate.SMPTE_2997_DROP: + case SmpteFrameRate.SMPTE_2997_NONDROP: + ticks27Mhz = frames * 3003 * 300; + break; + case SmpteFrameRate.SMPTE_30: + default: + ticks27Mhz = frames * 3000 * 300; + break; + } + + return ticks27Mhz; + } + + /** + * Returns the absolute time. + * + * @param absoluteTime The number of frames. + * @param rate The SMPTE frame rate to use for the conversion. + * @returns The absolute time. + */ + private static function absoluteTimeToFrames(absoluteTime:AbsoluteTimeHelper, rate:SmpteFrameRate):Number + { + var frames:Number; + + switch(rate) + { + case SmpteFrameRate.SMPTE_2398: + frames = absoluteTime.pcrTime / 3753.75; + break; + case SmpteFrameRate.SMPTE_24: + frames = absoluteTime.pcrTime / 3750; + break; + case SmpteFrameRate.SMPTE_25: + frames = absoluteTime.pcrTime / 3600; + break; + case SmpteFrameRate.SMPTE_30: + frames = absoluteTime.pcrTime / 3000; + break; + case SmpteFrameRate.SMPTE_2997_DROP: + case SmpteFrameRate.SMPTE_2997_NONDROP: + default: + frames = absoluteTime.pcrTime / 3003; + break; + } + + return frames; + } + + /** + * Returns the SMPTE 12M 23.98 timecode. + * + * @param absoluteTime The absolute time to convert from. + * @returns A string that contains the correct format. + */ + private static function absoluteTimeToSmpte12M_23_98fps(absoluteTime:AbsoluteTimeHelper):String + { + return TimeCode.ticks27MhzToSmpte12M_23_98fps(absoluteTime.time27Mhz); + } + + /** + * Converts to SMPTE 12M 24fps. + * + * @param absoluteTime The absolute time to convert from. + * @returns A string that contains the correct format. + */ + private static function absoluteTimeToSmpte12M_24fps(absoluteTime:AbsoluteTimeHelper):String + { + return TimeCode.ticks27MhzToSmpte12M_24fps(absoluteTime.time27Mhz); + } + + /** + * Converts to SMPTE 12M 25fps. + * + * @param absoluteTime The absolute time to convert from. + * @returns A string that contains the correct format. + */ + private static function absoluteTimeToSmpte12M_25fps(absoluteTime:AbsoluteTimeHelper):String + { + return TimeCode.ticks27MhzToSmpte12M_25fps(absoluteTime.time27Mhz); + } + + /** + * Converts to SMPTE 12M 29.97fps Drop. + * + * @param absoluteTime The absolute time to convert from. + * @returns A string that contains the correct format. + */ + private static function absoluteTimeToSmpte12M_29_97_Drop(absoluteTime:AbsoluteTimeHelper):String + { + return TimeCode.ticks27MhzToSmpte12M_29_27_Drop(absoluteTime.time27Mhz); + } + + /** + * Converts to SMPTE 12M 29.97fps Non Drop. + * + * @param absoluteTime The absolute time to convert from. + * @returns A string that contains the correct format. + */ + private static function absoluteTimeToSmpte12M_29_97_NonDrop(absoluteTime:AbsoluteTimeHelper):String + { + return TimeCode.ticks27MhzToSmpte12M_29_27_NonDrop(absoluteTime.time27Mhz); + } + + /** + * Converts to SMPTE 12M 30fps. + * + * @param absoluteTime The absolute time to convert from. + * @returns A string that contains the correct format. + */ + private static function absoluteTimeToSmpte12M_30fps(absoluteTime:AbsoluteTimeHelper):String + { + return TimeCode.ticks27MhzToSmpte12M_30fps(absoluteTime.time27Mhz); + } + + /** + * Converts to Ticks 27Mhz. + * + * @param timeCode The timecode to convert from. + * @return The number of 27Mhz ticks. + * + */ + private static function smpte12M_30fpsToTicks27Mhz(timeCode:String):Number + { + var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_30); + var ticksPcrTb:Number = Math.round((t.framesSegment * 3000) + + (90000 * t.secondsSegment) + + (5400000 * t.minutesSegment) + + (324000000 * t.hoursSegment)); + return ticksPcrTb * 300; + } + + /** + * Converts to Ticks 27Mhz. + * + * @param timeCode + * @return The number of 27Mhz ticks. + * + */ + private static function smpte12M_23_98fpsToTicks27Mhz(timeCode:String):Number + { + var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_2398); + var ticksPcrTb:Number = Math.round(Math.ceil(t.framesSegment * 3753.75) + + (90090 * t.secondsSegment) + + (5405400 * t.minutesSegment) + + (324324000 * t.hoursSegment)); + return ticksPcrTb * 300; + } + + /** + * Converts to Ticks 27Mhz. + * + * @param timeCode The timecode to convert from. + * @return The number of 27Mhz ticks. + */ + private static function smpte12M_24fpsToTicks27Mhz(timeCode:String):Number + { + var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_24); + var ticksPcrTb:Number = Math.round((t.framesSegment * 3750) + + (90000 * t.secondsSegment) + + (5400000 * t.minutesSegment) + + (324000000 * t.hoursSegment)); + return ticksPcrTb * 300; + } + + /** + * Converts to Ticks 27Mhz. + * + * @param timeCode The timecode to convert from. + * @return The number of 27Mhz ticks. + */ + private static function smpte12M_25fpsToTicks27Mhz(timeCode:String):Number + { + var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_25); + var ticksPcrTb:Number = Math.round((t.framesSegment * 3600) + + (90000 * t.secondsSegment) + + (5400000 * t.minutesSegment) + + (324000000 * t.hoursSegment)); + return ticksPcrTb * 300; + } + + /** + * Converts to Ticks 27Mhz. + * + * @param timeCode The timecode to convert from. + * @returns The number of 27Mhz ticks. + */ + private static function smpte12M_29_27_NonDropToTicks27Mhz(timeCode:String):Number + { + var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_2997_DROP); + var ticksPcrTb:Number = Math.round((t.framesSegment * 3003) + + (90090 * t.secondsSegment) + + (5405400 * t.minutesSegment) + + (324324000 * t.hoursSegment)); + return ticksPcrTb * 300; + } + + /** + * Converts to Ticks 27Mhz. + * + * @param timeCode The timecode to convert from. + * @returns The number of 27Mhz ticks. + */ + private static function smpte12M_29_27_DropToTicks27Mhz(timeCode:String):Number + { + var t:TimeCode = new TimeCode(timeCode, SmpteFrameRate.SMPTE_2997_NONDROP); + var ticksPcrTb:Number = Math.round((t.framesSegment * 3003) + + (90090 * t.secondsSegment) + + (5399394 * t.minutesSegment) + + (6006 * int(t.minutesSegment / 10)) + + (323999676 * t.hoursSegment)); + return ticksPcrTb * 300; + } + + /** + * Converts to SMPTE 12M 29.27fps Non Drop. + * + * @param ticks27Mhz The number of 27Mhz ticks to convert from. + * @returns A string that contains the correct format. + */ + private static function ticks27MhzToSmpte12M_29_27_NonDrop(ticks27Mhz:Number):String + { + var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); + var framecount:int = int(pcrTb / 3003); + var hours:int = int(framecount / 108000); + var minutes:int = int((framecount - (108000 * hours)) / 1800); + var seconds:int = int((framecount - (1800 * minutes) - (108000 * hours)) / 30); + var frames:int = framecount - (30 * seconds) - (1800 * minutes) - (108000 * hours); + + var days:int = hours / 24; + hours = hours % 24; + + return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); + } + + /** + * Converts to SMPTE 12M 29.27fps Non Drop. + * + * @param ticks27Mhz The number of 27Mhz ticks to convert from. + * @returns A string that contains the correct format. + */ + private static function ticks27MhzToSmpte12M_29_27_Drop(ticks27Mhz:Number):String + { + var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); + var framecount:int = int(pcrTb / 3003); + var hours:int = int(framecount / 107892); + var minutes:int = int((framecount + (2 * int((framecount - (107892 * hours)) / 1800)) - (2 * int((framecount - (107892 * hours)) / 18000)) - (107892 * hours)) / 1800); + var seconds:int = int((framecount - (1798 * minutes) - (2 * int(minutes / 10)) - (107892 * hours)) / 30); + var frames:int = framecount - (30 * seconds) - (1798 * minutes) - (2 * int(minutes / 10)) - (107892 * hours); + + var days:int = hours / 24; + hours = hours % 24; + + return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, true); + } + + /** + * Converts to SMPTE 12M 23.98fps. + * + * @param ticks27Mhz The number of 27Mhz ticks to convert from. + * @returns A string that contains the correct format. + */ + private static function ticks27MhzToSmpte12M_23_98fps(ticks27Mhz:Number):String + { + var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); + var framecount:int = int(pcrTb / 3753.75); + var days:int = int((framecount / 86400) / 24); + var hours:int = int((framecount / 86400) % 24); + var minutes:int = int((framecount - (86400 * hours)) / 1440) % 60; + var seconds:int = int((framecount - (1440 * minutes) - (86400 * hours)) / 24) % 60; + var frames:int = (framecount - (24 * seconds) - (1440 * minutes) - (86400 * hours)) % 24; + + return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); + } + + /** + * Converts to SMPTE 12M 24fps. + * + * @param ticks27Mhz The number of 27Mhz ticks to convert from. + * @returns A string that contains the correct format. + */ + private static function ticks27MhzToSmpte12M_24fps(ticks27Mhz:Number):String + { + var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); + var framecount:int =int(pcrTb / 3750); + var days:int = int((framecount / 86400) / 24); + var hours:int = int((framecount / 86400) % 24); + var minutes:int = int((framecount - (86400 * hours)) / 1440) % 60; + var seconds:int = int((framecount - (1440 * minutes) - (86400 * hours)) / 24) % 60; + var frames:int = (framecount - (24 * seconds) - (1440 * minutes) - (86400 * hours)) % 24; + + return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); + } + + /** + * Converts to SMPTE 12M 25fps. + * + * @param ticks27Mhz The number of 27Mhz ticks to convert from. + * @returns A string that contains the correct format. + */ + private static function ticks27MhzToSmpte12M_25fps(ticks27Mhz:Number):String + { + var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); + var framecount:int =int(pcrTb / 3600); + var days:int = int((framecount / 90000) / 24); + var hours:int = int((framecount / 90000) % 24); + var minutes:int = int((framecount - (90000 * hours)) / 1500) % 60; + var seconds:int = int((framecount - (1500 * minutes) - (90000 * hours)) / 25) % 60; + var frames:int = (framecount - (25 * seconds) - (1500 * minutes) - (90000 * hours)) % 25; + + return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); + } + + /** + * Converts to SMPTE 12M 30fps. + * + * @param ticks27Mhz The number of 27Mhz ticks to convert from. + * @returns A string that contains the correct format. + */ + private static function ticks27MhzToSmpte12M_30fps(ticks27Mhz:Number):String + { + var pcrTb:Number = TimeCode.ticks27MhzToPcrTb(ticks27Mhz); + var framecount:int =int(pcrTb / 3000); + var days:int = int((framecount / 108000) / 24); + var hours:int = int((framecount / 108000) % 24); + var minutes:int = int((framecount - (108000 * hours)) / 1800) % 60; + var seconds:int = int((framecount - (1800 * minutes) - (108000 * hours)) / 30) % 60; + var frames:int = (framecount - (30 * seconds) - (1800 * minutes) - (108000 * hours)) % 30; + + return TimeCode.formatTimeCodeString(days, hours, minutes, seconds, frames, false); + } + } +} diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeCodeComponents.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeCodeComponents.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeContainer.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeContainer.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeExpression.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeExpression.as old mode 100755 new mode 100644 index 21ed709..7d77fec --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeExpression.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeExpression.as @@ -1,265 +1,266 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.timing -{ - import org.osmf.smpte.tt.errors.SMPTETTException; - import org.osmf.smpte.tt.utilities.StringUtils; - - public class TimeExpression - { - - /** - * clock-time - * : hours ":" minutes ":" seconds ( fraction | ":" frames ( "." sub-frames )? )? - */ - public static const clockTimeRegex:RegExp = /^(?P\d+):(?P[0-5]\d):(?P[0-5]\d)((?P\.\d+)|:(?P\d\d+(?P\.\d+)?))?$/; - - /** - * offset-time - * : time-count fraction? metric - */ - public static const offsetTimeRegex:RegExp = /^(?P\d+(\.\d+)?)(?Pms|[hmsft])$/; - - /** - * Global clock mode for the current parse session. - */ - public static var CurrentClockMode:ClockMode; - - /** - * Global time base for the current parse session. - */ - public static var CurrentTimeBase:TimeBase; - - /** - * Global smpte mode for the current parse session. - */ - public static var CurrentSmpteMode:SmpteMode; - - /** - * Global framerate for the current parse session - */ - public static var CurrentFrameRate:Number; - - /** - * Global sub frame rate for the current parse session - */ - public static var CurrentSubFrameRate:Number; - - /** - * Global frame rate nominator for the current parse session - */ - public static var CurrentFrameRateNominator:Number; - - /** - * Global frame rate denominator for the current parse session - */ - public static var CurrentFrameRateDenominator:Number; - - - /** - * Global tick rate for the current parse session - */ - public static var CurrentTickRate:uint; - - - /** - * Global Smpte timecode to use for the current parse session - */ - public static function get CurrentSmpteFrameRate():SmpteFrameRate - { - if (TimeExpression.CurrentFrameRateDenominator == 0) TimeExpression.CurrentFrameRateDenominator = 1; - var framerate:Number = TimeExpression.CurrentFrameRate * (TimeExpression.CurrentFrameRateNominator / TimeExpression.CurrentFrameRateDenominator); - TimeCode.parseFramerate(framerate); - var s:SmpteFrameRate = SmpteFrameRate.UNKNOWN; - switch (TimeExpression.CurrentTimeBase) - { - case TimeBase.SMPTE: - switch (TimeExpression.CurrentSmpteMode) - { - case SmpteMode.DROP_NTSC: - case SmpteMode.DROP_PAL: - s = SmpteFrameRate.SMPTE_2997_DROP; - case SmpteMode.NON_DROP: - s = TimeCode.parseFramerate(framerate); - } - break; - case TimeBase.MEDIA: - s = SmpteFrameRate.SMPTE_30; - case TimeBase.CLOCK: - s = SmpteFrameRate.UNKNOWN; - } - return s; - } - - /** - * Initialize global parameters for the next parse session - */ - public static function initializeParameters():void - { - TimeExpression.CurrentTimeBase = TimeBase.MEDIA; - TimeExpression.CurrentTickRate = 1; - TimeExpression.CurrentSubFrameRate = 1; - TimeExpression.CurrentSmpteMode = SmpteMode.NON_DROP; - TimeExpression.CurrentFrameRate = 30; - TimeExpression.CurrentFrameRateDenominator = 1; - TimeExpression.CurrentFrameRateNominator = 1; - TimeExpression.CurrentClockMode = ClockMode.LOCAL; - } - - /// - /// Convert a timed text time expression into a TimeCode. - /// Where the current global framerate and tickrate apply - /// - /// Time expression - /// TimeSpan duration equal to time expression (ignored) - public static function parse(p_timeExpression:String):TimeCode - { - var hours:uint = 0, - minutes:uint = 0, - seconds:uint = 0, - frames:uint = 0, - // subframes = 0, - subseconds:Number = 0, - m:Array; - - var input:String = StringUtils.trim( p_timeExpression ); - var framerate:Number = TimeExpression.CurrentFrameRate * (TimeExpression.CurrentFrameRateNominator / TimeExpression.CurrentFrameRateDenominator); - - var validTimeExpression:Boolean = (TimeExpression.clockTimeRegex.test(input) || TimeExpression.offsetTimeRegex.test(input)); - if (!validTimeExpression) - { - throw new SMPTETTException("Invalid time expression " + p_timeExpression); - } - - if (input.indexOf(":")!=-1) - { - // its a clock-time - m = input.match(TimeExpression.clockTimeRegex); - - hours = parseInt(m["hrs"]); - minutes = parseInt(m["mins"]); - seconds = parseInt(m["secs"]); - if(m["subsecs"] && m["subsecs"].length>0) - { - subseconds = parseFloat("0" + m["subsecs"]); - frames = Math.floor(framerate * subseconds); - } - if(m["frames"] && m["frames"].length>0) - { - frames = Math.floor(parseFloat(m["frames"])); - } - if (TimeExpression.CurrentSmpteFrameRate != SmpteFrameRate.UNKNOWN) - { - return new TimeCode(hours, minutes, seconds, frames, CurrentSmpteFrameRate); - } - else - { - return new TimeCode(hours, minutes, seconds, frames, framerate); - } - } - else - { - // its a clock-time - m = input.match(TimeExpression.offsetTimeRegex); - - // work out hours etc.. - var multiplier:Number = TimeExpression.getMetricMultiplier(m["units"], framerate, TimeExpression.CurrentTickRate) * 10000; - var value:Number = parseFloat(m["value"]); - - // A tick is 100 nanosec (10^-7) of a second. - // A millisecond is 1000 of a sec (10^-3) - // A millisecond is 10000 ticks. - var ms:Number = Math.floor(value * multiplier); - //ms += (long)Math.Floor(subdigits * multiplier); - //var newtime = new TimeSpan(ms); - var newtime:TimeCode = new TimeCode(new TimeSpan(ms), framerate); - return newtime; - } - } - - /** - * Returns the number needed to convert a time expression to milliseconds - * if the time expression is defined in times of a time metric - * - * @param p_timeexpression - * @param p_framerate - * @param p_tickrate - */ - public static function getMetricMultiplier(p_timeexpression:String, p_framerate:Number, p_tickrate:Number):Number - { - if (p_timeexpression.indexOf("h")!=-1) - return 1000 * 60 * 60; - if (p_timeexpression.indexOf("ms")!=-1) - return 1; - if (p_timeexpression.indexOf("m")!=-1) - return 1000 * 60; - if (p_timeexpression.indexOf("s")!=-1) - return 1000; - if (p_timeexpression.indexOf("f")!=-1) - return 1000 / p_framerate; - if (p_timeexpression.indexOf("t")!=-1) - return 1000 / p_tickrate; - return 0; - } - - /** - * Test the time parser. Not comprehensive at this point - */ - public static function UnitTests():Boolean - { - // reference is a 60 second timespan. - // parse applies a default tickrate and framerate of 30 unless - // otherwise specified. - TimeExpression.initializeParameters(); - trace("reference: "); - var reference:TimeCode = new TimeCode(new TimeSpan(0, 1, 00), TimeExpression.CurrentFrameRate); - var pass:int = 1; - - trace('TimeExpression.parse("60s"): '); - pass &= TimeExpression.parse("60s").equalTo(reference) as int; - trace('TimeExpression.parse("1m"): '); - pass &= TimeExpression.parse("1m").equalTo(reference) as int; - trace('TimeExpression.parse("60000ms"): '); - pass &= TimeExpression.parse("60000ms").equalTo(reference) as int; - trace('TimeExpression.parse("1800f"): '); - pass &= TimeExpression.parse("1800f").equalTo(reference) as int; - TimeExpression.CurrentFrameRate = 10; - trace('TimeExpression.parse("600f") @ 10fps: '); - pass &= TimeExpression.parse("600f").equalTo(reference) as int; - TimeExpression.CurrentFrameRate = 30; - trace('TimeExpression.parse("00:01:00"): '); - pass &= TimeExpression.parse("00:01:00").equalTo(reference) as int; - trace('TimeExpression.parse("00:01:00:00"): '); - pass &= TimeExpression.parse("00:01:00:00").equalTo(reference) as int; - TimeExpression.CurrentFrameRate = 25; - trace('TimeExpression.parse("00:00:59:25") @25fps: '); - pass &= TimeExpression.parse("00:00:59:25").equalTo(reference) as int; - - TimeExpression.CurrentFrameRate = 30; - reference = new TimeCode(new TimeSpan(1, 0, 0), TimeExpression.CurrentFrameRate); - pass &= TimeExpression.parse("3600s").equalTo(reference) as int; - pass &= TimeExpression.parse("01:00:00").equalTo(reference) as int; - pass &= TimeExpression.parse("00:59:60:00").equalTo(reference) as int; - TimeExpression.CurrentFrameRate = 25; - pass &= TimeExpression.parse("00:59:59:25").equalTo(reference) as int; - return Boolean((pass & 1) == 0); - } - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.timing +{ + import org.osmf.smpte.tt.errors.SMPTETTException; + import org.osmf.smpte.tt.utilities.StringUtils; + + public class TimeExpression + { + + /** + * clock-time + * : hours ":" minutes ":" seconds ( fraction | ":" frames ( "." sub-frames )? )? + */ + public static const clockTimeRegex:RegExp = /^(?P\d+):(?P[0-5]\d):(?P[0-5]\d)((?P\.\d+)|:(?P\d\d+(?P\.\d+)?))?$/; + + /** + * offset-time + * : time-count fraction? metric + */ + public static const offsetTimeRegex:RegExp = /^(?P\d+(\.\d+)?)(?Pms|[hmsft])$/; + + /** + * Global clock mode for the current parse session. + */ + public static var CurrentClockMode:ClockMode; + + /** + * Global time base for the current parse session. + */ + public static var CurrentTimeBase:TimeBase; + + /** + * Global smpte mode for the current parse session. + */ + public static var CurrentSmpteMode:SmpteMode; + + /** + * Global framerate for the current parse session + */ + public static var CurrentFrameRate:Number; + + /** + * Global sub frame rate for the current parse session + */ + public static var CurrentSubFrameRate:Number; + + /** + * Global frame rate nominator for the current parse session + */ + public static var CurrentFrameRateNominator:Number; + + /** + * Global frame rate denominator for the current parse session + */ + public static var CurrentFrameRateDenominator:Number; + + + /** + * Global tick rate for the current parse session + */ + public static var CurrentTickRate:uint; + + + /** + * Global Smpte timecode to use for the current parse session + */ + public static function get CurrentSmpteFrameRate():SmpteFrameRate + { + if (TimeExpression.CurrentFrameRateDenominator == 0) TimeExpression.CurrentFrameRateDenominator = 1; + var framerate:Number = TimeExpression.CurrentFrameRate * (TimeExpression.CurrentFrameRateNominator / TimeExpression.CurrentFrameRateDenominator); + var s:SmpteFrameRate = SmpteFrameRate.UNKNOWN; + switch (TimeExpression.CurrentTimeBase) + { + case TimeBase.SMPTE: + switch (TimeExpression.CurrentSmpteMode) + { + case SmpteMode.DROP_NTSC: + case SmpteMode.DROP_PAL: + s = SmpteFrameRate.SMPTE_2997_DROP; + case SmpteMode.NON_DROP: + s = TimeCode.parseFramerate(framerate); + } + break; + case TimeBase.MEDIA: + s = SmpteFrameRate.SMPTE_30; + break; + case TimeBase.CLOCK: + s = SmpteFrameRate.UNKNOWN; + break; + } + return s; + } + + /** + * Initialize global parameters for the next parse session + */ + public static function initializeParameters():void + { + TimeExpression.CurrentTimeBase = TimeBase.MEDIA; + TimeExpression.CurrentTickRate = 1; + TimeExpression.CurrentSubFrameRate = 1; + TimeExpression.CurrentSmpteMode = SmpteMode.NON_DROP; + TimeExpression.CurrentFrameRate = 30; + TimeExpression.CurrentFrameRateDenominator = 1; + TimeExpression.CurrentFrameRateNominator = 1; + TimeExpression.CurrentClockMode = ClockMode.LOCAL; + } + + /// + /// Convert a timed text time expression into a TimeCode. + /// Where the current global framerate and tickrate apply + /// + /// Time expression + /// TimeSpan duration equal to time expression (ignored) + public static function parse(p_timeExpression:String):TimeCode + { + var hours:uint = 0, + minutes:uint = 0, + seconds:uint = 0, + frames:uint = 0, + // subframes = 0, + subseconds:Number = 0, + m:Array; + + var input:String = StringUtils.trim( p_timeExpression ); + var framerate:Number = TimeExpression.CurrentFrameRate * (TimeExpression.CurrentFrameRateNominator / TimeExpression.CurrentFrameRateDenominator); + + var validTimeExpression:Boolean = (TimeExpression.clockTimeRegex.test(input) || TimeExpression.offsetTimeRegex.test(input)); + if (!validTimeExpression) + { + throw new SMPTETTException("Invalid time expression " + p_timeExpression); + } + + if (input.indexOf(":")!=-1) + { + // its a clock-time + m = input.match(TimeExpression.clockTimeRegex); + + hours = parseInt(m["hrs"]); + minutes = parseInt(m["mins"]); + seconds = parseInt(m["secs"]); + if(m["subsecs"] && m["subsecs"].length>0) + { + subseconds = parseFloat("0" + m["subsecs"]); + frames = Math.floor(framerate * subseconds); + } + if(m["frames"] && m["frames"].length>0) + { + frames = Math.floor(parseFloat(m["frames"])); + } + if (TimeExpression.CurrentSmpteFrameRate != SmpteFrameRate.UNKNOWN) + { + return new TimeCode(hours, minutes, seconds, frames, CurrentSmpteFrameRate); + } + else + { + return new TimeCode(hours, minutes, seconds, frames, framerate); + } + } + else + { + // its a clock-time + m = input.match(TimeExpression.offsetTimeRegex); + + // work out hours etc.. + var multiplier:Number = TimeExpression.getMetricMultiplier(m["units"], framerate, TimeExpression.CurrentTickRate) * 10000; + var value:Number = parseFloat(m["value"]); + + // A tick is 100 nanosec (10^-7) of a second. + // A millisecond is 1000 of a sec (10^-3) + // A millisecond is 10000 ticks. + var ms:Number = Math.floor(value * multiplier); + //ms += (long)Math.Floor(subdigits * multiplier); + //var newtime = new TimeSpan(ms); + var newtime:TimeCode = new TimeCode(new TimeSpan(ms), framerate); + return newtime; + } + } + + /** + * Returns the number needed to convert a time expression to milliseconds + * if the time expression is defined in times of a time metric + * + * @param p_timeexpression + * @param p_framerate + * @param p_tickrate + */ + public static function getMetricMultiplier(p_timeexpression:String, p_framerate:Number, p_tickrate:Number):Number + { + if (p_timeexpression.indexOf("h")!=-1) + return 1000 * 60 * 60; + if (p_timeexpression.indexOf("ms")!=-1) + return 1; + if (p_timeexpression.indexOf("m")!=-1) + return 1000 * 60; + if (p_timeexpression.indexOf("s")!=-1) + return 1000; + if (p_timeexpression.indexOf("f")!=-1) + return 1000 / p_framerate; + if (p_timeexpression.indexOf("t")!=-1) + return 1000 / p_tickrate; + return 0; + } + + /** + * Test the time parser. Not comprehensive at this point + */ + public static function UnitTests():Boolean + { + // reference is a 60 second timespan. + // parse applies a default tickrate and framerate of 30 unless + // otherwise specified. + TimeExpression.initializeParameters(); + trace("reference: "); + var reference:TimeCode = new TimeCode(new TimeSpan(0, 1, 00), TimeExpression.CurrentFrameRate); + var pass:int = 1; + + trace('TimeExpression.parse("60s"): '); + pass &= TimeExpression.parse("60s").equalTo(reference) as int; + trace('TimeExpression.parse("1m"): '); + pass &= TimeExpression.parse("1m").equalTo(reference) as int; + trace('TimeExpression.parse("60000ms"): '); + pass &= TimeExpression.parse("60000ms").equalTo(reference) as int; + trace('TimeExpression.parse("1800f"): '); + pass &= TimeExpression.parse("1800f").equalTo(reference) as int; + TimeExpression.CurrentFrameRate = 10; + trace('TimeExpression.parse("600f") @ 10fps: '); + pass &= TimeExpression.parse("600f").equalTo(reference) as int; + TimeExpression.CurrentFrameRate = 30; + trace('TimeExpression.parse("00:01:00"): '); + pass &= TimeExpression.parse("00:01:00").equalTo(reference) as int; + trace('TimeExpression.parse("00:01:00:00"): '); + pass &= TimeExpression.parse("00:01:00:00").equalTo(reference) as int; + TimeExpression.CurrentFrameRate = 25; + trace('TimeExpression.parse("00:00:59:25") @25fps: '); + pass &= TimeExpression.parse("00:00:59:25").equalTo(reference) as int; + + TimeExpression.CurrentFrameRate = 30; + reference = new TimeCode(new TimeSpan(1, 0, 0), TimeExpression.CurrentFrameRate); + pass &= TimeExpression.parse("3600s").equalTo(reference) as int; + pass &= TimeExpression.parse("01:00:00").equalTo(reference) as int; + pass &= TimeExpression.parse("00:59:60:00").equalTo(reference) as int; + TimeExpression.CurrentFrameRate = 25; + pass &= TimeExpression.parse("00:59:59:25").equalTo(reference) as int; + return Boolean((pass & 1) == 0); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeSpan.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeSpan.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeTree.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeTree.as old mode 100755 new mode 100644 index 85e40f1..2a93a07 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeTree.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TimeTree.as @@ -19,13 +19,7 @@ **********************************************************/ package org.osmf.smpte.tt.timing { - import flash.utils.Dictionary; - - import mx.collections.ArrayList; - import org.osmf.smpte.tt.model.TimedTextAttributeBase; - import org.osmf.smpte.tt.model.TimedTextElementBase; - import org.osmf.smpte.tt.utilities.DictionaryUtils; public class TimeTree extends TreeType { diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TreeType.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TreeType.as old mode 100755 new mode 100644 index 31d1b74..14a0ccd --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TreeType.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/timing/TreeType.as @@ -1,323 +1,321 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.timing -{ - import flash.utils.Dictionary; - - import org.osmf.smpte.tt.logging.SMPTETTLogging; - import org.osmf.smpte.tt.model.TimedTextAttributeBase; - import org.osmf.smpte.tt.timing.TimeCode; - import org.osmf.smpte.tt.timing.TimeContainer; - import org.osmf.smpte.tt.utilities.DictionaryUtils; - - public class TreeType - { - //{ region Constructor - public function TreeType(p_attributes:Vector.=null, p_children:Vector.=null) - { - if(!p_attributes || !p_children){ - _children = new Vector.(); - _attributes = new Vector.(); - } else { - _children = p_children; - _attributes = p_attributes; - } - - } - //} endregion - - //{ region Variables and Properties - private var _timing:Dictionary = new Dictionary(); - /** - * The begin, end and dur times for this node - */ - public function get timing():Dictionary - { - return _timing; - } - - private var _timeSemantics:TimeContainer = TimeContainer.PAR; - /** - * Specifies whether children are sequential or parallel in time. - * unless an element overrides, the default is par. - */ - public function get timeSemantics():TimeContainer - { - return _timeSemantics; - } - public function set timeSemantics(value:TimeContainer):void - { - _timeSemantics = value; - } - - private var _startTime:TimeCode; - private var _endTime:TimeCode; - - /** - * Get the time at which this element becomes active - */ - public function get begin():TimeCode - { - return _startTime; - } - - /** - * Get the time at which this element is no longer active - */ - public function get end():TimeCode - { - return _endTime; - } - - /** - * Get the time at which this element is no longer active - */ - public function get duration():TimeCode - { - return _endTime.minus(_startTime); - } - //} endregion - - //{ region time container semantics - /** - * Test if the tree is active at the given time - * - * @param time time of test - * @returns true if active - */ - public function temporallyActive(time:TimeCode):Boolean - { - return (begin.lessThanOrEqualTo(time) && time.lessThan(end)); - } - - /** - * Apply function to all elements in the tree and return a flattened list - * - * @param function - * @returns - */ - private function reduce(p_func:Function):Vector. - { - var result:Vector. = new Vector.(); - result = result.concat( p_func(this as TreeType) ); - for each (var c:TreeType in children) - { - result = result.concat( c.reduce(p_func) ); - } - return result; - } - - /** - * return an ordered list of the significant time events - * in the time tree. - */ - public function get events():Vector. - { - var reduceQuery:Function = function(tree:TreeType):Vector. - { - var t:Vector. = new Vector.(); - t.push(tree.begin); - t.push(tree.end); - return t; - } - - var reduction:Vector. = distinctTimeCodeVector( this.reduce(reduceQuery).sort(TimeCode.Compare) ); - return reduction; - } - - private function distinctTimeCodeVector(pv:Vector.):Vector. - { - var dict:Dictionary = new Dictionary(); - var i:uint = 0, tc:TimeCode; - var unique:Vector. = new Vector.(); - for each(tc in pv) - { - if(!dict[tc.totalFrames]) - { - dict[tc.totalFrames] = true; - unique[unique.length] = tc; - } - } - return unique; - } - - /** - * Walk the tree to determine the absolute start and end times of all the elements. - * the reference times passed in are absolute times, the result of calling this is to set the local start time - * and end time to absolute times between these two reference times, based on the begin, end and dur attributes - * and to recursively set all of the children. - */ - public function computeTimeIntervals(context:TimeContainer, referenceStart:TimeCode, referenceEnd:TimeCode):void - { - var referenceDur:TimeCode, - locBegin:TimeCode, - locDur:TimeCode, - locEnd:TimeCode; - - _startTime = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); - _endTime = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); - - // compute the beginning of my interval. - locBegin = (DictionaryUtils.containsKey(timing,"begin")) ? (timing["begin"] as TimeCode) : new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); - _startTime = referenceStart.plus(locBegin); - - // compute the simple duration of the interval, - // par children have indefinite default duration, seq children have zero default duration. - // (we dont support indefinite here but truncate to the outer container) - // does end work here? surely it truncates the active duration, - if (!DictionaryUtils.containsKey(timing,"dur") - && !DictionaryUtils.containsKey(timing,"end") - && context == TimeContainer.SEQ) - { - referenceDur = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); - } - else - { - if (_startTime.lessThan(referenceEnd)) - { - referenceDur = referenceEnd.minus(_startTime); - } - else - { - referenceDur = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); - } - } - - var containsDur:Boolean = false; - if (DictionaryUtils.containsKey(timing,"dur")) - { - containsDur = true; - locDur = timing["dur"] as TimeCode; - if (locDur.greaterThan(referenceDur)) - { - locDur = referenceDur; - } - } - else - { - locDur = referenceDur; - } - _endTime = _startTime.plus(locDur); - - // end can truncate the simple duration. - var offsetEnd:TimeCode = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); - offsetEnd = offsetEnd.plus(referenceStart); - - if (DictionaryUtils.containsKey(timing,"end")) - { - locEnd = referenceStart.plus(timing["end"] as TimeCode); - } - else - { - // Original code: - // - // end = referenceEnd; - // - // NOTE: This logic was changed from original TimedText library to properly handle - // Sequential time containers when the duration is indefinite. - if (context == TimeContainer.PAR) - { - locEnd = referenceEnd; - } - else - { - locEnd = _startTime.plus(referenceDur); - } - } - //end = (Timing.ContainsKey("end")) ? (m_startTime.Add((TimeSpan)Timing["end"])) : referenceEnd; - if (!containsDur) - { - _endTime = locEnd; - } - else - { - _endTime = (locEnd.lessThan(_endTime)) ? locEnd : _endTime; - } - - // trace("\t"+this+((this.hasOwnProperty("text")&&this["text"]!=null)?" \""+this["text"]+"\"":"")+"\n\t.computeTimeIntervals()={begin:"+begin+",duration:"+duration+",end:"+end+"}"); - - var child:TreeType; - var i:uint = 0; - if (timeSemantics == TimeContainer.PAR) - { - for (i = 0; i; - private var _attributes:Vector.; - private var _parent:TreeType; - - /** - * tree node which is the unique parent of this node - */ - public function get parent():TreeType - { - return _parent; - - } - public function set parent(value:TreeType):void - { - _parent = value; - } - - /** - * List of time trees that are contained within this node - */ - public function get children():Vector. - { - return _children; - } - - /** - * List of attributes associated with this node - */ - public function get attributes():Vector. - { - return _attributes; - } - //} endregion - - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.timing +{ + import flash.utils.Dictionary; + + import org.osmf.smpte.tt.model.TimedTextAttributeBase; + + public class TreeType + { + //{ region Constructor + public function TreeType(p_attributes:Vector.=null, p_children:Vector.=null) + { + if(!p_attributes || !p_children){ + _children = new Vector.(); + _attributes = new Vector.(); + } else { + _children = p_children; + _attributes = p_attributes; + } + + } + //} endregion + + //{ region Variables and Properties + private var _timing:Dictionary = new Dictionary(); + /** + * The begin, end and dur times for this node + */ + public function get timing():Dictionary + { + return _timing; + } + + private var _timeSemantics:TimeContainer = TimeContainer.PAR; + /** + * Specifies whether children are sequential or parallel in time. + * unless an element overrides, the default is par. + */ + public function get timeSemantics():TimeContainer + { + return _timeSemantics; + } + public function set timeSemantics(value:TimeContainer):void + { + _timeSemantics = value; + } + + private var _startTime:TimeCode; + private var _endTime:TimeCode; + + /** + * Get the time at which this element becomes active + */ + public function get begin():TimeCode + { + return _startTime; + } + + /** + * Get the time at which this element is no longer active + */ + public function get end():TimeCode + { + return _endTime; + } + + /** + * Get the time at which this element is no longer active + */ + public function get duration():TimeCode + { + return _endTime.minus(_startTime); + } + //} endregion + + //{ region time container semantics + /** + * Test if the tree is active at the given time + * + * @param time time of test + * @returns true if active + */ + public function temporallyActive(time:TimeCode):Boolean + { + return (begin.lessThanOrEqualTo(time) && time.lessThan(end)); + } + + /** + * Apply function to all elements in the tree and return a flattened list + * + * @param function + * @returns + */ + private function reduce(p_func:Function):Vector. + { + var result:Vector. = new Vector.(); + result = result.concat( p_func(this as TreeType) ); + for each (var c:TreeType in children) + { + result = result.concat( c.reduce(p_func) ); + } + return result; + } + + private var _events:Vector.; + /** + * return an ordered list of the significant time events + * in the time tree. + */ + public function get events():Vector. + { + if (!_events) + { + var reduceQuery:Function = function(tree:TreeType):Vector. + { + var t:Vector. = new Vector.(); + t.push(tree.begin); + t.push(tree.end); + return t; + } + _events = distinctTimeCodeVector( this.reduce(reduceQuery) ); + } + return _events; + } + + private function distinctTimeCodeVector(pv:Vector.):Vector. + { + var dict:Dictionary = new Dictionary(); + var i:uint = 0, tc:TimeCode; + var unique:Vector. = new Vector.(); + for each(tc in pv) + { + if(!dict[tc.totalFrames]) + { + dict[tc.totalFrames] = true; + unique[unique.length] = tc; + } + } + return unique.sort(TimeCode.Compare); + } + + /** + * Walk the tree to determine the absolute start and end times of all the elements. + * the reference times passed in are absolute times, the result of calling this is to set the local start time + * and end time to absolute times between these two reference times, based on the begin, end and dur attributes + * and to recursively set all of the children. + */ + public function computeTimeIntervals(context:TimeContainer, referenceStart:TimeCode, referenceEnd:TimeCode):void + { + var referenceDur:TimeCode, + locBegin:TimeCode, + locDur:TimeCode, + locEnd:TimeCode; + + _startTime = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); + _endTime = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); + + // compute the beginning of my interval. + locBegin = (timing["begin"]) ? TimeCode(timing["begin"]) : new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); + _startTime = referenceStart.plus(locBegin); + + // compute the simple duration of the interval, + // par children have indefinite default duration, seq children have zero default duration. + // (we dont support indefinite here but truncate to the outer container) + // does end work here? surely it truncates the active duration, + if (!timing["dur"] && !timing["end"] && context == TimeContainer.SEQ) + { + referenceDur = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); + } + else + { + if (_startTime.lessThan(referenceEnd)) + { + referenceDur = referenceEnd.minus(_startTime); + } + else + { + referenceDur = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); + } + } + + var containsDur:Boolean = false; + if (timing["dur"]) + { + containsDur = true; + locDur = TimeCode(timing["dur"]); + if (locDur.greaterThan(referenceDur)) + { + locDur = referenceDur; + } + } + else + { + locDur = referenceDur; + } + _endTime = _startTime.plus(locDur); + + // end can truncate the simple duration. + var offsetEnd:TimeCode = new TimeCode(0, TimeExpression.CurrentSmpteFrameRate); + offsetEnd = offsetEnd.plus(referenceStart); + + if (timing["end"]) + { + locEnd = referenceStart.plus(TimeCode(timing["end"])); + } + else + { + // Original code: + // + // end = referenceEnd; + // + // NOTE: This logic was changed from original TimedText library to properly handle + // Sequential time containers when the duration is indefinite. + if (context == TimeContainer.PAR) + { + locEnd = referenceEnd; + } + else + { + locEnd = _startTime.plus(referenceDur); + } + } + //end = (Timing.ContainsKey("end")) ? (m_startTime.Add((TimeSpan)Timing["end"])) : referenceEnd; + if (!containsDur) + { + _endTime = locEnd; + } + else + { + _endTime = (locEnd.lessThan(_endTime)) ? locEnd : _endTime; + } + + // trace("\t"+this+((this.hasOwnProperty("text")&&this["text"]!=null)?" \""+this["text"]+"\"":"")+"\n\t.computeTimeIntervals()={begin:"+begin+",duration:"+duration+",end:"+end+"}"); + + var child:TreeType; + var i:uint = 0; + var len:uint = children.length; + if (timeSemantics == TimeContainer.PAR) + { + for (i = 0; i; + private var _attributes:Vector.; + private var _parent:TreeType; + + /** + * tree node which is the unique parent of this node + */ + public function get parent():TreeType + { + return _parent; + + } + public function set parent(value:TreeType):void + { + _parent = value; + } + + /** + * List of time trees that are contained within this node + */ + public function get children():Vector. + { + return _children; + } + + /** + * List of attributes associated with this node + */ + public function get attributes():Vector. + { + return _attributes; + } + //} endregion + + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/AsyncThread.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/AsyncThread.as old mode 100755 new mode 100644 index 85d4914..1b95ffb --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/AsyncThread.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/AsyncThread.as @@ -1,184 +1,238 @@ -/*********************************************************** - * - * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. - * - * ********************************************************* - * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence - * (the "License"); you may not use this file except in - * compliance with the License. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems - * Incorporated. All Rights Reserved. - **********************************************************/ -package org.osmf.smpte.tt.utilities -{ - import flash.display.Shape; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.IEventDispatcher; - import flash.utils.getTimer; - - /** - * @eventType flash.events.Event.COMPLETE - */ - [Event(name="complete", type="flash.events.Event")] - - public class AsyncThread extends EventDispatcher - { - private var _shape:Shape; - public function get shape():Shape - { - if(!_shape) _shape = new Shape(); - return _shape; - } - - private var _isComplete:Boolean = true; - [Bindable("complete")] - public function get isComplete():Boolean - { - return _isComplete; - } - - private var _stack:Array = [[]]; - - private function get currentQueue():Array - { - if ( _stack.length == 0 ) - return null; - - return _stack[ _stack.length - 1 ] as Array; - } - - public function AsyncThread() - { - } - - private function queue( func:Function, args:Array = null ):void - { - currentQueue.push( [ func, args ] ); - _isComplete = false; - } - - public function step():void - { - if ( _isComplete ) return; - - while ( currentQueue.length == 0 ) - { - _stack.pop(); - if ( currentQueue == null ) - { - _isComplete = true; - dispatchEvent( new Event( Event.COMPLETE ) ); - shape.removeEventListener( Event.ENTER_FRAME, shape_enterFrame ); - return; - } - } - - var entry:Array = currentQueue.shift() as Array; - // append to the stack so any calls made when executing this entry are stored in their own queue - _stack.push( [] ); - - //////////////// execute ////////////////// - var func:Function = entry[ 0 ] as Function; - var args:Array = []; - - if (entry[1] && entry[1] is Array) args = ( entry[1] as Array ); - - _threadStack.push( this ); - func.apply( null, args ); - _threadStack.pop(); - } - - private var _endTime:int; - /** - * - * Will execute this thread for the amount of time specified, if no argument is passed it will run to completion - * - * @param elapsed the time, in milliseconds, that this thread is given to run. defaults to -1 ( no limit ) - * - */ - public function run( elapsed:int = -1 ):void - { - _endTime = getTimer() + elapsed; - while ( ( elapsed == -1 ) - || ( getTimer() < _endTime ) ) - { - step(); - if ( _isComplete ) break; - } - } - - /** - * - * A common use case. - * Will add an enter frame listener and try to run( elapsed ) on each frame. - * - * @param elapsed - * - */ - public function runEachFrame( elapsed:int = 100 ):void - { - _elapsedPerFrame = elapsed; - shape.addEventListener( Event.ENTER_FRAME, shape_enterFrame ); - } - - private var _elapsedPerFrame:int; - - private function shape_enterFrame( event:Event ):void - { - run( _elapsedPerFrame ); - } - - private static var _threadStack:Array = []; - /** - * - * - * Creates a thread instance, starting at the given function. - * You can then call thread.step() to execute the first step and any - * other nested steps that get queued as well. - * - * - * @param func - * @param args - * @return - * - */ - public static function create( func:Function, args:Array = null ):AsyncThread - { - var thread:AsyncThread = new AsyncThread( ); - thread.queue( func, args ); - return thread; - } - - /** - * - * Even though this function is static, it operates on the current active runner thread. - * It is only meant to be called from within functions that are designed to work with async - * threads. - * - * @param func - * @param args - * - */ - public static function queue( func:Function, args:Array = null ):void - { - if ( _threadStack.length > 0 ) - { - // append call to the current ( topmost ) runner's queue - ( _threadStack[ _threadStack.length - 1 ] as AsyncThread ).queue( func, args ); - } - else - { - throw new Error( "There is no active AsyncThread. You cannot queue a method call." ); - } - } - } +/*********************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * ********************************************************* + * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence + * (the "License"); you may not use this file except in + * compliance with the License. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + **********************************************************/ +package org.osmf.smpte.tt.utilities +{ + import flash.display.Shape; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.IEventDispatcher; + import flash.utils.getTimer; + + /** + * @eventType flash.events.Event.COMPLETE + */ + [Event(name="complete", type="flash.events.Event")] + [Event(name="started",type="flash.events.Event")] + + public class AsyncThread extends EventDispatcher + { + public static const STARTED:String = "started"; + private var _shape:Shape; + public function get shape():Shape + { + if(!_shape) _shape = new Shape(); + return _shape; + } + + private var _isComplete:Boolean = true; + private var _isStarted:Boolean = false; + + [Bindable(event="started")] + public function get isStarted():Boolean + { + return _isStarted; + } + + public function set isStarted(value:Boolean):void + { + if (_isStarted != value) + { + _isStarted = value; + dispatchEvent(new Event(STARTED)); + } + } + + + [Bindable("complete")] + public function get isComplete():Boolean + { + return _isComplete; + } + + private var _stack:Array = [[]]; + + private function get currentQueue():Array + { + if ( _stack.length == 0 ) + return null; + + return _stack[ _stack.length - 1 ] as Array; + } + + public function AsyncThread() + { + } + + private function queue( func:Function, args:Array = null ):void + { + if (!isStarted) {_threadStack.push( this );} + currentQueue.push( [ func, args ] ); + _isComplete = false; + } + + public function step():void + { + if ( _isComplete ) return; + + while ( currentQueue.length == 0 ) + { + _stack.pop(); + if ( currentQueue == null ) + { + _isComplete = true; + dispatchEvent( new Event( Event.COMPLETE ) ); + shape.removeEventListener( Event.ENTER_FRAME, shape_enterFrame ); + return; + } + } + + var entry:Array = currentQueue.shift() as Array; + // append to the stack so any calls made when executing this entry are stored in their own queue + _stack.push( [] ); + + //////////////// execute ////////////////// + var func:Function = entry[ 0 ] as Function; + var args:Array = []; + + if (entry[1] && entry[1] is Array) args = ( entry[1] as Array ); + + if (isStarted) { + _threadStack.push( this ); + } + else + { + isStarted = true; + } + func.apply( null, args ); + _threadStack.pop(); + } + + public function stop():void + { + if (!_isComplete) + { + _isComplete = true; + _stack = [[]]; + if(_shape) + { + _shape.removeEventListener( Event.ENTER_FRAME, shape_enterFrame ); + _shape = null; + } + isStarted = false; + } + } + + private var _endTime:int; + /** + * + * Will execute this thread for the amount of time specified, if no argument is passed it will run to completion + * + * @param elapsed the time, in milliseconds, that this thread is given to run. defaults to -1 ( no limit ) + * + */ + public function run( elapsed:int = -1 ):void + { + isStarted = true; + _endTime = getTimer() + elapsed; + while ( ( elapsed == -1 ) + || ( getTimer() < _endTime ) ) + { + step(); + if ( _isComplete ) break; + } + } + + /** + * + * A common use case. + * Will add an enter frame listener and try to run( elapsed ) on each frame. + * + * @param elapsed + * + */ + public function runEachFrame( elapsed:int = 100 ):void + { + _elapsedPerFrame = elapsed; + shape.addEventListener( Event.ENTER_FRAME, shape_enterFrame, false, 0, true ); + } + + private var _elapsedPerFrame:int; + + private function shape_enterFrame( event:Event ):void + { + run( _elapsedPerFrame ); + } + + private static var _threadStack:Array = []; + /** + * + * + * Creates a thread instance, starting at the given function. + * You can then call thread.step() to execute the first step and any + * other nested steps that get queued as well. + * + * + * @param func + * @param args + * @return + * + */ + public static function create( func:Function, args:Array = null ):AsyncThread + { + var thread:AsyncThread = new AsyncThread( ); + thread.queue( func, args ); + return thread; + } + + /** + * + * Even though this function is static, it operates on the current active runner thread. + * It is only meant to be called from within functions that are designed to work with async + * threads. + * + * @param func + * @param args + * + */ + public static function queue( func:Function, args:Array = null ):void + { + if ( _threadStack.length > 0) + { + // append call to the current ( topmost ) runner's queue + ( _threadStack[ _threadStack.length - 1 ] as AsyncThread ).queue( func, args ); + } + else + { + throw new Error( "There is no active AsyncThread. You cannot queue a method call." ); + } + } + + public static function stop():void + { + if ( _threadStack.length > 0) + { + for each(var thread:AsyncThread in _threadStack) + { + thread.stop(); + } + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/DictionaryUtils.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/DictionaryUtils.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/IComparable.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/IComparable.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/IEquals.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/IEquals.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/StringUtils.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/StringUtils.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/VectorUtils.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/utilities/VectorUtils.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Attributes.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Attributes.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Elements.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Elements.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Metadata.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Metadata.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Namespaces.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Namespaces.as old mode 100755 new mode 100644 index d94cf7c..7b265b8 --- a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Namespaces.as +++ b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Namespaces.as @@ -21,6 +21,11 @@ package org.osmf.smpte.tt.vocabulary { public class Namespaces { + + static public const TTML_NS_REGEXP:RegExp = /^http\:\/\/www\.w3\.org\/(?:ns\/ttml|2006\/(?:02|04|10)\/ttaf1)/; + + static public const DEFAULT_TTML_NS:Namespace = new Namespace("http://www.w3.org/ns/ttml"); // default root namespace + static public var TTML_NS:Namespace = new Namespace("http://www.w3.org/ns/ttml"); //root namespace static public var TTML_PARAMETER_NS:Namespace = new Namespace("ttp","http://www.w3.org/ns/ttml#parameter"); //ttp: static public var TTML_STYLING_NS:Namespace = new Namespace("tts","http://www.w3.org/ns/ttml#styling"); //tts: diff --git a/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Styling.as b/lib/osmf/samples/SMPTETTPlugin/src/org/osmf/smpte/tt/vocabulary/Styling.as old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPluginTest/.actionScriptProperties b/lib/osmf/samples/SMPTETTPluginTest/.actionScriptProperties old mode 100755 new mode 100644 index b93e5e0..d7feec4 --- a/lib/osmf/samples/SMPTETTPluginTest/.actionScriptProperties +++ b/lib/osmf/samples/SMPTETTPluginTest/.actionScriptProperties @@ -1,29 +1,18 @@ - + + + - - - - - - + - - - - - - - - diff --git a/lib/osmf/samples/SMPTETTPluginTest/.flexProperties b/lib/osmf/samples/SMPTETTPluginTest/.flexProperties old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPluginTest/.fxpProperties b/lib/osmf/samples/SMPTETTPluginTest/.fxpProperties old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPluginTest/BSD-License.txt b/lib/osmf/samples/SMPTETTPluginTest/BSD-License.txt old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/Elephants_Dream.en.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/Elephants_Dream.en.xml old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/SMPTETT.flv b/lib/osmf/samples/SMPTETTPluginTest/html-template/SMPTETT.flv new file mode 100644 index 0000000..cb0b1a8 Binary files /dev/null and b/lib/osmf/samples/SMPTETTPluginTest/html-template/SMPTETT.flv differ diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/SMPTETT.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/SMPTETT.xml old mode 100755 new mode 100644 diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation001.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation001.xml deleted file mode 100755 index b163e0f..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation001.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Animation Test - Animate 001 - Set backgroundColor - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #backgroundColor-block - #styling-inline - #timeContainer - - - - -
      -

      - This background of this sentence should change from red to blue at 5s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation002.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation002.xml deleted file mode 100755 index 28d92f2..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation002.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Animation Test - Animate 002 - Set color - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #color - #styling-inline - #timeContainer - - - - -
      -

      - This text of this sentence should change from white to yellow at 5s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation003.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation003.xml deleted file mode 100755 index ec3bad1..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation003.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Animation Test - Animate 003 - Set display - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #display-block - #styling-inline - #timeContainer - - - - -
      -

      - This text of this sentence should appear at 5s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation004.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation004.xml deleted file mode 100755 index 472d448..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation004.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Animation Test - Animate 004 - Set fontFamily - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #fontFamily-generic - #styling-inline - #timeContainer - - - - -
      -

      - This text of this sentence should change from a serif to a sans serif font at 5s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation005.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation005.xml deleted file mode 100755 index 3ab299f..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation005.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Animation Test - Animate 005 - Set fontSize - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #fontSize-isomorphic - #length-pixel - #styling-inline - #timeContainer - - - - -
      -

      - This font height of this sentence should go from 20px to 40px at 5s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation006.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation006.xml deleted file mode 100755 index 100369a..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation006.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Animation Test - Animate 007 - Set fontStyle - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #styling-inline - #fontStyle - #timeContainer - - - - -
      -

      - This font of this sentence should go from normal to italic at 5s

      -

      - This font of this sentence should go from reverseOblique to oblique at 15s -

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation007.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation007.xml deleted file mode 100755 index bcebfd0..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation007.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Animation Test - Animate 007 - Set fontWeight - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #styling-inline - #fontWeight - #timeContainer - - - - -
      -

      - This font of this sentence should go from normal to bold at 5s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation008.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation008.xml deleted file mode 100755 index 53eb648..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation008.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Animation Test - Animate 007 - Set lineHeight - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #styling-inline - #length-pixel - #lineHeight - #timeContainer - - - - -
      -

      - This line height of this sentence should
      go from normal to zero at 5s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation012.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation012.xml deleted file mode 100755 index eb7ea37..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation012.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - Animation Test - Animate 001 - Set textAlign - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #styling-inline - #textAlign-absolute - #timeContainer - - - - -
      -

      - This sentence should move right at 5s for 5 seconds -

      -

      - This sentence should move left at 6s for 4 seconds -

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation013.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation013.xml deleted file mode 100755 index cca5775..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation013.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Animation Test - Animate 013 - Set textDecoration, also tests multiple sets in action - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #styling-inline - #textDecoration - #timeContainer - - - - -
      -

      - - - The line should move progressively down through this sentence every 2 seconds

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation014.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation014.xml deleted file mode 100755 index 99a74f3..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation014.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Animation Test - Animate 014 - Set textOutline - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #styling-inline - #textOutline - #timeContainer - - - - -
      -

      - This text should be outlined in blurred red from 5s to 10s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation015.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation015.xml deleted file mode 100755 index fbb13c4..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation015.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Animation Test - Animate 015 - Set visibility - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #styling-inline - #timeContainer - #visibility-block - - - - -
      -

      - This text should become invisible from 3s to 8s

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation016.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation016.xml deleted file mode 100755 index 5cef2be..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation016.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Animation Test - Animate 016 - Set wrapOption - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #layout - #styling-inline - #timeContainer - #wrapOption - - - - -
      -

      - This text should start to wrap from 3s to 8s it is a very long piece of text in order to ensure that it does in fact hit the region edges and thus require some wrapping action. Wrapping is not required to support hyphenation, so this text should wrap at whole word boundaries.

      -
      - -
      diff --git a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation017.xml b/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation017.xml deleted file mode 100755 index 295e1ba..0000000 --- a/lib/osmf/samples/SMPTETTPluginTest/html-template/dfxp-testsuite/Animation/Animation017.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - Animation Test - Animate 017 - Set zIndex - Copyright (C) 2008 W3C (MIT, ERCIM, Keio). - - - - #animation - #layout - #overflow-visible - #styling-inline - #timeContainer - #zIndex - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VASTSample/readme.txt b/lib/osmf/samples/VASTSample/readme.txt index 22741f6..aa8c5eb 100644 --- a/lib/osmf/samples/VASTSample/readme.txt +++ b/lib/osmf/samples/VASTSample/readme.txt @@ -1,11 +1,11 @@ -This is a simple player to allow testers to test different VAST creatives in a player. - -Steps to test: -Publish VASTNewSample.as -Launch VASTNewSample.html to test the video player - -Expected results: -Content video will play. - -Additional Instructions: +This is a simple player to allow testers to test different VAST creatives in a player. + +Steps to test: +Publish VASTNewSample.as +Launch VASTNewSample.html to test the video player + +Expected results: +Content video will play. + +Additional Instructions: Change chosenFile and chosenPlacement to other constants to vary creative and placement (make sure they match - e.g. nonlinear ad should be in a nonlinear placement) \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/.actionScriptProperties b/lib/osmf/samples/VASTTest/.actionScriptProperties index 41b46c4..a25bfda 100644 --- a/lib/osmf/samples/VASTTest/.actionScriptProperties +++ b/lib/osmf/samples/VASTTest/.actionScriptProperties @@ -1,19 +1,19 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VASTTest/.flexProperties b/lib/osmf/samples/VASTTest/.flexProperties index b5f031b..afb9306 100644 --- a/lib/osmf/samples/VASTTest/.flexProperties +++ b/lib/osmf/samples/VASTTest/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/elements/TestProxyElement.as b/lib/osmf/samples/VASTTest/src/org/osmf/elements/TestProxyElement.as index b2f3a9a..a34c6c5 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/elements/TestProxyElement.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/elements/TestProxyElement.as @@ -1,261 +1,261 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.elements -{ - import __AS3__.vec.Vector; - - import flash.errors.IllegalOperationError; - - import flexunit.framework.Assert; - - import org.osmf.containers.MediaContainer; - import org.osmf.events.ContainerChangeEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.TestMediaElement; - import org.osmf.media.URLResource; - import org.osmf.metadata.Metadata; - import org.osmf.traits.MediaTraitType; - import org.osmf.utils.DynamicMediaElement; - import org.osmf.utils.DynamicProxyElement; - import org.osmf.utils.SimpleLoader; - - public class TestProxyElement extends TestMediaElement - { - override public function setUp():void - { - super.setUp(); - - traitsAddedCount = 0; - traitsRemovedCount = 0; - } - - public function testConstructor():void - { - // No exception here. - new ProxyElement(new MediaElement()); - - // No exception here (though the wrappedElement must be set later). - new ProxyElement(null); - } - - public function testSetProxiedElement():void - { - var proxyElement:ProxyElement = createProxyElement(); - - // Most operations will fail until the wrappedElement is set. - try - { - proxyElement.resource = new URLResource(null); - } - catch (error:IllegalOperationError) - { - Assert.fail(); - } - - Assert.assertFalse(proxyElement.hasTrait(MediaTraitType.TIME)); - - var proxiedElement:DynamicMediaElement - = new DynamicMediaElement( [MediaTraitType.TIME, MediaTraitType.LOAD] - , new SimpleLoader() - ); - - proxyElement.proxiedElement = proxiedElement; - - Assert.assertTrue(proxyElement.hasTrait(MediaTraitType.TIME)); - Assert.assertTrue(proxyElement.hasTrait(MediaTraitType.PLAY) == false); - - // Setting a new wrapped element is possible. Doing so should - // cause the proxy's traits to change, and for some events to - // fire. - // - - proxyElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - proxyElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); - - var proxiedElement2:DynamicMediaElement - = new DynamicMediaElement( [MediaTraitType.PLAY, MediaTraitType.LOAD] - , new SimpleLoader() - ); - - Assert.assertTrue(traitsAddedCount == 0); - Assert.assertTrue(traitsRemovedCount == 0); - - proxyElement.proxiedElement = proxiedElement2; - - Assert.assertTrue(proxyElement.hasTrait(MediaTraitType.TIME) == false); - Assert.assertTrue(proxyElement.hasTrait(MediaTraitType.PLAY)); - - Assert.assertTrue(traitsAddedCount == 2); - Assert.assertTrue(traitsRemovedCount == 2); - - // Clearing the wrapped element is also possible. This should - // clear out the traits, and make many operations invalid. - // - - proxyElement.proxiedElement = null; - - Assert.assertTrue(proxyElement.proxiedElement == null); - - Assert.assertFalse(proxyElement.hasTrait(MediaTraitType.TIME)); - - Assert.assertTrue(traitsAddedCount == 2); - Assert.assertTrue(traitsRemovedCount == 4); - } - - public function testSetProxiedElementWithBaseTraits():void - { - // When setting a new proxied element, we should not get events - // for traits that are overridden or blocked (FM-937). - // - - var proxyElement:DynamicProxyElement = new DynamicProxyElement(null, [MediaTraitType.LOAD]); - var blockedTraits:Vector. = new Vector.(); - blockedTraits.push(MediaTraitType.PLAY); - proxyElement.setBlockedTraits(blockedTraits); - - var proxiedElement:DynamicMediaElement - = new DynamicMediaElement( [MediaTraitType.PLAY, MediaTraitType.LOAD] - , new SimpleLoader() - ); - - proxyElement.proxiedElement = proxiedElement; - - proxyElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - proxyElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); - - var proxiedElement2:DynamicMediaElement - = new DynamicMediaElement( [MediaTraitType.PLAY, MediaTraitType.LOAD] - , new SimpleLoader() - ); - - proxyElement.proxiedElement = proxiedElement2; - - Assert.assertTrue(traitsAddedCount == 0); - Assert.assertTrue(traitsRemovedCount == 0); - } - - override public function testContainer():void - { - var mediaElement:ProxyElement = createMediaElement() as ProxyElement; - mediaElement.proxiedElement = new MediaElement(); - - var gatewayA:MediaContainer = new MediaContainer(); - var gatewayB:MediaContainer = new MediaContainer(); - - Assert.assertNull(mediaElement.container); - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{gatewayA.addMediaElement(mediaElement);} - ); - - Assert.assertEquals(gatewayA, mediaElement.container); - - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{gatewayB.addMediaElement(mediaElement);} - ); - - Assert.assertEquals(gatewayB, mediaElement.container); - - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{mediaElement.container.removeMediaElement(mediaElement);} - ); - - Assert.assertNull(mediaElement.container); - } - - public function testMetadataEventPropagation():void - { - var proxyElement:ProxyElement = createProxyElement(); - - var metadataAdded:Boolean = false; - - proxyElement.addEventListener(MediaElementEvent.METADATA_ADD, onMetadataAdd); - proxyElement.addMetadata("foo", new Metadata()); - - function onMetadataAdd(event:MediaElementEvent):void - { - metadataAdded = true; - } - - Assert.assertTrue(metadataAdded); - } - - // Protected - // - - protected function createProxyElement():ProxyElement - { - return new ProxyElement(null); - } - - // Overrides - // - - override protected function createMediaElement():MediaElement - { - return new ProxyElement(new MediaElement()); - } - - override protected function get hasLoadTrait():Boolean - { - return false; - } - - override protected function get resourceForMediaElement():MediaResourceBase - { - return new URLResource("http://example.com"); - } - - override protected function get existentTraitTypesOnInitialization():Array - { - return []; - } - - override protected function get existentTraitTypesAfterLoad():Array - { - return []; - } - - // Internals - // - - private function onTraitAdd(event:MediaElementEvent):void - { - traitsAddedCount++; - } - - private function onTraitRemove(event:MediaElementEvent):void - { - traitsRemovedCount++; - } - - private var traitsAddedCount:int; - private var traitsRemovedCount:int; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.elements +{ + import __AS3__.vec.Vector; + + import flash.errors.IllegalOperationError; + + import flexunit.framework.Assert; + + import org.osmf.containers.MediaContainer; + import org.osmf.events.ContainerChangeEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.TestMediaElement; + import org.osmf.media.URLResource; + import org.osmf.metadata.Metadata; + import org.osmf.traits.MediaTraitType; + import org.osmf.utils.DynamicMediaElement; + import org.osmf.utils.DynamicProxyElement; + import org.osmf.utils.SimpleLoader; + + public class TestProxyElement extends TestMediaElement + { + override public function setUp():void + { + super.setUp(); + + traitsAddedCount = 0; + traitsRemovedCount = 0; + } + + public function testConstructor():void + { + // No exception here. + new ProxyElement(new MediaElement()); + + // No exception here (though the wrappedElement must be set later). + new ProxyElement(null); + } + + public function testSetProxiedElement():void + { + var proxyElement:ProxyElement = createProxyElement(); + + // Most operations will fail until the wrappedElement is set. + try + { + proxyElement.resource = new URLResource(null); + } + catch (error:IllegalOperationError) + { + Assert.fail(); + } + + Assert.assertFalse(proxyElement.hasTrait(MediaTraitType.TIME)); + + var proxiedElement:DynamicMediaElement + = new DynamicMediaElement( [MediaTraitType.TIME, MediaTraitType.LOAD] + , new SimpleLoader() + ); + + proxyElement.proxiedElement = proxiedElement; + + Assert.assertTrue(proxyElement.hasTrait(MediaTraitType.TIME)); + Assert.assertTrue(proxyElement.hasTrait(MediaTraitType.PLAY) == false); + + // Setting a new wrapped element is possible. Doing so should + // cause the proxy's traits to change, and for some events to + // fire. + // + + proxyElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + proxyElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); + + var proxiedElement2:DynamicMediaElement + = new DynamicMediaElement( [MediaTraitType.PLAY, MediaTraitType.LOAD] + , new SimpleLoader() + ); + + Assert.assertTrue(traitsAddedCount == 0); + Assert.assertTrue(traitsRemovedCount == 0); + + proxyElement.proxiedElement = proxiedElement2; + + Assert.assertTrue(proxyElement.hasTrait(MediaTraitType.TIME) == false); + Assert.assertTrue(proxyElement.hasTrait(MediaTraitType.PLAY)); + + Assert.assertTrue(traitsAddedCount == 2); + Assert.assertTrue(traitsRemovedCount == 2); + + // Clearing the wrapped element is also possible. This should + // clear out the traits, and make many operations invalid. + // + + proxyElement.proxiedElement = null; + + Assert.assertTrue(proxyElement.proxiedElement == null); + + Assert.assertFalse(proxyElement.hasTrait(MediaTraitType.TIME)); + + Assert.assertTrue(traitsAddedCount == 2); + Assert.assertTrue(traitsRemovedCount == 4); + } + + public function testSetProxiedElementWithBaseTraits():void + { + // When setting a new proxied element, we should not get events + // for traits that are overridden or blocked (FM-937). + // + + var proxyElement:DynamicProxyElement = new DynamicProxyElement(null, [MediaTraitType.LOAD]); + var blockedTraits:Vector. = new Vector.(); + blockedTraits.push(MediaTraitType.PLAY); + proxyElement.setBlockedTraits(blockedTraits); + + var proxiedElement:DynamicMediaElement + = new DynamicMediaElement( [MediaTraitType.PLAY, MediaTraitType.LOAD] + , new SimpleLoader() + ); + + proxyElement.proxiedElement = proxiedElement; + + proxyElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + proxyElement.addEventListener(MediaElementEvent.TRAIT_REMOVE, onTraitRemove); + + var proxiedElement2:DynamicMediaElement + = new DynamicMediaElement( [MediaTraitType.PLAY, MediaTraitType.LOAD] + , new SimpleLoader() + ); + + proxyElement.proxiedElement = proxiedElement2; + + Assert.assertTrue(traitsAddedCount == 0); + Assert.assertTrue(traitsRemovedCount == 0); + } + + override public function testContainer():void + { + var mediaElement:ProxyElement = createMediaElement() as ProxyElement; + mediaElement.proxiedElement = new MediaElement(); + + var gatewayA:MediaContainer = new MediaContainer(); + var gatewayB:MediaContainer = new MediaContainer(); + + Assert.assertNull(mediaElement.container); + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{gatewayA.addMediaElement(mediaElement);} + ); + + Assert.assertEquals(gatewayA, mediaElement.container); + + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{gatewayB.addMediaElement(mediaElement);} + ); + + Assert.assertEquals(gatewayB, mediaElement.container); + + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{mediaElement.container.removeMediaElement(mediaElement);} + ); + + Assert.assertNull(mediaElement.container); + } + + public function testMetadataEventPropagation():void + { + var proxyElement:ProxyElement = createProxyElement(); + + var metadataAdded:Boolean = false; + + proxyElement.addEventListener(MediaElementEvent.METADATA_ADD, onMetadataAdd); + proxyElement.addMetadata("foo", new Metadata()); + + function onMetadataAdd(event:MediaElementEvent):void + { + metadataAdded = true; + } + + Assert.assertTrue(metadataAdded); + } + + // Protected + // + + protected function createProxyElement():ProxyElement + { + return new ProxyElement(null); + } + + // Overrides + // + + override protected function createMediaElement():MediaElement + { + return new ProxyElement(new MediaElement()); + } + + override protected function get hasLoadTrait():Boolean + { + return false; + } + + override protected function get resourceForMediaElement():MediaResourceBase + { + return new URLResource("http://example.com"); + } + + override protected function get existentTraitTypesOnInitialization():Array + { + return []; + } + + override protected function get existentTraitTypesAfterLoad():Array + { + return []; + } + + // Internals + // + + private function onTraitAdd(event:MediaElementEvent):void + { + traitsAddedCount++; + } + + private function onTraitRemove(event:MediaElementEvent):void + { + traitsRemovedCount++; + } + + private var traitsAddedCount:int; + private var traitsRemovedCount:int; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/flexunit/TestCaseEx.as b/lib/osmf/samples/VASTTest/src/org/osmf/flexunit/TestCaseEx.as index 97d6eb0..fee85fb 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/flexunit/TestCaseEx.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/flexunit/TestCaseEx.as @@ -1,116 +1,116 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.flexunit -{ - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.utils.Dictionary; - - import flexunit.framework.TestCase; - - /** - * Defines an extended version of flex unit's TestCase class, providing - * a number of additional assert methods. - */ - public class TestCaseEx extends TestCase - { - /** - * @inheritDoc - */ - public function TestCaseEx(methodName:String=null) - { - super(methodName); - } - - // Utils - // - - /** - * Asserts that a function throws an exception on being invoked. - * - * @param f The function that's expected to throw an exception. - * @param arguments The arguments to pass to the function on its invocation. - * @return The result of the function invocation. - * - */ - protected function assertThrows(f:Function, ...arguments):* - { - var result:*; - - try - { - result = f.apply(null,arguments); - fail(); - } - catch(e:Error) - { - } - - return result; - } - - /** - * Asserts that one or more events get dispatched on a function being - * invoked. - * - * @param dispatcher The expected dispatcher of the events. - * @param types The types of the events that the dispatcher is expected to dispatch. - * @param f The function that's expected to trigger the event dispatching. - * @param arguments The arguments to pass to the function on its invocation. - * @return The result of the function invocation. - * - */ - protected function assertDispatches(dispatcher:EventDispatcher, types:Array, f:Function, ...arguments):* - { - var result:*; - var dispatched:Dictionary = new Dictionary(); - function handler(event:Event):void - { - dispatched[event.type] = true; - } - - var type:String; - for each (type in types) - { - dispatcher.addEventListener(type, handler); - } - - result = f.apply(null, arguments); - - for each (type in types) - { - dispatcher.removeEventListener(type, handler); - } - - for each (type in types) - { - if (dispatched[type] != true) - { - fail("Event of type " + type + " was not fired."); - } - } - - return result; - } - - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.flexunit +{ + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.utils.Dictionary; + + import flexunit.framework.TestCase; + + /** + * Defines an extended version of flex unit's TestCase class, providing + * a number of additional assert methods. + */ + public class TestCaseEx extends TestCase + { + /** + * @inheritDoc + */ + public function TestCaseEx(methodName:String=null) + { + super(methodName); + } + + // Utils + // + + /** + * Asserts that a function throws an exception on being invoked. + * + * @param f The function that's expected to throw an exception. + * @param arguments The arguments to pass to the function on its invocation. + * @return The result of the function invocation. + * + */ + protected function assertThrows(f:Function, ...arguments):* + { + var result:*; + + try + { + result = f.apply(null,arguments); + fail(); + } + catch(e:Error) + { + } + + return result; + } + + /** + * Asserts that one or more events get dispatched on a function being + * invoked. + * + * @param dispatcher The expected dispatcher of the events. + * @param types The types of the events that the dispatcher is expected to dispatch. + * @param f The function that's expected to trigger the event dispatching. + * @param arguments The arguments to pass to the function on its invocation. + * @return The result of the function invocation. + * + */ + protected function assertDispatches(dispatcher:EventDispatcher, types:Array, f:Function, ...arguments):* + { + var result:*; + var dispatched:Dictionary = new Dictionary(); + function handler(event:Event):void + { + dispatched[event.type] = true; + } + + var type:String; + for each (type in types) + { + dispatcher.addEventListener(type, handler); + } + + result = f.apply(null, arguments); + + for each (type in types) + { + dispatcher.removeEventListener(type, handler); + } + + for each (type in types) + { + if (dispatched[type] != true) + { + fail("Event of type " + type + " was not fired."); + } + } + + return result; + } + + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/media/TestMediaElement.as b/lib/osmf/samples/VASTTest/src/org/osmf/media/TestMediaElement.as index 7e25f2e..ea9c02a 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/media/TestMediaElement.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/media/TestMediaElement.as @@ -1,649 +1,649 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.media -{ - import flash.events.Event; - import flash.events.EventDispatcher; - - import org.osmf.containers.MediaContainer; - import org.osmf.events.ContainerChangeEvent; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorCodes; - import org.osmf.events.MediaErrorEvent; - import org.osmf.flexunit.TestCaseEx; - import org.osmf.metadata.Metadata; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.utils.OSMFStrings; - - public class TestMediaElement extends TestCaseEx - { - override public function setUp():void - { - super.setUp(); - - _eventDispatcher = new EventDispatcher(); - } - - override public function tearDown():void - { - super.tearDown(); - - _eventDispatcher = null; - } - - public function testGetTraitTypes():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyGetTraitTypes(mediaElement, existentTraitTypesOnInitialization); - } - - public function testGetTraitTypesAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyGetTraitTypes); - } - } - - public function testGetTraitTypesAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyGetTraitTypes, mediaElement); - } - } - - public function testHasTrait():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyHasTrait(mediaElement, existentTraitTypesOnInitialization); - } - - public function testHasTraitWhenParamIsNull():void - { - var mediaElement:MediaElement = createMediaElement(); - - try - { - mediaElement.hasTrait(null); - - fail(); - } - catch (error:ArgumentError) - { - } - } - - public function testHasTraitAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyHasTrait); - } - } - - public function testHasTraitAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyHasTrait, mediaElement); - } - } - - public function testGetTrait():void - { - var mediaElement:MediaElement = createMediaElement(); - - verifyGetTrait(mediaElement, existentTraitTypesOnInitialization); - } - - public function testGetTraitWhenParamIsNull():void - { - var mediaElement:MediaElement = createMediaElement(); - - try - { - mediaElement.getTrait(null); - - fail(); - } - catch (error:ArgumentError) - { - } - } - - public function testGetTraitAfterLoad():void - { - if (hasLoadTrait) - { - callAfterLoad(verifyGetTrait); - } - } - - public function testGetTraitAfterUnload():void - { - if (hasLoadTrait) - { - // Load the media without calling a verify function. - var mediaElement:MediaElement = callAfterLoad(null, false); - - // Verify it once the load completes. - callAfterUnload(verifyGetTrait, mediaElement); - } - } - - public function testGetResource():void - { - var mediaElement:MediaElement = createMediaElement(); - - assertTrue(mediaElement.resource == null); - } - - public function testSetResource():void - { - var mediaElement:MediaElement = createMediaElement(); - - mediaElement.resource = resourceForMediaElement; - assertTrue(mediaElement.resource != null); - - mediaElement.resource = null; - assertTrue(mediaElement.resource == null); - } - - public function testAddMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaElementEvent.METADATA_ADD, onAdd); - var addCalled:Boolean = false; - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - assertTrue(addCalled); - - mediaElement.addMetadata(nsurl2, meta2); - - assertEquals(mediaElement.getMetadata(nsurl1), meta1); - assertEquals(mediaElement.getMetadata(nsurl2), meta2); - - // Test addition through the undocumented API results in - // an event. (This is how we simulate metadata being added - // internally.) - addCalled = false; - mediaElement.metadata.addValue("foo", meta1); - assertEquals(mediaElement.getMetadata("foo"), meta1); - assertTrue(addCalled); - - // Test the Catching of Errors - try - { - mediaElement.addMetadata(null, meta1); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - try - { - mediaElement.addMetadata(nsurl1, null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - - function onAdd(event:MediaElementEvent):void - { - addCalled = true; - assertNotNull(event.metadata); - } - } - - public function testRemoveMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onRemove); - var removeCalled:Boolean = false; - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertFalse(removeCalled); - assertEquals(mediaElement.removeMetadata(nsurl2), meta2); - assertTrue(removeCalled); - assertEquals(mediaElement.removeMetadata(nsurl2), null); - assertEquals(mediaElement.removeMetadata(nsurl1), meta1); - - // Test removal through the undocumented API results in - // an event. (This is how we simulate metadata being removed - // internally.) - removeCalled = false; - mediaElement.addMetadata("foo", meta1); - assertEquals(mediaElement.metadata.removeValue("foo"), meta1); - assertTrue(removeCalled); - - // Test the Catching of Errors - try - { - mediaElement.removeMetadata(null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - - function onRemove(event:MediaElementEvent):void - { - removeCalled = true; - assertNotNull(event.metadata); - } - } - - public function testGetMetadata():void - { - var mediaElement:MediaElement = createMediaElement(); - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertEquals(mediaElement.getMetadata(nsurl2), meta2); - assertEquals(mediaElement.getMetadata(nsurl1), meta1); - assertEquals(mediaElement.getMetadata("foo"), null); - - // Test the Catching of Errors - try - { - mediaElement.getMetadata(null); - - fail(); - } - catch(error:ArgumentError) - { - assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); - } - } - - public function testGetMetadataNamespaceURLs():void - { - var mediaElement:MediaElement = createMediaElement(); - - var nsurl1:String = "nsurl1"; - var nsurl2:String = "nsurl2"; - var meta1:Metadata = new Metadata(); - var meta2:Metadata = new Metadata(); - - mediaElement.addMetadata(nsurl1, meta1); - mediaElement.addMetadata(nsurl2, meta2); - - assertTrue(mediaElement.metadataNamespaceURLs.length == 2); - assertTrue( ( mediaElement.metadataNamespaceURLs[0] == "nsurl1" - && mediaElement.metadataNamespaceURLs[1] == "nsurl2" - ) - || ( mediaElement.metadataNamespaceURLs[0] == "nsurl2" - && mediaElement.metadataNamespaceURLs[1] == "nsurl1" - ) - ); - } - - public function testMediaErrorEventDispatch():void - { - if (hasLoadTrait) - { - var mediaElement:MediaElement = createMediaElement(); - mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, 1000)); - - var eventCtr:int = 0; - - // Make sure error events dispatched on the trait are redispatched - // on the MediaElement. - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(99))); - loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID))); - - function onMediaError(event:MediaErrorEvent):void - { - eventCtr++; - - if (eventCtr == 1) - { - assertTrue(event.error.errorID == 99); - assertTrue(event.error.message == ""); - assertTrue(event.target == mediaElement); - } - else if (eventCtr == 2) - { - assertTrue(event.error.errorID == MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID); - assertTrue(event.error.message == "File has invalid structure"); - assertTrue(event.target == mediaElement); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - else fail(); - } - } - } - - public function testContainer():void - { - var mediaElement:MediaElement = createMediaElement(); - var containerA:MediaContainer = new MediaContainer(); - var containerB:MediaContainer = new MediaContainer(); - - assertNull(mediaElement.container); - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerA.addMediaElement(mediaElement);} - ); - - assertEquals(containerA, mediaElement.container); - - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerB.addMediaElement(mediaElement);} - ); - - assertEquals(containerB, mediaElement.container); - - assertDispatches - ( mediaElement - , [ContainerChangeEvent.CONTAINER_CHANGE] - , function():void{containerB.removeMediaElement(mediaElement);} - ); - - assertNull(mediaElement.container); - } - - // Protected - // - - protected function createMediaElement():MediaElement - { - // Subclasses can override to specify the MediaElement subclass - // to test. - return new MediaElement(); - } - - protected function get hasLoadTrait():Boolean - { - // Subclasses can override to specify that they start with the - // LoadTrait. - return false; - } - - protected function get resourceForMediaElement():MediaResourceBase - { - // Subclasses can override to specify a resource that the - // MediaElement can work with. - return new URLResource("http://www.example.com"); - } - - protected function get existentTraitTypesOnInitialization():Array - { - // Subclasses can override to specify the trait types which are - // expected upon initialization. - return []; - } - - protected function get existentTraitTypesAfterLoad():Array - { - // Subclasses can override to specify the trait types which are - // expected after a load. Ignored if the MediaElement - // lacks the LoadTrait. - return []; - } - - final protected function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - final protected function mustNotReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is NOT received. - fail(); - } - - final protected function get eventDispatcher():EventDispatcher - { - return _eventDispatcher; - } - - // Internals - // - - private function verifyGetTraitTypes(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - assertTrue(mediaElement.traitTypes != null); - assertTrue(mediaElement.traitTypes.length == expectedTraitTypes.length); - - // Verify all expected traits are in traitTypes. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.traitTypes.indexOf(traitType) >= 0); - } - - // Verify all other traits are not in traitTypes. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.traitTypes.indexOf(traitType) == -1); - } - } - - private function verifyHasTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - // Verify hasTrait returns true for all expected traits. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.hasTrait(traitType) == true); - } - - // Verify hasTrait returns false for all unexpected traits. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.hasTrait(traitType) == false); - } - } - - private function verifyGetTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void - { - // Verify getTrait returns a result for all expected traits. - for each (var traitType:String in expectedTraitTypes) - { - assertTrue(mediaElement.getTrait(traitType) != null); - } - - // Verify getTrait returns false for all unexpected traits. - var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); - for each (traitType in nonExistentTraitTypes) - { - assertTrue(mediaElement.getTrait(traitType) == null); - } - } - - private function callAfterLoad(func:Function, triggerTestCompleteEvent:Boolean=true):MediaElement - { - assertTrue(hasLoadTrait); - - if (triggerTestCompleteEvent) - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); - } - - var mediaElement:MediaElement = createMediaElement(); - mediaElement.resource = resourceForMediaElement; - - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCallAfterLoad - ); - loadTrait.load(); - - function onTestCallAfterLoad(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterLoad); - - if (func != null) - { - func(mediaElement, existentTraitTypesAfterLoad); - } - - if (triggerTestCompleteEvent) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - return mediaElement; - } - - private function callAfterUnload(func:Function, mediaElement:MediaElement):void - { - assertTrue(hasLoadTrait); - - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); - - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - - // If the MediaElement is not yet loaded, wait until it is. - if (loadTrait.loadState == LoadState.READY) - { - completeCallAfterUnload(func, mediaElement); - } - else - { - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCallAfterUnload - ); - - function onTestCallAfterUnload(event:LoadEvent):void - { - if (event.loadState == LoadState.READY) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterUnload); - - completeCallAfterUnload(func, mediaElement); - } - } - } - } - - private function completeCallAfterUnload(func:Function, mediaElement:MediaElement):void - { - var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; - assertTrue(loadTrait != null); - - loadTrait.addEventListener - ( LoadEvent.LOAD_STATE_CHANGE - , onTestCompleteCallAfterUnload - ); - loadTrait.unload(); - - function onTestCompleteCallAfterUnload(event:LoadEvent):void - { - if (event.loadState == LoadState.UNINITIALIZED) - { - loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCompleteCallAfterUnload); - - func(mediaElement, existentTraitTypesOnInitialization); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - private function inverseOf(traitTypes:Array):Array - { - var inverseTraitTypes:Array = []; - - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.AUDIO); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.BUFFER); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DRM); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DYNAMIC_STREAM); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.LOAD); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.PLAY); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.SEEK); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.TIME); - addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DISPLAY_OBJECT); - - return inverseTraitTypes; - } - - private function addIfNotPresent(traitTypes:Array, results:Array, traitType:String):void - { - if (traitTypes.indexOf(traitType) == -1) - { - results.push(traitType); - } - } - - private static const ASYNC_DELAY:Number = 8000; - - private var _eventDispatcher:EventDispatcher; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.media +{ + import flash.events.Event; + import flash.events.EventDispatcher; + + import org.osmf.containers.MediaContainer; + import org.osmf.events.ContainerChangeEvent; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorCodes; + import org.osmf.events.MediaErrorEvent; + import org.osmf.flexunit.TestCaseEx; + import org.osmf.metadata.Metadata; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.utils.OSMFStrings; + + public class TestMediaElement extends TestCaseEx + { + override public function setUp():void + { + super.setUp(); + + _eventDispatcher = new EventDispatcher(); + } + + override public function tearDown():void + { + super.tearDown(); + + _eventDispatcher = null; + } + + public function testGetTraitTypes():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyGetTraitTypes(mediaElement, existentTraitTypesOnInitialization); + } + + public function testGetTraitTypesAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyGetTraitTypes); + } + } + + public function testGetTraitTypesAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyGetTraitTypes, mediaElement); + } + } + + public function testHasTrait():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyHasTrait(mediaElement, existentTraitTypesOnInitialization); + } + + public function testHasTraitWhenParamIsNull():void + { + var mediaElement:MediaElement = createMediaElement(); + + try + { + mediaElement.hasTrait(null); + + fail(); + } + catch (error:ArgumentError) + { + } + } + + public function testHasTraitAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyHasTrait); + } + } + + public function testHasTraitAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyHasTrait, mediaElement); + } + } + + public function testGetTrait():void + { + var mediaElement:MediaElement = createMediaElement(); + + verifyGetTrait(mediaElement, existentTraitTypesOnInitialization); + } + + public function testGetTraitWhenParamIsNull():void + { + var mediaElement:MediaElement = createMediaElement(); + + try + { + mediaElement.getTrait(null); + + fail(); + } + catch (error:ArgumentError) + { + } + } + + public function testGetTraitAfterLoad():void + { + if (hasLoadTrait) + { + callAfterLoad(verifyGetTrait); + } + } + + public function testGetTraitAfterUnload():void + { + if (hasLoadTrait) + { + // Load the media without calling a verify function. + var mediaElement:MediaElement = callAfterLoad(null, false); + + // Verify it once the load completes. + callAfterUnload(verifyGetTrait, mediaElement); + } + } + + public function testGetResource():void + { + var mediaElement:MediaElement = createMediaElement(); + + assertTrue(mediaElement.resource == null); + } + + public function testSetResource():void + { + var mediaElement:MediaElement = createMediaElement(); + + mediaElement.resource = resourceForMediaElement; + assertTrue(mediaElement.resource != null); + + mediaElement.resource = null; + assertTrue(mediaElement.resource == null); + } + + public function testAddMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaElementEvent.METADATA_ADD, onAdd); + var addCalled:Boolean = false; + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + assertTrue(addCalled); + + mediaElement.addMetadata(nsurl2, meta2); + + assertEquals(mediaElement.getMetadata(nsurl1), meta1); + assertEquals(mediaElement.getMetadata(nsurl2), meta2); + + // Test addition through the undocumented API results in + // an event. (This is how we simulate metadata being added + // internally.) + addCalled = false; + mediaElement.metadata.addValue("foo", meta1); + assertEquals(mediaElement.getMetadata("foo"), meta1); + assertTrue(addCalled); + + // Test the Catching of Errors + try + { + mediaElement.addMetadata(null, meta1); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + try + { + mediaElement.addMetadata(nsurl1, null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + + function onAdd(event:MediaElementEvent):void + { + addCalled = true; + assertNotNull(event.metadata); + } + } + + public function testRemoveMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaElementEvent.METADATA_REMOVE, onRemove); + var removeCalled:Boolean = false; + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertFalse(removeCalled); + assertEquals(mediaElement.removeMetadata(nsurl2), meta2); + assertTrue(removeCalled); + assertEquals(mediaElement.removeMetadata(nsurl2), null); + assertEquals(mediaElement.removeMetadata(nsurl1), meta1); + + // Test removal through the undocumented API results in + // an event. (This is how we simulate metadata being removed + // internally.) + removeCalled = false; + mediaElement.addMetadata("foo", meta1); + assertEquals(mediaElement.metadata.removeValue("foo"), meta1); + assertTrue(removeCalled); + + // Test the Catching of Errors + try + { + mediaElement.removeMetadata(null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + + function onRemove(event:MediaElementEvent):void + { + removeCalled = true; + assertNotNull(event.metadata); + } + } + + public function testGetMetadata():void + { + var mediaElement:MediaElement = createMediaElement(); + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertEquals(mediaElement.getMetadata(nsurl2), meta2); + assertEquals(mediaElement.getMetadata(nsurl1), meta1); + assertEquals(mediaElement.getMetadata("foo"), null); + + // Test the Catching of Errors + try + { + mediaElement.getMetadata(null); + + fail(); + } + catch(error:ArgumentError) + { + assertEquals(error.message, OSMFStrings.getString(OSMFStrings.NULL_PARAM)); + } + } + + public function testGetMetadataNamespaceURLs():void + { + var mediaElement:MediaElement = createMediaElement(); + + var nsurl1:String = "nsurl1"; + var nsurl2:String = "nsurl2"; + var meta1:Metadata = new Metadata(); + var meta2:Metadata = new Metadata(); + + mediaElement.addMetadata(nsurl1, meta1); + mediaElement.addMetadata(nsurl2, meta2); + + assertTrue(mediaElement.metadataNamespaceURLs.length == 2); + assertTrue( ( mediaElement.metadataNamespaceURLs[0] == "nsurl1" + && mediaElement.metadataNamespaceURLs[1] == "nsurl2" + ) + || ( mediaElement.metadataNamespaceURLs[0] == "nsurl2" + && mediaElement.metadataNamespaceURLs[1] == "nsurl1" + ) + ); + } + + public function testMediaErrorEventDispatch():void + { + if (hasLoadTrait) + { + var mediaElement:MediaElement = createMediaElement(); + mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, 1000)); + + var eventCtr:int = 0; + + // Make sure error events dispatched on the trait are redispatched + // on the MediaElement. + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(99))); + loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID))); + + function onMediaError(event:MediaErrorEvent):void + { + eventCtr++; + + if (eventCtr == 1) + { + assertTrue(event.error.errorID == 99); + assertTrue(event.error.message == ""); + assertTrue(event.target == mediaElement); + } + else if (eventCtr == 2) + { + assertTrue(event.error.errorID == MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID); + assertTrue(event.error.message == "File has invalid structure"); + assertTrue(event.target == mediaElement); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + else fail(); + } + } + } + + public function testContainer():void + { + var mediaElement:MediaElement = createMediaElement(); + var containerA:MediaContainer = new MediaContainer(); + var containerB:MediaContainer = new MediaContainer(); + + assertNull(mediaElement.container); + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerA.addMediaElement(mediaElement);} + ); + + assertEquals(containerA, mediaElement.container); + + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerB.addMediaElement(mediaElement);} + ); + + assertEquals(containerB, mediaElement.container); + + assertDispatches + ( mediaElement + , [ContainerChangeEvent.CONTAINER_CHANGE] + , function():void{containerB.removeMediaElement(mediaElement);} + ); + + assertNull(mediaElement.container); + } + + // Protected + // + + protected function createMediaElement():MediaElement + { + // Subclasses can override to specify the MediaElement subclass + // to test. + return new MediaElement(); + } + + protected function get hasLoadTrait():Boolean + { + // Subclasses can override to specify that they start with the + // LoadTrait. + return false; + } + + protected function get resourceForMediaElement():MediaResourceBase + { + // Subclasses can override to specify a resource that the + // MediaElement can work with. + return new URLResource("http://www.example.com"); + } + + protected function get existentTraitTypesOnInitialization():Array + { + // Subclasses can override to specify the trait types which are + // expected upon initialization. + return []; + } + + protected function get existentTraitTypesAfterLoad():Array + { + // Subclasses can override to specify the trait types which are + // expected after a load. Ignored if the MediaElement + // lacks the LoadTrait. + return []; + } + + final protected function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + final protected function mustNotReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is NOT received. + fail(); + } + + final protected function get eventDispatcher():EventDispatcher + { + return _eventDispatcher; + } + + // Internals + // + + private function verifyGetTraitTypes(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + assertTrue(mediaElement.traitTypes != null); + assertTrue(mediaElement.traitTypes.length == expectedTraitTypes.length); + + // Verify all expected traits are in traitTypes. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.traitTypes.indexOf(traitType) >= 0); + } + + // Verify all other traits are not in traitTypes. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.traitTypes.indexOf(traitType) == -1); + } + } + + private function verifyHasTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + // Verify hasTrait returns true for all expected traits. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.hasTrait(traitType) == true); + } + + // Verify hasTrait returns false for all unexpected traits. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.hasTrait(traitType) == false); + } + } + + private function verifyGetTrait(mediaElement:MediaElement, expectedTraitTypes:Array):void + { + // Verify getTrait returns a result for all expected traits. + for each (var traitType:String in expectedTraitTypes) + { + assertTrue(mediaElement.getTrait(traitType) != null); + } + + // Verify getTrait returns false for all unexpected traits. + var nonExistentTraitTypes:Array = inverseOf(expectedTraitTypes); + for each (traitType in nonExistentTraitTypes) + { + assertTrue(mediaElement.getTrait(traitType) == null); + } + } + + private function callAfterLoad(func:Function, triggerTestCompleteEvent:Boolean=true):MediaElement + { + assertTrue(hasLoadTrait); + + if (triggerTestCompleteEvent) + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); + } + + var mediaElement:MediaElement = createMediaElement(); + mediaElement.resource = resourceForMediaElement; + + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCallAfterLoad + ); + loadTrait.load(); + + function onTestCallAfterLoad(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterLoad); + + if (func != null) + { + func(mediaElement, existentTraitTypesAfterLoad); + } + + if (triggerTestCompleteEvent) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + return mediaElement; + } + + private function callAfterUnload(func:Function, mediaElement:MediaElement):void + { + assertTrue(hasLoadTrait); + + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, ASYNC_DELAY)); + + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + + // If the MediaElement is not yet loaded, wait until it is. + if (loadTrait.loadState == LoadState.READY) + { + completeCallAfterUnload(func, mediaElement); + } + else + { + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCallAfterUnload + ); + + function onTestCallAfterUnload(event:LoadEvent):void + { + if (event.loadState == LoadState.READY) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCallAfterUnload); + + completeCallAfterUnload(func, mediaElement); + } + } + } + } + + private function completeCallAfterUnload(func:Function, mediaElement:MediaElement):void + { + var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait; + assertTrue(loadTrait != null); + + loadTrait.addEventListener + ( LoadEvent.LOAD_STATE_CHANGE + , onTestCompleteCallAfterUnload + ); + loadTrait.unload(); + + function onTestCompleteCallAfterUnload(event:LoadEvent):void + { + if (event.loadState == LoadState.UNINITIALIZED) + { + loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onTestCompleteCallAfterUnload); + + func(mediaElement, existentTraitTypesOnInitialization); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + private function inverseOf(traitTypes:Array):Array + { + var inverseTraitTypes:Array = []; + + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.AUDIO); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.BUFFER); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DRM); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DYNAMIC_STREAM); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.LOAD); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.PLAY); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.SEEK); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.TIME); + addIfNotPresent(traitTypes, inverseTraitTypes, MediaTraitType.DISPLAY_OBJECT); + + return inverseTraitTypes; + } + + private function addIfNotPresent(traitTypes:Array, results:Array, traitType:String):void + { + if (traitTypes.indexOf(traitType) == -1) + { + results.push(traitType); + } + } + + private static const ASYNC_DELAY:Number = 8000; + + private var _eventDispatcher:EventDispatcher; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/traits/TestLoaderBase.as b/lib/osmf/samples/VASTTest/src/org/osmf/traits/TestLoaderBase.as index 5435969..7f2c694 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/traits/TestLoaderBase.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/traits/TestLoaderBase.as @@ -1,415 +1,415 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.traits -{ - import flash.errors.IllegalOperationError; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.TimerEvent; - import flash.utils.Timer; - - import flexunit.framework.TestCase; - - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.utils.SimpleResource; - - public class TestLoaderBase extends TestCase - { - override public function setUp():void - { - super.setUp(); - - _loader = createLoader(); - - eventDispatcher = new EventDispatcher(); - eventCount = 0; - mediaErrors = []; - doTwice = false; - } - - override public function tearDown():void - { - super.tearDown(); - - _loader = null; - eventDispatcher = null; - } - - protected function createInterfaceObject(... args):Object - { - return new LoaderBase(); - } - - //--------------------------------------------------------------------- - - public function testCanHandleResource():void - { - assertTrue(loader.canHandleResource(successfulResource) == true); - assertTrue(loader.canHandleResource(failedResource) == true); - assertTrue(loader.canHandleResource(unhandledResource) == false); - } - - public function testLoad():void - { - doTestLoad(); - } - - public function testLoadTwice():void - { - doTwice = true; - doTestLoad(); - } - - private function doTestLoad():void - { - eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestLoad(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - if (doTwice) - { - reload = true; - } - else - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Calling load a second time should throw an exception. - try - { - event.loader.load(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - public function testLoadWithFailure():void - { - doTestLoadWithFailure(); - } - - public function testLoadWithFailureThenReload():void - { - doTwice = true; - doTestLoadWithFailure(); - } - - private function doTestLoadWithFailure():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); - var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); - loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - loader.load(loadTrait); - } - - private function onTestLoadWithFailure(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - if (eventCount == 1 && doTwice) - { - reload = true; - } - else - { - markCompleteOnMediaError(1); - } - break; - case 2: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOAD_ERROR); - assertTrue(event.newState == LoadState.LOADING); - break; - case 3: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - markCompleteOnMediaError(2); - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Reloading should repeat the failure. - event.loader.load(event.loadTrait); - } - } - - private function markCompleteOnMediaError(numExpected:int):void - { - if (numExpected == mediaErrors.length) - { - // Just verify one of them. - verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - else - { - // Wait a bit, then check again. - var timer:Timer = new Timer(400); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(event:TimerEvent):void - { - timer.stop(); - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - markCompleteOnMediaError(numExpected); - } - } - } - - public function testLoadWithInvalidResource():void - { - try - { - loader.load(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - public function testUnload():void - { - doTestUnload(); - } - - public function testUnloadTwice():void - { - doTwice = true; - doTestUnload(); - } - - private function doTestUnload():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestUnload(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var doUnload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - // Now unload. - doUnload = true; - - break; - case 2: - assertTrue(event.oldState == LoadState.READY); - assertTrue(event.newState == LoadState.UNLOADING); - break; - case 3: - assertTrue(event.oldState == LoadState.UNLOADING); - assertTrue(event.newState == LoadState.UNINITIALIZED); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - break; - - default: - fail(); - } - - eventCount++; - - if (doUnload) - { - event.loader.unload(event.loadTrait); - - if (doTwice) - { - // Unloading a second time should throw an exception - // (but the first unload will complete). - try - { - event.loader.unload(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - } - } - - public function testUnloadWithInvalidResource():void - { - try - { - loader.unload(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - //--------------------------------------------------------------------- - - protected final function createLoader():LoaderBase - { - return createInterfaceObject() as LoaderBase; - } - - protected function setOverriddenLoader(value:LoaderBase):void - { - _loader = value; - } - - protected final function get loader():LoaderBase - { - return _loader; - } - - protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - return new LoadTrait(loader, resource); - } - - - protected function get successfulResource():MediaResourceBase - { - throw new Error("Subclass must override get successfulResource!"); - } - - protected function get failedResource():MediaResourceBase - { - throw new Error("Subclass must override get failedResource!"); - } - - protected function get unhandledResource():MediaResourceBase - { - throw new Error("Subclass must override get unhandledResource!"); - } - - protected function verifyMediaErrorOnLoadFailure(error:MediaError):void - { - // Subclasses can override to check the error's properties. - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - private function mustNotReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is NOT received. - fail(); - } - - private function onMediaError(event:MediaErrorEvent):void - { - mediaErrors.push(event.error); - } - - private static const TEST_TIME:int = 8000; - - private var eventDispatcher:EventDispatcher; - private var eventCount:int = 0; - private var mediaErrors:Array; - private var _loader:LoaderBase; - private var doTwice:Boolean; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.traits +{ + import flash.errors.IllegalOperationError; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.TimerEvent; + import flash.utils.Timer; + + import flexunit.framework.TestCase; + + import org.osmf.events.LoaderEvent; + import org.osmf.events.MediaError; + import org.osmf.events.MediaErrorEvent; + import org.osmf.media.MediaResourceBase; + import org.osmf.utils.SimpleResource; + + public class TestLoaderBase extends TestCase + { + override public function setUp():void + { + super.setUp(); + + _loader = createLoader(); + + eventDispatcher = new EventDispatcher(); + eventCount = 0; + mediaErrors = []; + doTwice = false; + } + + override public function tearDown():void + { + super.tearDown(); + + _loader = null; + eventDispatcher = null; + } + + protected function createInterfaceObject(... args):Object + { + return new LoaderBase(); + } + + //--------------------------------------------------------------------- + + public function testCanHandleResource():void + { + assertTrue(loader.canHandleResource(successfulResource) == true); + assertTrue(loader.canHandleResource(failedResource) == true); + assertTrue(loader.canHandleResource(unhandledResource) == false); + } + + public function testLoad():void + { + doTestLoad(); + } + + public function testLoadTwice():void + { + doTwice = true; + doTestLoad(); + } + + private function doTestLoad():void + { + eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); + loader.load(createLoadTrait(loader, successfulResource)); + } + + private function onTestLoad(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var reload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.READY); + + if (doTwice) + { + reload = true; + } + else + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + break; + default: + fail(); + } + + eventCount++; + + if (reload) + { + // Calling load a second time should throw an exception. + try + { + event.loader.load(event.loadTrait); + + fail(); + } + catch (error:IllegalOperationError) + { + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + } + } + + public function testLoadWithFailure():void + { + doTestLoadWithFailure(); + } + + public function testLoadWithFailureThenReload():void + { + doTwice = true; + doTestLoadWithFailure(); + } + + private function doTestLoadWithFailure():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); + var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); + loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + loader.load(loadTrait); + } + + private function onTestLoadWithFailure(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var reload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.LOAD_ERROR); + + if (eventCount == 1 && doTwice) + { + reload = true; + } + else + { + markCompleteOnMediaError(1); + } + break; + case 2: + assertTrue(doTwice); + + assertTrue(event.oldState == LoadState.LOAD_ERROR); + assertTrue(event.newState == LoadState.LOADING); + break; + case 3: + assertTrue(doTwice); + + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.LOAD_ERROR); + + markCompleteOnMediaError(2); + break; + default: + fail(); + } + + eventCount++; + + if (reload) + { + // Reloading should repeat the failure. + event.loader.load(event.loadTrait); + } + } + + private function markCompleteOnMediaError(numExpected:int):void + { + if (numExpected == mediaErrors.length) + { + // Just verify one of them. + verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + } + else + { + // Wait a bit, then check again. + var timer:Timer = new Timer(400); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + + function onTimer(event:TimerEvent):void + { + timer.stop(); + timer.removeEventListener(TimerEvent.TIMER, onTimer); + + markCompleteOnMediaError(numExpected); + } + } + } + + public function testLoadWithInvalidResource():void + { + try + { + loader.load(createLoadTrait(loader, unhandledResource)); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + + public function testUnload():void + { + doTestUnload(); + } + + public function testUnloadTwice():void + { + doTwice = true; + doTestUnload(); + } + + private function doTestUnload():void + { + eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); + + loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); + loader.load(createLoadTrait(loader, successfulResource)); + } + + private function onTestUnload(event:LoaderEvent):void + { + assertTrue(event.loader == loader); + assertTrue(event.loadTrait != null); + assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); + + var doUnload:Boolean = false; + + switch (eventCount) + { + case 0: + assertTrue(event.oldState == LoadState.UNINITIALIZED); + assertTrue(event.newState == LoadState.LOADING); + break; + case 1: + assertTrue(event.oldState == LoadState.LOADING); + assertTrue(event.newState == LoadState.READY); + + // Now unload. + doUnload = true; + + break; + case 2: + assertTrue(event.oldState == LoadState.READY); + assertTrue(event.newState == LoadState.UNLOADING); + break; + case 3: + assertTrue(event.oldState == LoadState.UNLOADING); + assertTrue(event.newState == LoadState.UNINITIALIZED); + + eventDispatcher.dispatchEvent(new Event("testComplete")); + break; + + default: + fail(); + } + + eventCount++; + + if (doUnload) + { + event.loader.unload(event.loadTrait); + + if (doTwice) + { + // Unloading a second time should throw an exception + // (but the first unload will complete). + try + { + event.loader.unload(event.loadTrait); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + } + } + + public function testUnloadWithInvalidResource():void + { + try + { + loader.unload(createLoadTrait(loader, unhandledResource)); + + fail(); + } + catch (error:IllegalOperationError) + { + } + } + + //--------------------------------------------------------------------- + + protected final function createLoader():LoaderBase + { + return createInterfaceObject() as LoaderBase; + } + + protected function setOverriddenLoader(value:LoaderBase):void + { + _loader = value; + } + + protected final function get loader():LoaderBase + { + return _loader; + } + + protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait + { + return new LoadTrait(loader, resource); + } + + + protected function get successfulResource():MediaResourceBase + { + throw new Error("Subclass must override get successfulResource!"); + } + + protected function get failedResource():MediaResourceBase + { + throw new Error("Subclass must override get failedResource!"); + } + + protected function get unhandledResource():MediaResourceBase + { + throw new Error("Subclass must override get unhandledResource!"); + } + + protected function verifyMediaErrorOnLoadFailure(error:MediaError):void + { + // Subclasses can override to check the error's properties. + } + + private function mustReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is received. + } + + private function mustNotReceiveEvent(event:Event):void + { + // Placeholder to ensure an event is NOT received. + fail(); + } + + private function onMediaError(event:MediaErrorEvent):void + { + mediaErrors.push(event.error); + } + + private static const TEST_TIME:int = 8000; + + private var eventDispatcher:EventDispatcher; + private var eventCount:int = 0; + private var mediaErrors:Array; + private var _loader:LoaderBase; + private var doTwice:Boolean; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicBufferTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicBufferTrait.as index cafaeb4..dbff648 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicBufferTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicBufferTrait.as @@ -1,38 +1,38 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.traits.BufferTrait; - - public class DynamicBufferTrait extends BufferTrait - { - public function set buffering(value:Boolean):void - { - setBuffering(value); - } - - public function set bufferLength(value:Number):void - { - setBufferLength(value); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.traits.BufferTrait; + + public class DynamicBufferTrait extends BufferTrait + { + public function set buffering(value:Boolean):void + { + setBuffering(value); + } + + public function set bufferLength(value:Number):void + { + setBufferLength(value); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDRMTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDRMTrait.as index a4f108e..3f91058 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDRMTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDRMTrait.as @@ -1,73 +1,73 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.events.DRMEvent; - import org.osmf.events.MediaError; - import org.osmf.traits.DRMState; - import org.osmf.traits.DRMTrait; - - public class DynamicDRMTrait extends DRMTrait - { - public function DynamicDRMTrait() - { - super(); - } - - override public function authenticate(username:String=null, password:String=null):void - { - invokeDrmStateChange(DRMState.AUTHENTICATING, null, null); - if (username == null) - { - invokeDrmStateChange(DRMState.AUTHENTICATION_ERROR, null, null); - } - else - { - invokeDrmStateChange(DRMState.AUTHENTICATION_COMPLETE, null, null); - } - } - - override public function authenticateWithToken(token:Object):void - { - invokeDrmStateChange(DRMState.AUTHENTICATING, token, null); - if (token == null) - { - invokeDrmStateChange(DRMState.AUTHENTICATION_ERROR, null, null); - } - else - { - invokeDrmStateChange(DRMState.AUTHENTICATION_COMPLETE, token, null); - } - } - - public function invokeDrmStateChange(state:String, token:Object, error:MediaError, start:Date = null, end:Date = null, period:Number = NaN, serverURL:String = null):void - { - setStartDate(start); - setEndDate(end); - setPeriod(period); - setDrmState(state); - dispatchEvent(new DRMEvent(DRMEvent.DRM_STATE_CHANGE, state,false, false, start, end, period, serverURL, token, error)); - } - - - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.events.DRMEvent; + import org.osmf.events.MediaError; + import org.osmf.traits.DRMState; + import org.osmf.traits.DRMTrait; + + public class DynamicDRMTrait extends DRMTrait + { + public function DynamicDRMTrait() + { + super(); + } + + override public function authenticate(username:String=null, password:String=null):void + { + invokeDrmStateChange(DRMState.AUTHENTICATING, null, null); + if (username == null) + { + invokeDrmStateChange(DRMState.AUTHENTICATION_ERROR, null, null); + } + else + { + invokeDrmStateChange(DRMState.AUTHENTICATION_COMPLETE, null, null); + } + } + + override public function authenticateWithToken(token:Object):void + { + invokeDrmStateChange(DRMState.AUTHENTICATING, token, null); + if (token == null) + { + invokeDrmStateChange(DRMState.AUTHENTICATION_ERROR, null, null); + } + else + { + invokeDrmStateChange(DRMState.AUTHENTICATION_COMPLETE, token, null); + } + } + + public function invokeDrmStateChange(state:String, token:Object, error:MediaError, start:Date = null, end:Date = null, period:Number = NaN, serverURL:String = null):void + { + setStartDate(start); + setEndDate(end); + setPeriod(period); + setDrmState(state); + dispatchEvent(new DRMEvent(DRMEvent.DRM_STATE_CHANGE, state,false, false, start, end, period, serverURL, token, error)); + } + + + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDVRTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDVRTrait.as index fd16af3..53b647c 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDVRTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDVRTrait.as @@ -1,39 +1,39 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.utils -{ - import org.osmf.traits.DVRTrait; - - public class DynamicDVRTrait extends DVRTrait - { - public function DynamicDVRTrait(isRecording:Boolean=false) - { - super(isRecording); - } - - public function set isRecording(value:Boolean):void - { - setIsRecording(value); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.utils +{ + import org.osmf.traits.DVRTrait; + + public class DynamicDVRTrait extends DVRTrait + { + public function DynamicDVRTrait(isRecording:Boolean=false) + { + super(isRecording); + } + + public function set isRecording(value:Boolean):void + { + setIsRecording(value); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDisplayObjectTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDisplayObjectTrait.as index 87de183..6d88d06 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDisplayObjectTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDisplayObjectTrait.as @@ -1,45 +1,45 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.display.DisplayObject; - - import org.osmf.traits.DisplayObjectTrait; - - public class DynamicDisplayObjectTrait extends DisplayObjectTrait - { - public function DynamicDisplayObjectTrait(displayObject:DisplayObject, mediaWidth:Number=0, mediaHeight:Number=0) - { - super(displayObject, mediaWidth, mediaHeight); - } - - public function set displayObject(value:DisplayObject):void - { - setDisplayObject(value); - } - - public function setSize(width:Number, height:Number):void - { - setMediaSize(width, height); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.display.DisplayObject; + + import org.osmf.traits.DisplayObjectTrait; + + public class DynamicDisplayObjectTrait extends DisplayObjectTrait + { + public function DynamicDisplayObjectTrait(displayObject:DisplayObject, mediaWidth:Number=0, mediaHeight:Number=0) + { + super(displayObject, mediaWidth, mediaHeight); + } + + public function set displayObject(value:DisplayObject):void + { + setDisplayObject(value); + } + + public function setSize(width:Number, height:Number):void + { + setMediaSize(width, height); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDynamicStreamTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDynamicStreamTrait.as index 8fea716..fd0df6d 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDynamicStreamTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicDynamicStreamTrait.as @@ -1,67 +1,67 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.traits.DynamicStreamTrait; - - public class DynamicDynamicStreamTrait extends DynamicStreamTrait - { - public function DynamicDynamicStreamTrait(autoSwitch:Boolean = false, currentIndex:int = 0, numDynamicStreams:int = 1) - { - super(autoSwitch,currentIndex, numDynamicStreams); - } - - public function set currentIndex(value:int):void - { - setCurrentIndex(value); - } - - public function get bitrates():Array - { - return _bitrates; - } - - public function set bitrates(value:Array):void - { - _bitrates = value; - setNumDynamicStreams(bitrates.length); - maxAllowedIndex = bitrates.length - 1; - } - - override public function getBitrateForIndex(index:int):Number - { - return _bitrates[index]; - } - - override protected function switchingChangeEnd(index:int):void - { - super.switchingChangeEnd(index); - - if (switching) - { - setSwitching(false, index); - } - } - - private var _bitrates:Array = []; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.traits.DynamicStreamTrait; + + public class DynamicDynamicStreamTrait extends DynamicStreamTrait + { + public function DynamicDynamicStreamTrait(autoSwitch:Boolean = false, currentIndex:int = 0, numDynamicStreams:int = 1) + { + super(autoSwitch,currentIndex, numDynamicStreams); + } + + public function set currentIndex(value:int):void + { + setCurrentIndex(value); + } + + public function get bitrates():Array + { + return _bitrates; + } + + public function set bitrates(value:Array):void + { + _bitrates = value; + setNumDynamicStreams(bitrates.length); + maxAllowedIndex = bitrates.length - 1; + } + + override public function getBitrateForIndex(index:int):Number + { + return _bitrates[index]; + } + + override protected function switchingChangeEnd(index:int):void + { + super.switchingChangeEnd(index); + + if (switching) + { + setSwitching(false, index); + } + } + + private var _bitrates:Array = []; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicLoadTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicLoadTrait.as index bd2c18a..916673f 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicLoadTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicLoadTrait.as @@ -1,45 +1,45 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.media.MediaResourceBase; - - public class DynamicLoadTrait extends LoadTrait - { - public function DynamicLoadTrait(loader:LoaderBase, resource:MediaResourceBase) - { - super(loader, resource); - } - - public function set bytesLoaded(value:Number):void - { - setBytesLoaded(value); - } - - public function set bytesTotal(value:Number):void - { - setBytesTotal(value); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.media.MediaResourceBase; + + public class DynamicLoadTrait extends LoadTrait + { + public function DynamicLoadTrait(loader:LoaderBase, resource:MediaResourceBase) + { + super(loader, resource); + } + + public function set bytesLoaded(value:Number):void + { + setBytesLoaded(value); + } + + public function set bytesTotal(value:Number):void + { + setBytesTotal(value); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicMediaElement.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicMediaElement.as index 332aa27..b381eca 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicMediaElement.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicMediaElement.as @@ -1,119 +1,119 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.display.Sprite; - - import org.osmf.media.MediaElement; - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.AudioTrait; - import org.osmf.traits.BufferTrait; - import org.osmf.traits.DRMTrait; - import org.osmf.traits.DVRTrait; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.DynamicStreamTrait; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.traits.MediaTraitBase; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - - public class DynamicMediaElement extends MediaElement - { - public function DynamicMediaElement(traitTypes:Array=null, loader:LoaderBase=null, resource:MediaResourceBase=null, useDynamicTraits:Boolean=false) - { - this.resource = resource; - - var doCreateSeekTrait:Boolean = false; - - if (traitTypes != null) - { - for each (var traitType:String in traitTypes) - { - var trait:MediaTraitBase = null; - - switch (traitType) - { - case MediaTraitType.AUDIO: - trait = new AudioTrait(); - break; - case MediaTraitType.BUFFER: - trait = useDynamicTraits ? new DynamicBufferTrait() : new BufferTrait(); - break; - case MediaTraitType.LOAD: - trait = useDynamicTraits ? new DynamicLoadTrait(loader, resource) : new LoadTrait(loader, resource); - break; - case MediaTraitType.PLAY: - trait = useDynamicTraits ? new DynamicPlayTrait() : new PlayTrait(); - break; - case MediaTraitType.SEEK: - doCreateSeekTrait = true; - continue; - case MediaTraitType.DYNAMIC_STREAM: - trait = useDynamicTraits ? new DynamicDynamicStreamTrait() : new DynamicStreamTrait(true, 0, 5); - break; - case MediaTraitType.TIME: - trait = useDynamicTraits ? new DynamicTimeTrait() : new TimeTrait(); - timeTrait = trait as TimeTrait; - break; - case MediaTraitType.DISPLAY_OBJECT: - trait = useDynamicTraits ? new DynamicDisplayObjectTrait(new Sprite()) : new DisplayObjectTrait(new Sprite()); - break; - case MediaTraitType.DRM: - trait = useDynamicTraits ? new DynamicDRMTrait() : new DRMTrait(); - break; - case MediaTraitType.DVR: - trait = useDynamicTraits ? new DynamicDVRTrait() : new DVRTrait(); - break; - default: - break; - } - - if (trait != null) - { - doAddTrait(traitType, trait); - } - } - } - - if (doCreateSeekTrait) - { - var seekTrait:SeekTrait = useDynamicTraits ? new DynamicSeekTrait(DynamicTimeTrait(timeTrait)) : new SeekTrait(timeTrait); - doAddTrait(MediaTraitType.SEEK, seekTrait); - } - } - - public function doAddTrait(traitType:String, instance:MediaTraitBase):void - { - this.addTrait(traitType, instance); - } - - public function doRemoveTrait(traitType:String):MediaTraitBase - { - return this.removeTrait(traitType); - } - - private var timeTrait:TimeTrait; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.display.Sprite; + + import org.osmf.media.MediaElement; + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.AudioTrait; + import org.osmf.traits.BufferTrait; + import org.osmf.traits.DRMTrait; + import org.osmf.traits.DVRTrait; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.DynamicStreamTrait; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.traits.MediaTraitBase; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + + public class DynamicMediaElement extends MediaElement + { + public function DynamicMediaElement(traitTypes:Array=null, loader:LoaderBase=null, resource:MediaResourceBase=null, useDynamicTraits:Boolean=false) + { + this.resource = resource; + + var doCreateSeekTrait:Boolean = false; + + if (traitTypes != null) + { + for each (var traitType:String in traitTypes) + { + var trait:MediaTraitBase = null; + + switch (traitType) + { + case MediaTraitType.AUDIO: + trait = new AudioTrait(); + break; + case MediaTraitType.BUFFER: + trait = useDynamicTraits ? new DynamicBufferTrait() : new BufferTrait(); + break; + case MediaTraitType.LOAD: + trait = useDynamicTraits ? new DynamicLoadTrait(loader, resource) : new LoadTrait(loader, resource); + break; + case MediaTraitType.PLAY: + trait = useDynamicTraits ? new DynamicPlayTrait() : new PlayTrait(); + break; + case MediaTraitType.SEEK: + doCreateSeekTrait = true; + continue; + case MediaTraitType.DYNAMIC_STREAM: + trait = useDynamicTraits ? new DynamicDynamicStreamTrait() : new DynamicStreamTrait(true, 0, 5); + break; + case MediaTraitType.TIME: + trait = useDynamicTraits ? new DynamicTimeTrait() : new TimeTrait(); + timeTrait = trait as TimeTrait; + break; + case MediaTraitType.DISPLAY_OBJECT: + trait = useDynamicTraits ? new DynamicDisplayObjectTrait(new Sprite()) : new DisplayObjectTrait(new Sprite()); + break; + case MediaTraitType.DRM: + trait = useDynamicTraits ? new DynamicDRMTrait() : new DRMTrait(); + break; + case MediaTraitType.DVR: + trait = useDynamicTraits ? new DynamicDVRTrait() : new DVRTrait(); + break; + default: + break; + } + + if (trait != null) + { + doAddTrait(traitType, trait); + } + } + } + + if (doCreateSeekTrait) + { + var seekTrait:SeekTrait = useDynamicTraits ? new DynamicSeekTrait(DynamicTimeTrait(timeTrait)) : new SeekTrait(timeTrait); + doAddTrait(MediaTraitType.SEEK, seekTrait); + } + } + + public function doAddTrait(traitType:String, instance:MediaTraitBase):void + { + this.addTrait(traitType, instance); + } + + public function doRemoveTrait(traitType:String):MediaTraitBase + { + return this.removeTrait(traitType); + } + + private var timeTrait:TimeTrait; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicPlayTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicPlayTrait.as index 56f4df4..82a83db 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicPlayTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicPlayTrait.as @@ -1,33 +1,33 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.traits.PlayTrait; - - public class DynamicPlayTrait extends PlayTrait - { - public function set canPause(value:Boolean):void - { - setCanPause(value); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.traits.PlayTrait; + + public class DynamicPlayTrait extends PlayTrait + { + public function set canPause(value:Boolean):void + { + setCanPause(value); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicProxyElement.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicProxyElement.as index 1c87e2b..704c176 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicProxyElement.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicProxyElement.as @@ -1,109 +1,109 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import __AS3__.vec.Vector; - - import org.osmf.elements.ProxyElement; - import org.osmf.media.MediaElement; - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.AudioTrait; - import org.osmf.traits.BufferTrait; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.traits.MediaTraitBase; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - - public class DynamicProxyElement extends ProxyElement - { - public function DynamicProxyElement(wrappedElement:MediaElement=null, traitTypes:Array=null, loader:LoaderBase=null, resource:MediaResourceBase=null) - { - super(wrappedElement); - - if (traitTypes != null || loader != null || resource != null) - { - initialize(traitTypes, loader, resource); - } - } - - public function doAddTrait(type:String, instance:MediaTraitBase):void - { - this.addTrait(type,instance); - } - - public function doRemoveTrait(type:String):MediaTraitBase - { - return this.removeTrait(type); - } - - public function setBlockedTraits(traits:Vector.):void - { - super.blockedTraits = traits; - } - - private function initialize(traitTypes:Array, loader:LoaderBase, resource:MediaResourceBase):void - { - this.resource = resource; - - if (traitTypes != null) - { - for each (var traitType:String in traitTypes) - { - var trait:MediaTraitBase = null; - - switch (traitType) - { - case MediaTraitType.AUDIO: - trait = new AudioTrait(); - break; - case MediaTraitType.BUFFER: - trait = new BufferTrait(); - break; - case MediaTraitType.LOAD: - trait = new LoadTrait(loader, resource); - break; - case MediaTraitType.PLAY: - trait = new PlayTrait(); - break; - case MediaTraitType.SEEK: - trait = new SeekTrait(null); - break; - case MediaTraitType.TIME: - trait = new TimeTrait(); - break; - case MediaTraitType.DISPLAY_OBJECT: - trait = new DisplayObjectTrait(null); - break; - default: - throw new ArgumentError(); - } - - addTrait(traitType, trait); - } - } - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import __AS3__.vec.Vector; + + import org.osmf.elements.ProxyElement; + import org.osmf.media.MediaElement; + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.AudioTrait; + import org.osmf.traits.BufferTrait; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.traits.MediaTraitBase; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + + public class DynamicProxyElement extends ProxyElement + { + public function DynamicProxyElement(wrappedElement:MediaElement=null, traitTypes:Array=null, loader:LoaderBase=null, resource:MediaResourceBase=null) + { + super(wrappedElement); + + if (traitTypes != null || loader != null || resource != null) + { + initialize(traitTypes, loader, resource); + } + } + + public function doAddTrait(type:String, instance:MediaTraitBase):void + { + this.addTrait(type,instance); + } + + public function doRemoveTrait(type:String):MediaTraitBase + { + return this.removeTrait(type); + } + + public function setBlockedTraits(traits:Vector.):void + { + super.blockedTraits = traits; + } + + private function initialize(traitTypes:Array, loader:LoaderBase, resource:MediaResourceBase):void + { + this.resource = resource; + + if (traitTypes != null) + { + for each (var traitType:String in traitTypes) + { + var trait:MediaTraitBase = null; + + switch (traitType) + { + case MediaTraitType.AUDIO: + trait = new AudioTrait(); + break; + case MediaTraitType.BUFFER: + trait = new BufferTrait(); + break; + case MediaTraitType.LOAD: + trait = new LoadTrait(loader, resource); + break; + case MediaTraitType.PLAY: + trait = new PlayTrait(); + break; + case MediaTraitType.SEEK: + trait = new SeekTrait(null); + break; + case MediaTraitType.TIME: + trait = new TimeTrait(); + break; + case MediaTraitType.DISPLAY_OBJECT: + trait = new DisplayObjectTrait(null); + break; + default: + throw new ArgumentError(); + } + + addTrait(traitType, trait); + } + } + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicSeekTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicSeekTrait.as index a9b4e2d..1daadc2 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicSeekTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicSeekTrait.as @@ -1,89 +1,89 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.events.TimerEvent; - import flash.utils.Timer; - - import org.osmf.events.SeekEvent; - import org.osmf.traits.SeekTrait; - import org.osmf.traits.TimeTrait; - - public class DynamicSeekTrait extends SeekTrait - { - public function DynamicSeekTrait(timeTrait:TimeTrait) - { - super(timeTrait); - - addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); - - _autoCompleteSeek = true; - } - - public function set autoCompleteSeek(value:Boolean):void - { - _autoCompleteSeek = value; - } - - public function get autoCompleteSeek():Boolean - { - return _autoCompleteSeek; - } - - public function completeSeek(time:Number):void - { - var dynamicTimeTrait:DynamicTimeTrait = timeTrait as DynamicTimeTrait; - if (dynamicTimeTrait != null) - { - dynamicTimeTrait.currentTime = time; - } - - super.setSeeking(false, time); - } - - // Internals - // - - private function onSeekingChange(event:SeekEvent):void - { - if (event.seeking && autoCompleteSeek) - { - seekTargetTime = event.time; - - // Complete the seek shortly after it begins. - var timer:Timer = new Timer(500, 1); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(timerEvent:TimerEvent):void - { - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - setSeeking(false, seekTargetTime); - } - } - } - - private var _autoCompleteSeek:Boolean; - private var seekTargetTime:Number; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.events.TimerEvent; + import flash.utils.Timer; + + import org.osmf.events.SeekEvent; + import org.osmf.traits.SeekTrait; + import org.osmf.traits.TimeTrait; + + public class DynamicSeekTrait extends SeekTrait + { + public function DynamicSeekTrait(timeTrait:TimeTrait) + { + super(timeTrait); + + addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange); + + _autoCompleteSeek = true; + } + + public function set autoCompleteSeek(value:Boolean):void + { + _autoCompleteSeek = value; + } + + public function get autoCompleteSeek():Boolean + { + return _autoCompleteSeek; + } + + public function completeSeek(time:Number):void + { + var dynamicTimeTrait:DynamicTimeTrait = timeTrait as DynamicTimeTrait; + if (dynamicTimeTrait != null) + { + dynamicTimeTrait.currentTime = time; + } + + super.setSeeking(false, time); + } + + // Internals + // + + private function onSeekingChange(event:SeekEvent):void + { + if (event.seeking && autoCompleteSeek) + { + seekTargetTime = event.time; + + // Complete the seek shortly after it begins. + var timer:Timer = new Timer(500, 1); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + + function onTimer(timerEvent:TimerEvent):void + { + timer.removeEventListener(TimerEvent.TIMER, onTimer); + + setSeeking(false, seekTargetTime); + } + } + } + + private var _autoCompleteSeek:Boolean; + private var seekTargetTime:Number; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicTimeTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicTimeTrait.as index daa20aa..5ae94b9 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicTimeTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/DynamicTimeTrait.as @@ -1,38 +1,38 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.traits.TimeTrait; - - public class DynamicTimeTrait extends TimeTrait - { - public function set currentTime(value:Number):void - { - setCurrentTime(value); - } - - public function set duration(value:Number):void - { - setDuration(value); - } - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.traits.TimeTrait; + + public class DynamicTimeTrait extends TimeTrait + { + public function set currentTime(value:Number):void + { + setCurrentTime(value); + } + + public function set duration(value:Number):void + { + setDuration(value); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/MockHTTPLoader.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/MockHTTPLoader.as index 62bfd4a..37d7fc2 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/MockHTTPLoader.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/MockHTTPLoader.as @@ -1,47 +1,47 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.net.URLLoader; - - public class MockHTTPLoader extends HTTPLoader - { - public function MockHTTPLoader() - { - super(); - - urlLoader = new MockURLLoader(); - } - - public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void - { - urlLoader.setExpectationForURL(url, expectSuccess, expectedData); - } - - override protected function createURLLoader():URLLoader - { - return urlLoader; - } - - private var urlLoader:MockURLLoader; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.net.URLLoader; + + public class MockHTTPLoader extends HTTPLoader + { + public function MockHTTPLoader() + { + super(); + + urlLoader = new MockURLLoader(); + } + + public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void + { + urlLoader.setExpectationForURL(url, expectSuccess, expectedData); + } + + override protected function createURLLoader():URLLoader + { + return urlLoader; + } + + private var urlLoader:MockURLLoader; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/MockURLLoader.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/MockURLLoader.as index c2d49a1..490bb25 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/MockURLLoader.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/MockURLLoader.as @@ -1,70 +1,70 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.events.Event; - import flash.events.IOErrorEvent; - import flash.net.URLLoader; - import flash.net.URLRequest; - import flash.utils.Dictionary; - - public class MockURLLoader extends URLLoader - { - public function MockURLLoader() - { - super(); - - expectations = new Dictionary(); - } - - public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void - { - expectations[url] = {"success":expectSuccess, "data":expectedData}; - } - - override public function load(request:URLRequest):void - { - var expectation:Object = expectations[request.url]; - if (expectation != null) - { - data = expectation["data"]; - - // Prevent the network request from happening. - if (expectation["success"] == true) - { - dispatchEvent(new Event(Event.COMPLETE)); - } - else - { - data = null; - dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR)); - } - } - else - { - throw new Error("Expectation needs to be set on MockURLLoader!"); - } - } - - private var expectations:Dictionary; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + import flash.utils.Dictionary; + + public class MockURLLoader extends URLLoader + { + public function MockURLLoader() + { + super(); + + expectations = new Dictionary(); + } + + public function setExpectationForURL(url:String, expectSuccess:Boolean, expectedData:*):void + { + expectations[url] = {"success":expectSuccess, "data":expectedData}; + } + + override public function load(request:URLRequest):void + { + var expectation:Object = expectations[request.url]; + if (expectation != null) + { + data = expectation["data"]; + + // Prevent the network request from happening. + if (expectation["success"] == true) + { + dispatchEvent(new Event(Event.COMPLETE)); + } + else + { + data = null; + dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR)); + } + } + else + { + throw new Error("Expectation needs to be set on MockURLLoader!"); + } + } + + private var expectations:Dictionary; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/NullResource.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/NullResource.as index b8b27cc..775b8e1 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/NullResource.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/NullResource.as @@ -1,29 +1,29 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.media.MediaResourceBase; - - public class NullResource extends MediaResourceBase - { - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.media.MediaResourceBase; + + public class NullResource extends MediaResourceBase + { + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/SimpleLoader.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/SimpleLoader.as index c901efb..e1bbe53 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/SimpleLoader.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/SimpleLoader.as @@ -1,117 +1,117 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.events.TimerEvent; - import flash.utils.Timer; - - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - - /** - * A SimpleLoader performs loads and unloads synchronously. - **/ - public class SimpleLoader extends LoaderBase - { - /** - * Constructor. - **/ - public function SimpleLoader(delayLoadComplete:Boolean = false) - { - this.delayLoadComplete = delayLoadComplete; - } - - /** - * Indicates that the load operation should be forced to - * fail. - **/ - public function forceFail(loadTrait:LoadTrait):Boolean - { - return loadTrait.resource is SimpleResource && - SimpleResource(loadTrait.resource).type == SimpleResource.FAILED; - } - - /** - * @inheritDoc - **/ - override public function canHandleResource(resource:MediaResourceBase):Boolean - { - var simpleResource:SimpleResource = resource as SimpleResource; - if (simpleResource != null) - { - return simpleResource.type != SimpleResource.UNHANDLED; - } - - return true; - } - - /** - * @inheritDoc - **/ - override protected function executeLoad(loadTrait:LoadTrait):void - { - updateLoadTrait(loadTrait, LoadState.LOADING); - - if (forceFail(loadTrait)) - { - updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); - } - else - { - if (delayLoadComplete) - { - var timer:Timer = new Timer(500, 1); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(event:TimerEvent):void - { - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - updateLoadTrait(loadTrait, LoadState.READY); - } - } - else - { - updateLoadTrait(loadTrait, LoadState.READY); - } - } - } - - /** - * @inheritDoc - **/ - override protected function executeUnload(loadTrait:LoadTrait):void - { - if (loadTrait.loadState == LoadState.LOADING || - loadTrait.loadState == LoadState.READY) - { - updateLoadTrait(loadTrait, LoadState.UNLOADING); - updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); - } - } - - private var delayLoadComplete:Boolean = false; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.events.TimerEvent; + import flash.utils.Timer; + + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + + /** + * A SimpleLoader performs loads and unloads synchronously. + **/ + public class SimpleLoader extends LoaderBase + { + /** + * Constructor. + **/ + public function SimpleLoader(delayLoadComplete:Boolean = false) + { + this.delayLoadComplete = delayLoadComplete; + } + + /** + * Indicates that the load operation should be forced to + * fail. + **/ + public function forceFail(loadTrait:LoadTrait):Boolean + { + return loadTrait.resource is SimpleResource && + SimpleResource(loadTrait.resource).type == SimpleResource.FAILED; + } + + /** + * @inheritDoc + **/ + override public function canHandleResource(resource:MediaResourceBase):Boolean + { + var simpleResource:SimpleResource = resource as SimpleResource; + if (simpleResource != null) + { + return simpleResource.type != SimpleResource.UNHANDLED; + } + + return true; + } + + /** + * @inheritDoc + **/ + override protected function executeLoad(loadTrait:LoadTrait):void + { + updateLoadTrait(loadTrait, LoadState.LOADING); + + if (forceFail(loadTrait)) + { + updateLoadTrait(loadTrait, LoadState.LOAD_ERROR); + } + else + { + if (delayLoadComplete) + { + var timer:Timer = new Timer(500, 1); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + + function onTimer(event:TimerEvent):void + { + timer.removeEventListener(TimerEvent.TIMER, onTimer); + + updateLoadTrait(loadTrait, LoadState.READY); + } + } + else + { + updateLoadTrait(loadTrait, LoadState.READY); + } + } + } + + /** + * @inheritDoc + **/ + override protected function executeUnload(loadTrait:LoadTrait):void + { + if (loadTrait.loadState == LoadState.LOADING || + loadTrait.loadState == LoadState.READY) + { + updateLoadTrait(loadTrait, LoadState.UNLOADING); + updateLoadTrait(loadTrait, LoadState.UNINITIALIZED); + } + } + + private var delayLoadComplete:Boolean = false; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/SimpleResource.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/SimpleResource.as index 2e0ea2f..038567c 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/SimpleResource.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/SimpleResource.as @@ -1,44 +1,44 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import org.osmf.media.MediaResourceBase; - - public class SimpleResource extends MediaResourceBase - { - public static const SUCCESSFUL:String = "successful"; - public static const FAILED:String = "failed"; - public static const UNHANDLED:String = "unhandled"; - - public function SimpleResource(type:String) - { - _type = type; - } - - public function get type():String - { - return _type; - } - - private var _type:String; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import org.osmf.media.MediaResourceBase; + + public class SimpleResource extends MediaResourceBase + { + public static const SUCCESSFUL:String = "successful"; + public static const FAILED:String = "failed"; + public static const UNHANDLED:String = "unhandled"; + + public function SimpleResource(type:String) + { + _type = type; + } + + public function get type():String + { + return _type; + } + + private var _type:String; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/TestConstants.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/TestConstants.as index a2cf88c..0ad3c1e 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/TestConstants.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/TestConstants.as @@ -1,133 +1,133 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - /** - * Centralized test class for constants, such as URLs to resources. - * - * If your test is the only one that needs a constant, then the - * constant should be scoped to the test class. Only place it here - * if it makes sense for multiple test classes to use it. - **/ - public class TestConstants - { - // Videos - // - - public static const REMOTE_PROGRESSIVE_VIDEO:String - = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; - public static const REMOTE_PROGRESSIVE_VIDEO_EXPECTED_DURATION:Number = 30; - public static const REMOTE_PROGRESSIVE_VIDEO_EXPECTED_WIDTH:Number = 640; - public static const REMOTE_PROGRESSIVE_VIDEO_EXPECTED_HEIGHT:Number = 352; - public static const REMOTE_PROGRESSIVE_VIDEO_EXPECTED_BYTES:Number = 12345; - - public static const REMOTE_STREAMING_VIDEO:String - = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - public static const REMOTE_STREAMING_VIDEO_EXPECTED_DURATION:Number = 35; - public static const REMOTE_STREAMING_VIDEO_EXPECTED_WIDTH:Number = 640; - public static const REMOTE_STREAMING_VIDEO_EXPECTED_HEIGHT:Number = 352; - - public static const REMOTE_STREAMING_VIDEO_RTMP:String - = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const REMOTE_STREAMING_VIDEO_RTMPS:String - = "rtmps://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const REMOTE_STREAMING_VIDEO_RTMPT:String - = "rtmpt://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const REMOTE_STREAMING_VIDEO_RTMPE:String - = "rtmpe://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const REMOTE_STREAMING_VIDEO_RTMPTE:String - = "rtmpte://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const REMOTE_STREAMING_VIDEO_1935:String - = "rtmp://cp67126.edgefcs.net:1935/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const REMOTE_STREAMING_VIDEO_443:String - = "rtmp://cp67126.edgefcs.net:443/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const REMOTE_STREAMING_VIDEO_80:String - = "rtmp://cp67126.edgefcs.net:80/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const INVALID_STREAMING_VIDEO:String - = "rtmp://cp67126.edgefcsfail.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv" - - public static const DEFAULT_PORT_PROTOCOL_RESULT:String = "1935rtmp443rtmp80rtmp1935rtmps443rtmps80rtmps1935rtmpt443rtmpt80rtmpt"; - - public static const RESULT_FOR_RTMPTE_443:String = "443rtmpte"; - - public static const REMOTE_STREAMING_VIDEO_WITH_PORT_PROTOCOL:String - = "rtmpte://cp67126.edgefcs.net:443/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; - - public static const CONNECT_ADDRESS_REMOTE_WITH_RTMPTE_443:String = "rtmpte://cp67126.edgefcs.net:443/ondemand"; - - public static const REMOTE_DYNAMIC_STREAMING_VIDEO_HOST:String = "rtmp://cp60395.edgefcs.net/ondemand"; - - public static const REMOTE_DYNAMIC_STREAMING_VIDEO_STREAMS:Array = - [ - {stream:"mp4:videos/encoded2/Train_450kbps.mp4", bitrate:"450000"}, - {stream:"mp4:videos/encoded2/Train_700kbps.mp4", bitrate:"700000"}, - {stream:"mp4:videos/encoded2/Train_900kbps.mp4", bitrate:"900000"}, - {stream:"mp4:videos/encoded2/Train_1000kbps_H.mp4", bitrate:"1000000"}, - ] - - public static const REMOTE_STREAMING_VIDEO_LIVE:String - = "rtmp://cp34973.live.edgefcs.net/live/Flash_live_bm_500K@9319"; - - // Images - // - - public static const REMOTE_IMAGE_FILE:String = "http://mediapm.edgesuite.net/strobe/content/test/train.jpg"; - public static const REMOTE_INVALID_IMAGE_FILE:String = "http://mediapm.edgesuite.net/fail/strobe/content/test/train.jpg"; - - public static const LOCAL_IMAGE_FILE:String = "assets/image.gif"; - - // Audio - // - - public static const LOCAL_SOUND_FILE:String = "assets/sound.mp3"; - public static const LOCAL_SOUND_FILE_EXPECTED_BYTES:Number = 30439; - public static const LOCAL_INVALID_SOUND_FILE:String = "assets/invalid.mp3"; - - public static const STREAMING_AUDIO_FILE:String - = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - - public static const INVALID_STREAMING_AUDIO_FILE:String - = "rtmp://cp67126.edgefcsfail.net/ondemand/mp3:mediapm/ovp/content/test/video/nocc_small.mp3"; - - // HTTP Streaming - // - - // This bootstrap box was taken from the field generated - // for the shuttle-720p video's manifest, which is located here: - // http://fms1j009f.corp.adobe.com/zeri-media/Fragments_Source_Media_Unprotected/MBR/shuttle/shuttle-mbr.f4m - // TODO: Post this and the media file publicly when we have a place to put them. - public static const ABST_BOX_DATA:String = "AAABGmFic3QAAAAAAAAADwAAAAPoAAAAAAAA7ekAAAAAAAAAAAAAAAAAAQAAABlhc3J0AAAAAAAAAAABAAAAAQAAAA8BAAAA1WFmcnQAAAAAAAAD6AAAAAAMAAAAAQAAAAAAAAAAAAARMAAAAAMAAAAAAAAiaAAADOQAAAAEAAAAAAAAL1AAABEwAAAABgAAAAAAAFG4AAAM5AAAAAcAAAAAAABeoAAAETAAAAAJAAAAAAAAgSoAAAyAAAAACgAAAAAAAI3OAAARMAAAAAsAAAAAAACfAwAADtgAAAAMAAAAAAAArd8AABEwAAAADQAAAAAAAL8TAAAM5AAAAA4AAAAAAADL+gAAETAAAAAPAAAAAAAA3S8AABDM"; - - // This AFRA box was taken from the shuttle-720p.f4x file, which is located here: - // http://fms1j009f.corp.adobe.com/zeri-media/Fragments_Source_Media_Unprotected/MBR/shuttle/shuttle-720p.f4x - // TODO: Post this and the media file publicly when we have a place to put them. - public static const AFRA_BOX_DATA:String = "AAAB+WFmcmEAAAAA4AAAA+gAAAAAAAAADwAAAAAAAAAAAAAAAQAAAAEAAAAAAAofUgAAAAAAAAAAAAAAAAAAETQAAAABAAAAAgAAAAAAQCdbAAAAAAAAAAAAAAAAAAAiaAAAAAEAAAADAAAAAABy3ZgAAAAAAAAAAAAAAAAAAC9QAAAAAQAAAAQAAAAAAJdI4QAAAAAAAAAAAAAAAAAAQIQAAAABAAAABQAAAAAA0CltAAAAAAAAAAAAAAAAAABRuAAAAAEAAAAGAAAAAAECGTsAAAAAAAAAAAAAAAAAAF6gAAAAAQAAAAcAAAAAASF1lwAAAAAAAAAAAAAAAAAAb9QAAAABAAAACAAAAAABX6IMAAAAAAAAAAAAAAAAAACBKgAAAAEAAAAJAAAAAAGaRKgAAAAAAAAAAAAAAAAAAI3OAAAAAQAAAAoAAAAAAcAHowAAAAAAAAAAAAAAAAAAnwMAAAABAAAACwAAAAAB49KkAAAAAAAAAAAAAAAAAACt3wAAAAEAAAAMAAAAAAIYd80AAAAAAAAAAAAAAAAAAL8TAAAAAQAAAA0AAAAAAkrsbAAAAAAAAAAAAAAAAAAAy/oAAAABAAAADgAAAAACcR6jAAAAAAAAAAAAAAAAAADdLwAAAAEAAAAPAAAAAAKuC8cAAAAAAAAAAA=="; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + /** + * Centralized test class for constants, such as URLs to resources. + * + * If your test is the only one that needs a constant, then the + * constant should be scoped to the test class. Only place it here + * if it makes sense for multiple test classes to use it. + **/ + public class TestConstants + { + // Videos + // + + public static const REMOTE_PROGRESSIVE_VIDEO:String + = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv"; + public static const REMOTE_PROGRESSIVE_VIDEO_EXPECTED_DURATION:Number = 30; + public static const REMOTE_PROGRESSIVE_VIDEO_EXPECTED_WIDTH:Number = 640; + public static const REMOTE_PROGRESSIVE_VIDEO_EXPECTED_HEIGHT:Number = 352; + public static const REMOTE_PROGRESSIVE_VIDEO_EXPECTED_BYTES:Number = 12345; + + public static const REMOTE_STREAMING_VIDEO:String + = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + public static const REMOTE_STREAMING_VIDEO_EXPECTED_DURATION:Number = 35; + public static const REMOTE_STREAMING_VIDEO_EXPECTED_WIDTH:Number = 640; + public static const REMOTE_STREAMING_VIDEO_EXPECTED_HEIGHT:Number = 352; + + public static const REMOTE_STREAMING_VIDEO_RTMP:String + = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const REMOTE_STREAMING_VIDEO_RTMPS:String + = "rtmps://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const REMOTE_STREAMING_VIDEO_RTMPT:String + = "rtmpt://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const REMOTE_STREAMING_VIDEO_RTMPE:String + = "rtmpe://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const REMOTE_STREAMING_VIDEO_RTMPTE:String + = "rtmpte://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const REMOTE_STREAMING_VIDEO_1935:String + = "rtmp://cp67126.edgefcs.net:1935/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const REMOTE_STREAMING_VIDEO_443:String + = "rtmp://cp67126.edgefcs.net:443/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const REMOTE_STREAMING_VIDEO_80:String + = "rtmp://cp67126.edgefcs.net:80/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const INVALID_STREAMING_VIDEO:String + = "rtmp://cp67126.edgefcsfail.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv" + + public static const DEFAULT_PORT_PROTOCOL_RESULT:String = "1935rtmp443rtmp80rtmp1935rtmps443rtmps80rtmps1935rtmpt443rtmpt80rtmpt"; + + public static const RESULT_FOR_RTMPTE_443:String = "443rtmpte"; + + public static const REMOTE_STREAMING_VIDEO_WITH_PORT_PROTOCOL:String + = "rtmpte://cp67126.edgefcs.net:443/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short.flv"; + + public static const CONNECT_ADDRESS_REMOTE_WITH_RTMPTE_443:String = "rtmpte://cp67126.edgefcs.net:443/ondemand"; + + public static const REMOTE_DYNAMIC_STREAMING_VIDEO_HOST:String = "rtmp://cp60395.edgefcs.net/ondemand"; + + public static const REMOTE_DYNAMIC_STREAMING_VIDEO_STREAMS:Array = + [ + {stream:"mp4:videos/encoded2/Train_450kbps.mp4", bitrate:"450000"}, + {stream:"mp4:videos/encoded2/Train_700kbps.mp4", bitrate:"700000"}, + {stream:"mp4:videos/encoded2/Train_900kbps.mp4", bitrate:"900000"}, + {stream:"mp4:videos/encoded2/Train_1000kbps_H.mp4", bitrate:"1000000"}, + ] + + public static const REMOTE_STREAMING_VIDEO_LIVE:String + = "rtmp://cp34973.live.edgefcs.net/live/Flash_live_bm_500K@9319"; + + // Images + // + + public static const REMOTE_IMAGE_FILE:String = "http://mediapm.edgesuite.net/strobe/content/test/train.jpg"; + public static const REMOTE_INVALID_IMAGE_FILE:String = "http://mediapm.edgesuite.net/fail/strobe/content/test/train.jpg"; + + public static const LOCAL_IMAGE_FILE:String = "assets/image.gif"; + + // Audio + // + + public static const LOCAL_SOUND_FILE:String = "assets/sound.mp3"; + public static const LOCAL_SOUND_FILE_EXPECTED_BYTES:Number = 30439; + public static const LOCAL_INVALID_SOUND_FILE:String = "assets/invalid.mp3"; + + public static const STREAMING_AUDIO_FILE:String + = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + + public static const INVALID_STREAMING_AUDIO_FILE:String + = "rtmp://cp67126.edgefcsfail.net/ondemand/mp3:mediapm/ovp/content/test/video/nocc_small.mp3"; + + // HTTP Streaming + // + + // This bootstrap box was taken from the field generated + // for the shuttle-720p video's manifest, which is located here: + // http://fms1j009f.corp.adobe.com/zeri-media/Fragments_Source_Media_Unprotected/MBR/shuttle/shuttle-mbr.f4m + // TODO: Post this and the media file publicly when we have a place to put them. + public static const ABST_BOX_DATA:String = "AAABGmFic3QAAAAAAAAADwAAAAPoAAAAAAAA7ekAAAAAAAAAAAAAAAAAAQAAABlhc3J0AAAAAAAAAAABAAAAAQAAAA8BAAAA1WFmcnQAAAAAAAAD6AAAAAAMAAAAAQAAAAAAAAAAAAARMAAAAAMAAAAAAAAiaAAADOQAAAAEAAAAAAAAL1AAABEwAAAABgAAAAAAAFG4AAAM5AAAAAcAAAAAAABeoAAAETAAAAAJAAAAAAAAgSoAAAyAAAAACgAAAAAAAI3OAAARMAAAAAsAAAAAAACfAwAADtgAAAAMAAAAAAAArd8AABEwAAAADQAAAAAAAL8TAAAM5AAAAA4AAAAAAADL+gAAETAAAAAPAAAAAAAA3S8AABDM"; + + // This AFRA box was taken from the shuttle-720p.f4x file, which is located here: + // http://fms1j009f.corp.adobe.com/zeri-media/Fragments_Source_Media_Unprotected/MBR/shuttle/shuttle-720p.f4x + // TODO: Post this and the media file publicly when we have a place to put them. + public static const AFRA_BOX_DATA:String = "AAAB+WFmcmEAAAAA4AAAA+gAAAAAAAAADwAAAAAAAAAAAAAAAQAAAAEAAAAAAAofUgAAAAAAAAAAAAAAAAAAETQAAAABAAAAAgAAAAAAQCdbAAAAAAAAAAAAAAAAAAAiaAAAAAEAAAADAAAAAABy3ZgAAAAAAAAAAAAAAAAAAC9QAAAAAQAAAAQAAAAAAJdI4QAAAAAAAAAAAAAAAAAAQIQAAAABAAAABQAAAAAA0CltAAAAAAAAAAAAAAAAAABRuAAAAAEAAAAGAAAAAAECGTsAAAAAAAAAAAAAAAAAAF6gAAAAAQAAAAcAAAAAASF1lwAAAAAAAAAAAAAAAAAAb9QAAAABAAAACAAAAAABX6IMAAAAAAAAAAAAAAAAAACBKgAAAAEAAAAJAAAAAAGaRKgAAAAAAAAAAAAAAAAAAI3OAAAAAQAAAAoAAAAAAcAHowAAAAAAAAAAAAAAAAAAnwMAAAABAAAACwAAAAAB49KkAAAAAAAAAAAAAAAAAACt3wAAAAEAAAAMAAAAAAIYd80AAAAAAAAAAAAAAAAAAL8TAAAAAQAAAA0AAAAAAkrsbAAAAAAAAAAAAAAAAAAAy/oAAAABAAAADgAAAAACcR6jAAAAAAAAAAAAAAAAAADdLwAAAAEAAAAPAAAAAAKuC8cAAAAAAAAAAA=="; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VASTTest/src/org/osmf/utils/TimerTimeTrait.as b/lib/osmf/samples/VASTTest/src/org/osmf/utils/TimerTimeTrait.as index ff3c681..f64fa43 100644 --- a/lib/osmf/samples/VASTTest/src/org/osmf/utils/TimerTimeTrait.as +++ b/lib/osmf/samples/VASTTest/src/org/osmf/utils/TimerTimeTrait.as @@ -1,78 +1,78 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.utils -{ - import flash.events.TimerEvent; - import flash.utils.Timer; - - import org.osmf.events.PlayEvent; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - import org.osmf.traits.TimeTrait; - - /** - * TimeTrait which keeps its current time in sync with the playing state of a - * PlayTrait, via a Timer. Useful for testing. - **/ - public class TimerTimeTrait extends TimeTrait - { - public function TimerTimeTrait(duration:Number, playTrait:PlayTrait) - { - super(duration); - - setCurrentTime(0); - this.playTrait = playTrait; - - playheadTimer = new Timer(250); - playheadTimer.addEventListener(TimerEvent.TIMER, onPlayheadTimer); - - playTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); - } - - override protected function signalComplete():void - { - super.signalComplete(); - - playheadTimer.stop(); - } - - private function onPlayStateChange(event:PlayEvent):void - { - if (event.playState == PlayState.PLAYING) - { - playheadTimer.start(); - } - else - { - playheadTimer.stop(); - } - } - - private function onPlayheadTimer(event:TimerEvent):void - { - setCurrentTime(currentTime + 0.25); - } - - private var playTrait:PlayTrait; - private var playheadTimer:Timer; - } +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + import flash.events.TimerEvent; + import flash.utils.Timer; + + import org.osmf.events.PlayEvent; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + import org.osmf.traits.TimeTrait; + + /** + * TimeTrait which keeps its current time in sync with the playing state of a + * PlayTrait, via a Timer. Useful for testing. + **/ + public class TimerTimeTrait extends TimeTrait + { + public function TimerTimeTrait(duration:Number, playTrait:PlayTrait) + { + super(duration); + + setCurrentTime(0); + this.playTrait = playTrait; + + playheadTimer = new Timer(250); + playheadTimer.addEventListener(TimerEvent.TIMER, onPlayheadTimer); + + playTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); + } + + override protected function signalComplete():void + { + super.signalComplete(); + + playheadTimer.stop(); + } + + private function onPlayStateChange(event:PlayEvent):void + { + if (event.playState == PlayState.PLAYING) + { + playheadTimer.start(); + } + else + { + playheadTimer.stop(); + } + } + + private function onPlayheadTimer(event:TimerEvent):void + { + setCurrentTime(currentTime + 0.25); + } + + private var playTrait:PlayTrait; + private var playheadTimer:Timer; + } } \ No newline at end of file diff --git a/lib/osmf/samples/VPAIDAdSequencingUnitTest/.actionScriptProperties b/lib/osmf/samples/VPAIDAdSequencingUnitTest/.actionScriptProperties index f83d4dd..b6b30b9 100644 --- a/lib/osmf/samples/VPAIDAdSequencingUnitTest/.actionScriptProperties +++ b/lib/osmf/samples/VPAIDAdSequencingUnitTest/.actionScriptProperties @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/AC_OETags.js b/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/AC_OETags.js +++ b/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/history/historyFrame.html b/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/history/historyFrame.html +++ b/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/index.template.html b/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/index.template.html +++ b/lib/osmf/samples/VPAIDAdSequencingUnitTest/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDAdSequencingUnitTest/readme.txt b/lib/osmf/samples/VPAIDAdSequencingUnitTest/readme.txt index b618786..8705560 100644 --- a/lib/osmf/samples/VPAIDAdSequencingUnitTest/readme.txt +++ b/lib/osmf/samples/VPAIDAdSequencingUnitTest/readme.txt @@ -1,30 +1,30 @@ -VPAIDTestplayer.as is already set up to run multiple ad sequences. -In order to test various sequences, the user will need to modify the String being sent to updateSerialElement() - -Steps to Test: -1) Open VPAIDTestplayer.as -2) Locate updateSerialElement("preroll/overlay"); at the end of the constructor. -3) Modify the String being sent as a parameter to this function to test differenct ad sequences. - - "preroll/overlay" - Preroll - Overlay(Content Video) - Postroll - - "overlay" - Preroll - Overlay(Content Video) - - "preroll/postroll" - Preroll - Preroll - Content Video - Postroll - Postroll - - "preroll" - Preroll - Preroll - Preroll - Content Video - - "postroll" - Content Video - Postroll - -4) Publish VPAIDTestPlayer.fla -5) Launch VPAIDTestPlayer.html - -Additional Instructions: -To test other creatives, change chosenLinear to any of the other constants in the list preceding it. E.g.: - public static const chosenLinear:String = LINEAR_VPAID; +VPAIDTestplayer.as is already set up to run multiple ad sequences. +In order to test various sequences, the user will need to modify the String being sent to updateSerialElement() + +Steps to Test: +1) Open VPAIDTestplayer.as +2) Locate updateSerialElement("preroll/overlay"); at the end of the constructor. +3) Modify the String being sent as a parameter to this function to test differenct ad sequences. + + "preroll/overlay" + Preroll - Overlay(Content Video) - Postroll + + "overlay" + Preroll - Overlay(Content Video) + + "preroll/postroll" + Preroll - Preroll - Content Video - Postroll - Postroll + + "preroll" + Preroll - Preroll - Preroll - Content Video + + "postroll" + Content Video - Postroll + +4) Publish VPAIDTestPlayer.fla +5) Launch VPAIDTestPlayer.html + +Additional Instructions: +To test other creatives, change chosenLinear to any of the other constants in the list preceding it. E.g.: + public static const chosenLinear:String = LINEAR_VPAID; public static const chosenNonLinear:String = NONLINEAR_VPAID; \ No newline at end of file diff --git a/lib/osmf/samples/VPAIDLibrary/.actionScriptProperties b/lib/osmf/samples/VPAIDLibrary/.actionScriptProperties index c2996bb..f3f71d6 100644 --- a/lib/osmf/samples/VPAIDLibrary/.actionScriptProperties +++ b/lib/osmf/samples/VPAIDLibrary/.actionScriptProperties @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDLibrary/.flexLibProperties b/lib/osmf/samples/VPAIDLibrary/.flexLibProperties index 1c18299..e0f9e4a 100644 --- a/lib/osmf/samples/VPAIDLibrary/.flexLibProperties +++ b/lib/osmf/samples/VPAIDLibrary/.flexLibProperties @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDLibrary/VPAID-build-config.xml b/lib/osmf/samples/VPAIDLibrary/VPAID-build-config.xml index b6ae5ed..34d4751 100644 --- a/lib/osmf/samples/VPAIDLibrary/VPAID-build-config.xml +++ b/lib/osmf/samples/VPAIDLibrary/VPAID-build-config.xml @@ -24,8 +24,8 @@ - @@ -40,10 +40,10 @@ false - @@ -110,11 +110,11 @@ - @@ -125,8 +125,8 @@ - @@ -145,13 +145,13 @@ - @@ -161,12 +161,12 @@ flash.fonts.BatikFontManager - @@ -286,19 +286,19 @@
      - - - @@ -312,8 +312,8 @@ true - diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/.actionScriptProperties b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/.actionScriptProperties index df2ad5b..3bd61e8 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/.actionScriptProperties +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/.actionScriptProperties @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/.flexLibProperties b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/.flexLibProperties index 99c48ec..e8c352f 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/.flexLibProperties +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/.flexLibProperties @@ -1,285 +1,285 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/elements/VPAIDElement.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/elements/VPAIDElement.as index 63e25f0..452a287 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/elements/VPAIDElement.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/elements/VPAIDElement.as @@ -1,782 +1,782 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.elements -{ - import flash.events.Event; - import flash.geom.Rectangle; - import flash.system.Security; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.SWFElement; - import org.osmf.elements.SWFLoader; - import org.osmf.elements.loaderClasses.LoaderLoadTrait; - import org.osmf.elements.loaderClasses.LoaderUtils; - import org.osmf.events.AudioEvent; - import org.osmf.events.LoadEvent; - import org.osmf.events.MetadataEvent; - import org.osmf.events.PlayEvent; - import org.osmf.events.TimeEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.traits.AudioTrait; - import org.osmf.traits.DisplayObjectTrait; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayState; - import org.osmf.traits.PlayTrait; - import org.osmf.vpaid.events.VPAIDLoadEvent; - import org.osmf.vpaid.metadata.VPAIDMetadata; - import org.osmf.vpaid.model.IVPAIDBase; - import org.osmf.vpaid.model.VPAID_1_1; - import org.osmf.vpaid.traits.VPAIDLoadTrait; - import org.osmf.vpaid.traits.VPAIDTimeTrait; - - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } - - /** - * VPAIDElement is a media element specifically created for presenting IAB compliant VPAID SWFs. - *

      The VPAIDElement uses a standard SWFLoader class to load and unload its media.

      - * - * @see org.osmf.elements.SWFLoader - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - - public class VPAIDElement extends SWFElement - { - public function VPAIDElement(resource:URLResource, loader:SWFLoader = null) - { - Security.allowDomain("*"); - super(resource, loader); - - _vpaidMetadata = new VPAIDMetadata(); - _vpaidMetadata.addEventListener(MetadataEvent.VALUE_CHANGE, onMetadataValueChanged); - _vpaidMetadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); - _vpaidMetadata.addEventListener(MetadataEvent.VALUE_REMOVE, onMetadataValueRemoved); - addMetadata(VPAIDMetadata.NAMESPACE, _vpaidMetadata); - - _loadTrait = getTrait(MediaTraitType.LOAD) as VPAIDLoadTrait; - _loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - _loadTrait.addEventListener(VPAIDLoadEvent.INITIALIZE_VPAID, onSWFLoad); - - _playTrait = new PlayTrait(); - addTrait(MediaTraitType.PLAY, _playTrait); - - _audioTrait = new AudioTrait(); - addTrait(MediaTraitType.AUDIO, _audioTrait); - - - } - - //Once the SWF is loaded we need to figure out the VPAID version - //the creative supports and the load the correct module. - private function vpaidHandshakeTest():void - { - var _testResult:Boolean = false; - for each (var version:String in _supportedVersion) - { - CONFIG::LOGGING - { - logger.debug("[VPAID] Testing HandshakeVersion: "+ version); - } - if (_testResult == false){ - _testResult = probeVersion(version); - }else{ - break; - } - } - if (_testResult){ - //found a handshake - CONFIG::LOGGING - { - logger.debug("[VPAID] Matching HandshakeVersion, ad responded: "+ _vpaid.version +" - ok"); - } - //Module is ready time to initalize the creative. - initVPAID(); - }else{ - CONFIG::LOGGING - { - logger.debug("[VPAID] Unsupported VPAID API version "); - } - _vpaidMetadata.addValue(VPAIDMetadata.ERROR, VPAIDMetadata.ERROR); - removeListeners(); - } - } - - private function probeVersion(versionToTest:String):Boolean - { - var result:Boolean = false; - var vpaidSWF:Object = _loadTrait.loader.contentLoaderInfo.content; - - switch(versionToTest) - { - case "1.0": - //TODO: Add support for VPAID 1.0 - break; - case "1.1": - _vpaid = new VPAID_1_1(vpaidSWF, this); - result = _vpaid.probeVersion(); - handshakePerformed = true; - break; - } - return result; - } - - //Need to add listeners to important VPAID events once the creative is initalized - private function initVPAID():void - { - - addEventListener("AdStarted", onAdStarted); - addEventListener("AdLoaded", onAdLoaded); - addEventListener("AdStopped", onAdStopped); - - addEventListener("AdRemainingTimeChange", onAdTimeChange); - addEventListener("AdLinearChange", onAdLinearChange); - - addEventListener("AdExpandedChange", onAdExpandedChange) - addEventListener("AdClickThru", onClickThruChange); - addEventListener("AdUserAcceptInvitation", onVPAIDEventReceived); - addEventListener("AdUserMinimize", onVPAIDEventReceived); - addEventListener("AdUserClose", onVPAIDEventReceived); - - addEventListener("AdCreativeView", onVPAIDEventReceived); - - addEventListener("AdPlaying", onAdPlayPause); - addEventListener("AdPaused", onAdPlayPause); - addEventListener("AdImpression", onVPAIDEventReceived); - addEventListener("AdVolumeChange", onVPAIDEventReceived); - addEventListener("AdVideoStart", onVPAIDEventReceived); - addEventListener("AdVideoFirstQuartile", onVPAIDEventReceived); - addEventListener("AdVideoMidpoint", onVPAIDEventReceived); - addEventListener("AdVideoThirdQuartile", onVPAIDEventReceived); - addEventListener("AdVideoComplete", onVPAIDEventReceived); - addEventListener("AdLog", onVPAIDEventReceived); - addEventListener("AdError", onVPAIDEventReceived); - - - //pre VPAID specifciation diagram, we need to get the linear state of the creative before we call initAd - _vpaidMetadata.addValue(VPAIDMetadata.AD_LINEAR, _vpaid.linearVPAID); - //This stores the inital linear start of the creative so that we can see if it is a linear (preroll) or nonlinear (ticker) creative. - //It can also be set by the publisher if they know were in the content video this creative is placed. - _vpaidMetadata.addValue(VPAIDMetadata.NON_LINEAR_CREATIVE, !_vpaid.linearVPAID); - - if(_vpaid.linearVPAID) - { - //only add time trait for linear ads - _timeTrait = new VPAIDTimeTrait(); - addTrait(MediaTraitType.TIME, _timeTrait); - - _timeTrait.addEventListener(TimeEvent.COMPLETE, onTimerChange); - _timeTrait.addEventListener(TimeEvent.DURATION_CHANGE, onTimerChange); - } - - _vpaid.initVPAID(getDimensions().width,getDimensions().height,"normal", 500, "", ""); - } - - private function onVPAIDEventReceived(event:Object):void - { - CONFIG::LOGGING - { - logger.debug("[VPAID] onVPAIDEventReceived: event.type=" + event.type); - } - switch(event.type) - { - - case "AdCreativeView": - _vpaidMetadata.addValue(VPAIDMetadata.AD_CREATIVE_VIEW, event); - break; - - case "AdImpression": - _vpaidMetadata.addValue(VPAIDMetadata.AD_IMPRESSION, event); - break; - - case "AdVideoStart": - _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_START, event); - break; - - case "AdVideoFirstQuartile": - _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_FIRST_QUARTILE, event); - break; - - case "AdVideoMidpoint": - _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_MID_POINT, event); - break; - - case "AdVideoThirdQuartile": - _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_THIRD_QUARTILE, event); - break; - - case "AdVideoComplete": - _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_COMPLETE,event); - break; - - case"AdUserAcceptInvitation": - - _vpaidMetadata.addValue(VPAIDMetadata.AD_USER_ACCEPT_INVITATION, event); - break; - - case"AdUserMinimize": - - _vpaidMetadata.addValue(VPAIDMetadata.AD_USER_MINIMIZE, event); - break; - - case"AdUserClose": - - _vpaidMetadata.addValue(VPAIDMetadata.AD_USER_CLOSE, event); - - break; - - case "AdError": - if(!handshakePerformed) - _vpaidMetadata.addValue(VPAIDMetadata.AD_ERROR,event); - break; - - case "AdLog": - var success:Boolean = false; - try - { - if (event.hasOwnProperty("data")) - { - if (event.data.hasOwnProperty("message")) - { - var msg:String = event.data.message.toString(); - if (msg != null) - { - CONFIG::LOGGING - { - logger.debug("[VPAID creative] " + msg); - } - success = true; - } - } - } - } - catch(e:Event) - { - } - - CONFIG::LOGGING - { - if (success == false) - { - logger.debug("[VPAID] Invalid AdLog event sent from creative. event.data not defined. Check creative."); - } - } - break; - - } - - } - - //The creative needs height and width to scale to. - private function getDimensions():Rectangle - { - var height:int; - var width:int; - - var vpaidContainer:MediaContainer = container as MediaContainer; - var displayObject:DisplayObjectTrait = this.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; - - if(vpaidContainer != null){ - width = vpaidContainer.width; - height = vpaidContainer.height; - //Sometimes we can't find the container - }else if(displayObject != null){ - width = displayObject.mediaWidth; - height = displayObject.mediaHeight; - //Default to size of the creative coming into the VPAIDElement - }else if (_MASTWidth > -1) - { - // Not sure why this works for MAST (except if you resize the container) - width = _MASTWidth; - height = _MASTHeight; - } - else{ - width = _loadTrait.loader.contentLoaderInfo.content.width; - height = _loadTrait.loader.contentLoaderInfo.content.height; - } - - CONFIG::LOGGING - { - logger.debug("[VPAID] getDimensions width:" + width + " height: " + height); - } - - return new Rectangle(0,0,width, height); - } - - //collapses or expands Ad based on the parameter passed to it - private function collapseAd(value:Boolean):void - { - if(value) - { - _vpaid.collapseVPAID(); - _vpaidMetadata.addValue(VPAIDMetadata.AD_COLLAPSE, true); - } - else - { - _vpaid.expandVPAID(); - _vpaidMetadata.addValue(VPAIDMetadata.AD_EXPAND, true); - } - - } - - //removes all event listeners - private function removeListeners():void - { - - - removeEventListener("AdStarted", onAdStarted); - removeEventListener("AdLoaded", onAdLoaded); - removeEventListener("AdStopped", onAdStopped); - removeEventListener("AdError", onAdStopped); - removeEventListener("AdRemainingTimeChange", onAdTimeChange); - removeEventListener("AdLinearChange", onAdLinearChange); - - removeEventListener("AdExpandedChange", onAdExpandedChange) - removeEventListener("AdClickThru", onClickThruChange); - removeEventListener("AdUserAcceptInvitation", onVPAIDEventReceived); - removeEventListener("AdUserMinimize", onVPAIDEventReceived); - removeEventListener("AdUserClose", onVPAIDEventReceived); - - removeEventListener("AdCreativeView", onVPAIDEventReceived); - - removeEventListener("AdPlaying", onAdPlayPause); - removeEventListener("AdPaused", onAdPlayPause); - removeEventListener("AdImpression", onVPAIDEventReceived); - removeEventListener("AdVolumeChange", onVPAIDEventReceived); - removeEventListener("AdVideoStart", onVPAIDEventReceived); - removeEventListener("AdVideoFirstQuartile", onVPAIDEventReceived); - removeEventListener("AdVideoMidpoint", onVPAIDEventReceived); - removeEventListener("AdVideoThridQuartile", onVPAIDEventReceived); - removeEventListener("AdVideoComplete", onVPAIDEventReceived); - - _audioTrait.removeEventListener(AudioEvent.MUTED_CHANGE, onAudioChange); - _audioTrait.removeEventListener(AudioEvent.VOLUME_CHANGE, onAudioChange); - _playTrait.removeEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); - - _vpaidMetadata.removeEventListener(MetadataEvent.VALUE_CHANGE, onMetadataValueChanged); - _vpaidMetadata.removeEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); - _vpaidMetadata.removeEventListener(MetadataEvent.VALUE_REMOVE, onMetadataValueRemoved); - _loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - if(_timeTrait) - { - _timeTrait.removeEventListener(TimeEvent.COMPLETE, onTimerChange); - _timeTrait.removeEventListener(TimeEvent.DURATION_CHANGE, onTimerChange); - } - } - - //The VPAID swf is loaded, time to start up the VPAID before dispatching READY - private function onSWFLoad(event:VPAIDLoadEvent):void - { - CONFIG::LOGGING - { - logger.debug("[VPAID] Initalizing VPAID"); - } - _loadTrait.removeEventListener(VPAIDLoadEvent.INITIALIZE_VPAID, onSWFLoad); - vpaidHandshakeTest(); - } - - private function onLoadStateChange(event:LoadEvent):void - { - CONFIG::LOGGING - { - logger.debug("[VPAID] LoadState Change: " + event.loadState); - } - if(event.loadState == LoadState.READY) - { - _vpaid.resizeVPAID(getDimensions().width,getDimensions().height, "normal"); - } - - } - - private function onTimerChange(event:TimeEvent):void - { - //trace(event.type +"time: "+ event.time); - } - - private function onPlayStateChange(event:PlayEvent):void - { - //Do not react to playstate changes for nonlinear creatives because you can't play/pause the creative - CONFIG::LOGGING - { - logger.debug("[VPAID] PlayState Change: " + event.playState); - } - var nonlinear:Boolean = _vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE); - - - switch(event.playState) - { - case PlayState.PLAYING: - if(_firstRun){ - _firstRun = false; - _vpaid.startVPAID(); - }else if(!nonlinear){ - _vpaid.resumeVPAID(); - } - break; - case PlayState.PAUSED: - if(!nonlinear) - _vpaid.pauseVPAID(); - break; - case PlayState.STOPPED: - _vpaid.stopVPAID(); - - if(_vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) - cleanUp(); - break; - } - } - - private function onAudioChange(event:AudioEvent):void { - if(event.type == AudioEvent.MUTED_CHANGE ) - { - CONFIG::LOGGING - { - logger.debug("[VPAID] Audio Change: event.muted=" + event.muted); - } - if(event.muted) - _vpaid.volumeVPAID = 0; - else - _vpaid.volumeVPAID = _audioTrait.volume; - }else{ - CONFIG::LOGGING - { - logger.debug("[VPAID] Audio Change: event.volume=" + event.volume); - } - _vpaid.volumeVPAID = event.volume; - _vpaidMetadata.addValue(VPAIDMetadata.AD_VOLUME_CHANGE, event.volume); - } - - } - - private function onMetadataValueChanged(e:MetadataEvent):void - { - switch(e.key) - { - - case VPAIDMetadata.RESIZE_AD : - var dataObj:Object = e.value as Object; - _vpaid.resizeVPAID(dataObj.width, dataObj.height, dataObj.viewMode); - break; - - case VPAIDMetadata.COLLAPSE_AD : - var collapse:Boolean = e.value as Boolean; - collapseAd(collapse); - break; - - case VPAIDMetadata.NON_LINEAR_CREATIVE : - - break; - } - } - - private function onMetadataValueAdded(e:MetadataEvent):void - { - - switch(e.key) - { - - case VPAIDMetadata.RESIZE_AD : - var dataObj:Object = e.value as Object; - _vpaid.resizeVPAID(dataObj.width, dataObj.height, dataObj.viewMode); - break; - - case VPAIDMetadata.COLLAPSE_AD : - var collapse:Boolean = e.value as Boolean; - collapseAd(collapse); - break; - - - case VPAIDMetadata.AD_LINEAR : - - break; - - case VPAIDMetadata.NON_LINEAR_CREATIVE : - - break; - - } - } - - private function onMetadataValueRemoved(e:MetadataEvent):void - { - switch(e.key) - { - - case VPAIDMetadata.RESIZE_AD : - - break; - - case VPAIDMetadata.COLLAPSE_AD : - - break; - - case VPAIDMetadata.AD_EXPANDED : - - break; - - case VPAIDMetadata.AD_LINEAR : - - break; - - case VPAIDMetadata.NON_LINEAR_CREATIVE : - - break; - - } - } - - //Need to create a customer loaderTrait so we can delay the READY until the VPAID creative sends out AdLoaded Event - override protected function createLoadTrait(resource:MediaResourceBase, loader:LoaderBase):LoadTrait - { - return new VPAIDLoadTrait(loader, resource); - } - - override protected function processUnloadingState():void - { - CONFIG::LOGGING - { - logger.debug("[VPAID] VPAIDElement.ProcessUnloadingState"); - } - removeTrait(MediaTraitType.DISPLAY_OBJECT); - } - - /** - * @private - */ - override protected function processReadyState():void - { - //Do nothing, because we add the creative swf to the DisplayObjectTrait when the ad calls AdStarted. - } - - - //We can now dispatch READY and change the PlayState to Playing if the player wants us to play. - private function onAdLoaded(event:Event):void - { - CONFIG::LOGGING - { - logger.debug("[VPAID] VPAIDElement.onAdLoaded() "); - } - - _vpaidMetadata.addValue(VPAIDMetadata.AD_CREATIVE_VIEW, event); - removeEventListener("AdLoaded", onAdLoaded); - _audioTrait.addEventListener(AudioEvent.MUTED_CHANGE, onAudioChange); - _audioTrait.addEventListener(AudioEvent.VOLUME_CHANGE, onAudioChange); - _vpaid.volumeVPAID = _audioTrait.volume; - _vpaidMetadata.addValue(VPAIDMetadata.AD_EXPANDED, _vpaid.expandedVPAID); - - if(_playTrait.playState == PlayState.PLAYING || _vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) - { - if(_firstRun){ - _firstRun = false; - _vpaid.startVPAID(); - } - } - - _playTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); - - - _loadTrait.vpaidReady(); - - - } - - private function onAdStopped(event:Event):void - { - _vpaidMetadata.addValue(VPAIDMetadata.AD_STOPPED, event); - if(_timeTrait) - _timeTrait.updateRemainingTime(0); - - if(!_vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) - cleanUp(); - } - - //Add the SWF to the display list and resize the Ad after it is started to get new values - private function onAdStarted(event:Event):void - { - - removeEventListener("AdStarted", onAdStarted); - var loaderLoadTrait:LoaderLoadTrait = getTrait(MediaTraitType.LOAD) as LoaderLoadTrait; - addTrait(MediaTraitType.DISPLAY_OBJECT, LoaderUtils.createDisplayObjectTrait(loaderLoadTrait.loader, this)); - _vpaid.resizeVPAID(getDimensions().width, getDimensions().height, "normal"); - } - - private function onAdTimeChange(event:Event):void - { - - if(_vpaid.remainingTimeVPAID >= 0 && _timeTrait != null) - _timeTrait.updateRemainingTime(_vpaid.remainingTimeVPAID); - } - - private function onAdLinearChange(event:Event):void - { - CONFIG::LOGGING - { - logger.debug("[VPAID] onAdLinearChange"); - } - - _vpaidMetadata.addValue(VPAIDMetadata.AD_LINEAR, _vpaid.linearVPAID); - if(_vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) - { - if(_vpaid.linearVPAID) - { - //Pause content video - _playTrait.pause(); - }else{ - //Play content video - _playTrait.play(); - } - return; - } - - if(_timeTrait != null ) - { - if(_vpaid.linearVPAID){ - _timeTrait.resumeTimer(); - }else{ - _timeTrait.pauseTimer(); - } - } - - } - - private function onAdExpandedChange(event:Event):void - { - - _vpaidMetadata.addValue(VPAIDMetadata.AD_EXPANDED, _vpaid.expandedVPAID); - } - - private function onClickThruChange(event:Event):void - { - _vpaidMetadata.addValue(VPAIDMetadata.AD_CLICKTRK, event); - } - - - private function onAdPlayPause(event:Event):void - { - if(_vpaid.linearVPAID) - { - if(_timeTrait) - { - if(event.type == "AdPaused") - { - _timeTrait.pauseTimer(); - _vpaidMetadata.addValue(VPAIDMetadata.AD_PAUSED, event); - } - - if(event.type == "AdPlaying") - { - _timeTrait.resumeTimer(); - _vpaidMetadata.addValue(VPAIDMetadata.AD_PLAYING, event); - } - - } - - } - } - - private function cleanUp():void - { - if(_playTrait.playState != PlayState.STOPPED) - _playTrait.stop(); - - _loadTrait.unload(); - - removeListeners(); - - } - - /** - * Prints out the error message and cleans up the current VPAIDElement. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function error(message:String = ""):void - { - CONFIG::LOGGING - { - logger.debug("[VPAID] Error: " + message); - } - cleanUp(); - } - - /** - * Provides access to the VPAIDMetadata associated with this VPAIDElemnt - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function vpaidMetadata():VPAIDMetadata - { - return _vpaidMetadata; - } - - private var handshakePerformed:Boolean = false; - private var _suppressPlaying:Boolean = true; - private var _playTrait:PlayTrait; - private var _loadTrait:VPAIDLoadTrait; - private var _timeTrait:VPAIDTimeTrait; - private var _audioTrait:AudioTrait; - private var _vpaidMetadata:VPAIDMetadata; - private var _vpaid:IVPAIDBase; - private var _supportedVersion:Array = ["1.1"]; - private var _firstRun:Boolean = true; - - // Just temporary, for MASTProxyElement to make initial size be correct(should use Metadata in the future) - private var _MASTWidth:Number = -1; - private var _MASTHeight:Number = -1; - public function get MASTWidth():Number - { - return _MASTWidth; - } - public function get MASTHeight():Number - { - return _MASTHeight; - } - public function set MASTWidth(val:Number):void - { - _MASTWidth = val; - } - public function set MASTHeight(val:Number):void - { - _MASTHeight = val; - } - - CONFIG::LOGGING - private static const logger:Logger = Log.getLogger("org.osmf.vpaid.elements.VPAIDElement"); - } - -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.elements +{ + import flash.events.Event; + import flash.geom.Rectangle; + import flash.system.Security; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.SWFElement; + import org.osmf.elements.SWFLoader; + import org.osmf.elements.loaderClasses.LoaderLoadTrait; + import org.osmf.elements.loaderClasses.LoaderUtils; + import org.osmf.events.AudioEvent; + import org.osmf.events.LoadEvent; + import org.osmf.events.MetadataEvent; + import org.osmf.events.PlayEvent; + import org.osmf.events.TimeEvent; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.URLResource; + import org.osmf.traits.AudioTrait; + import org.osmf.traits.DisplayObjectTrait; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoaderBase; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayState; + import org.osmf.traits.PlayTrait; + import org.osmf.vpaid.events.VPAIDLoadEvent; + import org.osmf.vpaid.metadata.VPAIDMetadata; + import org.osmf.vpaid.model.IVPAIDBase; + import org.osmf.vpaid.model.VPAID_1_1; + import org.osmf.vpaid.traits.VPAIDLoadTrait; + import org.osmf.vpaid.traits.VPAIDTimeTrait; + + CONFIG::LOGGING + { + import org.osmf.logging.Logger; + import org.osmf.logging.Log; + } + + /** + * VPAIDElement is a media element specifically created for presenting IAB compliant VPAID SWFs. + *

      The VPAIDElement uses a standard SWFLoader class to load and unload its media.

      + * + * @see org.osmf.elements.SWFLoader + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + + public class VPAIDElement extends SWFElement + { + public function VPAIDElement(resource:URLResource, loader:SWFLoader = null) + { + Security.allowDomain("*"); + super(resource, loader); + + _vpaidMetadata = new VPAIDMetadata(); + _vpaidMetadata.addEventListener(MetadataEvent.VALUE_CHANGE, onMetadataValueChanged); + _vpaidMetadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); + _vpaidMetadata.addEventListener(MetadataEvent.VALUE_REMOVE, onMetadataValueRemoved); + addMetadata(VPAIDMetadata.NAMESPACE, _vpaidMetadata); + + _loadTrait = getTrait(MediaTraitType.LOAD) as VPAIDLoadTrait; + _loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + _loadTrait.addEventListener(VPAIDLoadEvent.INITIALIZE_VPAID, onSWFLoad); + + _playTrait = new PlayTrait(); + addTrait(MediaTraitType.PLAY, _playTrait); + + _audioTrait = new AudioTrait(); + addTrait(MediaTraitType.AUDIO, _audioTrait); + + + } + + //Once the SWF is loaded we need to figure out the VPAID version + //the creative supports and the load the correct module. + private function vpaidHandshakeTest():void + { + var _testResult:Boolean = false; + for each (var version:String in _supportedVersion) + { + CONFIG::LOGGING + { + logger.debug("[VPAID] Testing HandshakeVersion: "+ version); + } + if (_testResult == false){ + _testResult = probeVersion(version); + }else{ + break; + } + } + if (_testResult){ + //found a handshake + CONFIG::LOGGING + { + logger.debug("[VPAID] Matching HandshakeVersion, ad responded: "+ _vpaid.version +" - ok"); + } + //Module is ready time to initalize the creative. + initVPAID(); + }else{ + CONFIG::LOGGING + { + logger.debug("[VPAID] Unsupported VPAID API version "); + } + _vpaidMetadata.addValue(VPAIDMetadata.ERROR, VPAIDMetadata.ERROR); + removeListeners(); + } + } + + private function probeVersion(versionToTest:String):Boolean + { + var result:Boolean = false; + var vpaidSWF:Object = _loadTrait.loader.contentLoaderInfo.content; + + switch(versionToTest) + { + case "1.0": + //TODO: Add support for VPAID 1.0 + break; + case "1.1": + _vpaid = new VPAID_1_1(vpaidSWF, this); + result = _vpaid.probeVersion(); + handshakePerformed = true; + break; + } + return result; + } + + //Need to add listeners to important VPAID events once the creative is initalized + private function initVPAID():void + { + + addEventListener("AdStarted", onAdStarted); + addEventListener("AdLoaded", onAdLoaded); + addEventListener("AdStopped", onAdStopped); + + addEventListener("AdRemainingTimeChange", onAdTimeChange); + addEventListener("AdLinearChange", onAdLinearChange); + + addEventListener("AdExpandedChange", onAdExpandedChange) + addEventListener("AdClickThru", onClickThruChange); + addEventListener("AdUserAcceptInvitation", onVPAIDEventReceived); + addEventListener("AdUserMinimize", onVPAIDEventReceived); + addEventListener("AdUserClose", onVPAIDEventReceived); + + addEventListener("AdCreativeView", onVPAIDEventReceived); + + addEventListener("AdPlaying", onAdPlayPause); + addEventListener("AdPaused", onAdPlayPause); + addEventListener("AdImpression", onVPAIDEventReceived); + addEventListener("AdVolumeChange", onVPAIDEventReceived); + addEventListener("AdVideoStart", onVPAIDEventReceived); + addEventListener("AdVideoFirstQuartile", onVPAIDEventReceived); + addEventListener("AdVideoMidpoint", onVPAIDEventReceived); + addEventListener("AdVideoThirdQuartile", onVPAIDEventReceived); + addEventListener("AdVideoComplete", onVPAIDEventReceived); + addEventListener("AdLog", onVPAIDEventReceived); + addEventListener("AdError", onVPAIDEventReceived); + + + //pre VPAID specifciation diagram, we need to get the linear state of the creative before we call initAd + _vpaidMetadata.addValue(VPAIDMetadata.AD_LINEAR, _vpaid.linearVPAID); + //This stores the inital linear start of the creative so that we can see if it is a linear (preroll) or nonlinear (ticker) creative. + //It can also be set by the publisher if they know were in the content video this creative is placed. + _vpaidMetadata.addValue(VPAIDMetadata.NON_LINEAR_CREATIVE, !_vpaid.linearVPAID); + + if(_vpaid.linearVPAID) + { + //only add time trait for linear ads + _timeTrait = new VPAIDTimeTrait(); + addTrait(MediaTraitType.TIME, _timeTrait); + + _timeTrait.addEventListener(TimeEvent.COMPLETE, onTimerChange); + _timeTrait.addEventListener(TimeEvent.DURATION_CHANGE, onTimerChange); + } + + _vpaid.initVPAID(getDimensions().width,getDimensions().height,"normal", 500, "", ""); + } + + private function onVPAIDEventReceived(event:Object):void + { + CONFIG::LOGGING + { + logger.debug("[VPAID] onVPAIDEventReceived: event.type=" + event.type); + } + switch(event.type) + { + + case "AdCreativeView": + _vpaidMetadata.addValue(VPAIDMetadata.AD_CREATIVE_VIEW, event); + break; + + case "AdImpression": + _vpaidMetadata.addValue(VPAIDMetadata.AD_IMPRESSION, event); + break; + + case "AdVideoStart": + _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_START, event); + break; + + case "AdVideoFirstQuartile": + _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_FIRST_QUARTILE, event); + break; + + case "AdVideoMidpoint": + _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_MID_POINT, event); + break; + + case "AdVideoThirdQuartile": + _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_THIRD_QUARTILE, event); + break; + + case "AdVideoComplete": + _vpaidMetadata.addValue(VPAIDMetadata.AD_VIDEO_COMPLETE,event); + break; + + case"AdUserAcceptInvitation": + + _vpaidMetadata.addValue(VPAIDMetadata.AD_USER_ACCEPT_INVITATION, event); + break; + + case"AdUserMinimize": + + _vpaidMetadata.addValue(VPAIDMetadata.AD_USER_MINIMIZE, event); + break; + + case"AdUserClose": + + _vpaidMetadata.addValue(VPAIDMetadata.AD_USER_CLOSE, event); + + break; + + case "AdError": + if(!handshakePerformed) + _vpaidMetadata.addValue(VPAIDMetadata.AD_ERROR,event); + break; + + case "AdLog": + var success:Boolean = false; + try + { + if (event.hasOwnProperty("data")) + { + if (event.data.hasOwnProperty("message")) + { + var msg:String = event.data.message.toString(); + if (msg != null) + { + CONFIG::LOGGING + { + logger.debug("[VPAID creative] " + msg); + } + success = true; + } + } + } + } + catch(e:Event) + { + } + + CONFIG::LOGGING + { + if (success == false) + { + logger.debug("[VPAID] Invalid AdLog event sent from creative. event.data not defined. Check creative."); + } + } + break; + + } + + } + + //The creative needs height and width to scale to. + private function getDimensions():Rectangle + { + var height:int; + var width:int; + + var vpaidContainer:MediaContainer = container as MediaContainer; + var displayObject:DisplayObjectTrait = this.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait; + + if(vpaidContainer != null){ + width = vpaidContainer.width; + height = vpaidContainer.height; + //Sometimes we can't find the container + }else if(displayObject != null){ + width = displayObject.mediaWidth; + height = displayObject.mediaHeight; + //Default to size of the creative coming into the VPAIDElement + }else if (_MASTWidth > -1) + { + // Not sure why this works for MAST (except if you resize the container) + width = _MASTWidth; + height = _MASTHeight; + } + else{ + width = _loadTrait.loader.contentLoaderInfo.content.width; + height = _loadTrait.loader.contentLoaderInfo.content.height; + } + + CONFIG::LOGGING + { + logger.debug("[VPAID] getDimensions width:" + width + " height: " + height); + } + + return new Rectangle(0,0,width, height); + } + + //collapses or expands Ad based on the parameter passed to it + private function collapseAd(value:Boolean):void + { + if(value) + { + _vpaid.collapseVPAID(); + _vpaidMetadata.addValue(VPAIDMetadata.AD_COLLAPSE, true); + } + else + { + _vpaid.expandVPAID(); + _vpaidMetadata.addValue(VPAIDMetadata.AD_EXPAND, true); + } + + } + + //removes all event listeners + private function removeListeners():void + { + + + removeEventListener("AdStarted", onAdStarted); + removeEventListener("AdLoaded", onAdLoaded); + removeEventListener("AdStopped", onAdStopped); + removeEventListener("AdError", onAdStopped); + removeEventListener("AdRemainingTimeChange", onAdTimeChange); + removeEventListener("AdLinearChange", onAdLinearChange); + + removeEventListener("AdExpandedChange", onAdExpandedChange) + removeEventListener("AdClickThru", onClickThruChange); + removeEventListener("AdUserAcceptInvitation", onVPAIDEventReceived); + removeEventListener("AdUserMinimize", onVPAIDEventReceived); + removeEventListener("AdUserClose", onVPAIDEventReceived); + + removeEventListener("AdCreativeView", onVPAIDEventReceived); + + removeEventListener("AdPlaying", onAdPlayPause); + removeEventListener("AdPaused", onAdPlayPause); + removeEventListener("AdImpression", onVPAIDEventReceived); + removeEventListener("AdVolumeChange", onVPAIDEventReceived); + removeEventListener("AdVideoStart", onVPAIDEventReceived); + removeEventListener("AdVideoFirstQuartile", onVPAIDEventReceived); + removeEventListener("AdVideoMidpoint", onVPAIDEventReceived); + removeEventListener("AdVideoThridQuartile", onVPAIDEventReceived); + removeEventListener("AdVideoComplete", onVPAIDEventReceived); + + _audioTrait.removeEventListener(AudioEvent.MUTED_CHANGE, onAudioChange); + _audioTrait.removeEventListener(AudioEvent.VOLUME_CHANGE, onAudioChange); + _playTrait.removeEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); + + _vpaidMetadata.removeEventListener(MetadataEvent.VALUE_CHANGE, onMetadataValueChanged); + _vpaidMetadata.removeEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); + _vpaidMetadata.removeEventListener(MetadataEvent.VALUE_REMOVE, onMetadataValueRemoved); + _loadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + if(_timeTrait) + { + _timeTrait.removeEventListener(TimeEvent.COMPLETE, onTimerChange); + _timeTrait.removeEventListener(TimeEvent.DURATION_CHANGE, onTimerChange); + } + } + + //The VPAID swf is loaded, time to start up the VPAID before dispatching READY + private function onSWFLoad(event:VPAIDLoadEvent):void + { + CONFIG::LOGGING + { + logger.debug("[VPAID] Initalizing VPAID"); + } + _loadTrait.removeEventListener(VPAIDLoadEvent.INITIALIZE_VPAID, onSWFLoad); + vpaidHandshakeTest(); + } + + private function onLoadStateChange(event:LoadEvent):void + { + CONFIG::LOGGING + { + logger.debug("[VPAID] LoadState Change: " + event.loadState); + } + if(event.loadState == LoadState.READY) + { + _vpaid.resizeVPAID(getDimensions().width,getDimensions().height, "normal"); + } + + } + + private function onTimerChange(event:TimeEvent):void + { + //trace(event.type +"time: "+ event.time); + } + + private function onPlayStateChange(event:PlayEvent):void + { + //Do not react to playstate changes for nonlinear creatives because you can't play/pause the creative + CONFIG::LOGGING + { + logger.debug("[VPAID] PlayState Change: " + event.playState); + } + var nonlinear:Boolean = _vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE); + + + switch(event.playState) + { + case PlayState.PLAYING: + if(_firstRun){ + _firstRun = false; + _vpaid.startVPAID(); + }else if(!nonlinear){ + _vpaid.resumeVPAID(); + } + break; + case PlayState.PAUSED: + if(!nonlinear) + _vpaid.pauseVPAID(); + break; + case PlayState.STOPPED: + _vpaid.stopVPAID(); + + if(_vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) + cleanUp(); + break; + } + } + + private function onAudioChange(event:AudioEvent):void { + if(event.type == AudioEvent.MUTED_CHANGE ) + { + CONFIG::LOGGING + { + logger.debug("[VPAID] Audio Change: event.muted=" + event.muted); + } + if(event.muted) + _vpaid.volumeVPAID = 0; + else + _vpaid.volumeVPAID = _audioTrait.volume; + }else{ + CONFIG::LOGGING + { + logger.debug("[VPAID] Audio Change: event.volume=" + event.volume); + } + _vpaid.volumeVPAID = event.volume; + _vpaidMetadata.addValue(VPAIDMetadata.AD_VOLUME_CHANGE, event.volume); + } + + } + + private function onMetadataValueChanged(e:MetadataEvent):void + { + switch(e.key) + { + + case VPAIDMetadata.RESIZE_AD : + var dataObj:Object = e.value as Object; + _vpaid.resizeVPAID(dataObj.width, dataObj.height, dataObj.viewMode); + break; + + case VPAIDMetadata.COLLAPSE_AD : + var collapse:Boolean = e.value as Boolean; + collapseAd(collapse); + break; + + case VPAIDMetadata.NON_LINEAR_CREATIVE : + + break; + } + } + + private function onMetadataValueAdded(e:MetadataEvent):void + { + + switch(e.key) + { + + case VPAIDMetadata.RESIZE_AD : + var dataObj:Object = e.value as Object; + _vpaid.resizeVPAID(dataObj.width, dataObj.height, dataObj.viewMode); + break; + + case VPAIDMetadata.COLLAPSE_AD : + var collapse:Boolean = e.value as Boolean; + collapseAd(collapse); + break; + + + case VPAIDMetadata.AD_LINEAR : + + break; + + case VPAIDMetadata.NON_LINEAR_CREATIVE : + + break; + + } + } + + private function onMetadataValueRemoved(e:MetadataEvent):void + { + switch(e.key) + { + + case VPAIDMetadata.RESIZE_AD : + + break; + + case VPAIDMetadata.COLLAPSE_AD : + + break; + + case VPAIDMetadata.AD_EXPANDED : + + break; + + case VPAIDMetadata.AD_LINEAR : + + break; + + case VPAIDMetadata.NON_LINEAR_CREATIVE : + + break; + + } + } + + //Need to create a customer loaderTrait so we can delay the READY until the VPAID creative sends out AdLoaded Event + override protected function createLoadTrait(resource:MediaResourceBase, loader:LoaderBase):LoadTrait + { + return new VPAIDLoadTrait(loader, resource); + } + + override protected function processUnloadingState():void + { + CONFIG::LOGGING + { + logger.debug("[VPAID] VPAIDElement.ProcessUnloadingState"); + } + removeTrait(MediaTraitType.DISPLAY_OBJECT); + } + + /** + * @private + */ + override protected function processReadyState():void + { + //Do nothing, because we add the creative swf to the DisplayObjectTrait when the ad calls AdStarted. + } + + + //We can now dispatch READY and change the PlayState to Playing if the player wants us to play. + private function onAdLoaded(event:Event):void + { + CONFIG::LOGGING + { + logger.debug("[VPAID] VPAIDElement.onAdLoaded() "); + } + + _vpaidMetadata.addValue(VPAIDMetadata.AD_CREATIVE_VIEW, event); + removeEventListener("AdLoaded", onAdLoaded); + _audioTrait.addEventListener(AudioEvent.MUTED_CHANGE, onAudioChange); + _audioTrait.addEventListener(AudioEvent.VOLUME_CHANGE, onAudioChange); + _vpaid.volumeVPAID = _audioTrait.volume; + _vpaidMetadata.addValue(VPAIDMetadata.AD_EXPANDED, _vpaid.expandedVPAID); + + if(_playTrait.playState == PlayState.PLAYING || _vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) + { + if(_firstRun){ + _firstRun = false; + _vpaid.startVPAID(); + } + } + + _playTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); + + + _loadTrait.vpaidReady(); + + + } + + private function onAdStopped(event:Event):void + { + _vpaidMetadata.addValue(VPAIDMetadata.AD_STOPPED, event); + if(_timeTrait) + _timeTrait.updateRemainingTime(0); + + if(!_vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) + cleanUp(); + } + + //Add the SWF to the display list and resize the Ad after it is started to get new values + private function onAdStarted(event:Event):void + { + + removeEventListener("AdStarted", onAdStarted); + var loaderLoadTrait:LoaderLoadTrait = getTrait(MediaTraitType.LOAD) as LoaderLoadTrait; + addTrait(MediaTraitType.DISPLAY_OBJECT, LoaderUtils.createDisplayObjectTrait(loaderLoadTrait.loader, this)); + _vpaid.resizeVPAID(getDimensions().width, getDimensions().height, "normal"); + } + + private function onAdTimeChange(event:Event):void + { + + if(_vpaid.remainingTimeVPAID >= 0 && _timeTrait != null) + _timeTrait.updateRemainingTime(_vpaid.remainingTimeVPAID); + } + + private function onAdLinearChange(event:Event):void + { + CONFIG::LOGGING + { + logger.debug("[VPAID] onAdLinearChange"); + } + + _vpaidMetadata.addValue(VPAIDMetadata.AD_LINEAR, _vpaid.linearVPAID); + if(_vpaidMetadata.getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) + { + if(_vpaid.linearVPAID) + { + //Pause content video + _playTrait.pause(); + }else{ + //Play content video + _playTrait.play(); + } + return; + } + + if(_timeTrait != null ) + { + if(_vpaid.linearVPAID){ + _timeTrait.resumeTimer(); + }else{ + _timeTrait.pauseTimer(); + } + } + + } + + private function onAdExpandedChange(event:Event):void + { + + _vpaidMetadata.addValue(VPAIDMetadata.AD_EXPANDED, _vpaid.expandedVPAID); + } + + private function onClickThruChange(event:Event):void + { + _vpaidMetadata.addValue(VPAIDMetadata.AD_CLICKTRK, event); + } + + + private function onAdPlayPause(event:Event):void + { + if(_vpaid.linearVPAID) + { + if(_timeTrait) + { + if(event.type == "AdPaused") + { + _timeTrait.pauseTimer(); + _vpaidMetadata.addValue(VPAIDMetadata.AD_PAUSED, event); + } + + if(event.type == "AdPlaying") + { + _timeTrait.resumeTimer(); + _vpaidMetadata.addValue(VPAIDMetadata.AD_PLAYING, event); + } + + } + + } + } + + private function cleanUp():void + { + if(_playTrait.playState != PlayState.STOPPED) + _playTrait.stop(); + + _loadTrait.unload(); + + removeListeners(); + + } + + /** + * Prints out the error message and cleans up the current VPAIDElement. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function error(message:String = ""):void + { + CONFIG::LOGGING + { + logger.debug("[VPAID] Error: " + message); + } + cleanUp(); + } + + /** + * Provides access to the VPAIDMetadata associated with this VPAIDElemnt + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function vpaidMetadata():VPAIDMetadata + { + return _vpaidMetadata; + } + + private var handshakePerformed:Boolean = false; + private var _suppressPlaying:Boolean = true; + private var _playTrait:PlayTrait; + private var _loadTrait:VPAIDLoadTrait; + private var _timeTrait:VPAIDTimeTrait; + private var _audioTrait:AudioTrait; + private var _vpaidMetadata:VPAIDMetadata; + private var _vpaid:IVPAIDBase; + private var _supportedVersion:Array = ["1.1"]; + private var _firstRun:Boolean = true; + + // Just temporary, for MASTProxyElement to make initial size be correct(should use Metadata in the future) + private var _MASTWidth:Number = -1; + private var _MASTHeight:Number = -1; + public function get MASTWidth():Number + { + return _MASTWidth; + } + public function get MASTHeight():Number + { + return _MASTHeight; + } + public function set MASTWidth(val:Number):void + { + _MASTWidth = val; + } + public function set MASTHeight(val:Number):void + { + _MASTHeight = val; + } + + CONFIG::LOGGING + private static const logger:Logger = Log.getLogger("org.osmf.vpaid.elements.VPAIDElement"); + } + +} diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/events/VPAIDEvent.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/events/VPAIDEvent.as index f44a6fb..0bab5dd 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/events/VPAIDEvent.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/events/VPAIDEvent.as @@ -1,69 +1,69 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.events -{ - import flash.events.Event; - - /** - * An VPAIDEvent is the type of event that should be passed by the VPAID creative. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - - public class VPAIDEvent extends Event - { - public static const AdLoaded : String = "AdLoaded"; - public static const AdStarted : String = "AdStarted"; - public static const AdStopped : String = "AdStopped"; - public static const AdLinearChange : String = "AdLinearChange"; - public static const AdExpandedChange : String = "AdExpandedChange"; - public static const AdRemainingTimeChange : String= "AdRemainingTimeChange"; - public static const AdVolumeChange : String = "AdVolumeChange"; - public static const AdImpression : String = "AdImpression"; - public static const AdVideoStart : String = "AdVideoStart"; - public static const AdVideoFirstQuartile : String= "AdVideoFirstQuartile"; - public static const AdVideoMidpoint : String = "AdVideoMidpoint"; - public static const AdVideoThirdQuartile : String= "AdVideoThirdQuartile"; - public static const AdVideoComplete : String = "AdVideoComplete"; - public static const AdClickThru : String = "AdClickThru"; - public static const AdUserAcceptInvitation : String= "AdUserAcceptInvitation"; - public static const AdUserMinimize : String = "AdUserMinimize"; - public static const AdUserClose : String = "AdUserClose"; - public static const AdPaused : String = "AdPaused"; - public static const AdPlaying : String = "AdPlaying"; - public static const AdLog : String = "AdLog"; - public static const AdError : String = "AdError"; - private var _data:Object; - public function VPAIDEvent(type:String, data:Object=null, bubbles:Boolean=false,cancelable:Boolean=false) - { - super(type, bubbles, cancelable); - _data = data; - } - public function get data():Object - { - return _data; - } - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.events +{ + import flash.events.Event; + + /** + * An VPAIDEvent is the type of event that should be passed by the VPAID creative. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + + public class VPAIDEvent extends Event + { + public static const AdLoaded : String = "AdLoaded"; + public static const AdStarted : String = "AdStarted"; + public static const AdStopped : String = "AdStopped"; + public static const AdLinearChange : String = "AdLinearChange"; + public static const AdExpandedChange : String = "AdExpandedChange"; + public static const AdRemainingTimeChange : String= "AdRemainingTimeChange"; + public static const AdVolumeChange : String = "AdVolumeChange"; + public static const AdImpression : String = "AdImpression"; + public static const AdVideoStart : String = "AdVideoStart"; + public static const AdVideoFirstQuartile : String= "AdVideoFirstQuartile"; + public static const AdVideoMidpoint : String = "AdVideoMidpoint"; + public static const AdVideoThirdQuartile : String= "AdVideoThirdQuartile"; + public static const AdVideoComplete : String = "AdVideoComplete"; + public static const AdClickThru : String = "AdClickThru"; + public static const AdUserAcceptInvitation : String= "AdUserAcceptInvitation"; + public static const AdUserMinimize : String = "AdUserMinimize"; + public static const AdUserClose : String = "AdUserClose"; + public static const AdPaused : String = "AdPaused"; + public static const AdPlaying : String = "AdPlaying"; + public static const AdLog : String = "AdLog"; + public static const AdError : String = "AdError"; + private var _data:Object; + public function VPAIDEvent(type:String, data:Object=null, bubbles:Boolean=false,cancelable:Boolean=false) + { + super(type, bubbles, cancelable); + _data = data; + } + public function get data():Object + { + return _data; + } + } +} diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/events/VPAIDLoadEvent.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/events/VPAIDLoadEvent.as index 0e586c3..cefbdd6 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/events/VPAIDLoadEvent.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/events/VPAIDLoadEvent.as @@ -1,45 +1,45 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.events -{ - import flash.events.Event; - - /** - * An VPAIDLoadEvent is dispatched when the properties of a VPAIDLoadTrait change. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - - public class VPAIDLoadEvent extends Event - { - public function VPAIDLoadEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) - { - super(type, bubbles, cancelable); - } - - public static const INITIALIZE_VPAID:String = "InitalizeVPAID"; - public static const VPAID_READY:String = "VPAIDReady"; - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.events +{ + import flash.events.Event; + + /** + * An VPAIDLoadEvent is dispatched when the properties of a VPAIDLoadTrait change. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + + public class VPAIDLoadEvent extends Event + { + public function VPAIDLoadEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) + { + super(type, bubbles, cancelable); + } + + public static const INITIALIZE_VPAID:String = "InitalizeVPAID"; + public static const VPAID_READY:String = "VPAIDReady"; + } +} diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/media/IVPAID.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/media/IVPAID.as index 16cd7c7..00f0f68 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/media/IVPAID.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/media/IVPAID.as @@ -1,28 +1,28 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.media -{ - public interface IVPAID - { - - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.media +{ + public interface IVPAID + { + + } +} diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/metadata/VPAIDMetadata.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/metadata/VPAIDMetadata.as index 23c752c..425553e 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/metadata/VPAIDMetadata.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/metadata/VPAIDMetadata.as @@ -1,250 +1,250 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.metadata -{ - import org.osmf.metadata.Metadata; - - - /** - * Because some of VPAID's properties, methods, and events - * do not fit into OSMF's built in traits, this class is provided - * to allow publishers to access specific information such as - * adLinear, adExpanded, contactAd(), and expandAd() etc. - * - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public class VPAIDMetadata extends Metadata - { - - //VPAID Method and Property calls - /** - * An event dispatched when publishers want to call the collapseAd() function - */ - public static const COLLAPSE_AD:String = "collapseAd"; - - /** - * An event dispatched when publishers want to call the expandAd() function - */ - public static const EXPAND_AD:String = "expandAd"; - - /** - * An event dispatched when publishers want to call the resize() function - */ - public static const RESIZE_AD:String = "resizeAd"; - - /** - * An event dispatched when the creative's adLinear property is being changed - */ - public static const AD_LINEAR:String = "adLinear"; - - /** - * An event dispatched when the creative's adExpanded property is being changed - */ - public static const AD_EXPANDED:String = "adExpanded"; - - /** - * An event dispatched when... - */ - public static const NON_LINEAR_CREATIVE:String = "NonlinearCreative"; - - /** - * An event dispatched when the creative has finished loading - */ - public static const AD_LOADED:String = "adLoaded"; - - /** - * An event dispatched when the creative begins playing for the first - */ - public static const AD_STARTED:String = "adStarted"; - - /** - * An event dispatched in order to stop the ad. - * Usually results in the running of the stopAd() function - */ - public static const AD_STOPPED:String = "adStopped"; - - /** - * An event disptached with the purpose of stopping the ad and removing related - * event listeners and Objects. - * Results in the running of the endAd() function - */ - public static const END_AD:String = "endAd"; - - /** - * An event dispatched when any error occurs within the creative. - */ - public static const ERROR:String = "error"; - - /** - * An event that is dispatched whenever the time remaining in the playback of the creative - */ - public static const AD_REMAINING_TIME_CHANGE:String = "adRemainingTimeChange"; - - /** - * An event dispatched when the adLinear property has been changed - */ - public static const AD_LINEAR_CHANGE:String = "adLinearChange"; - - /** - * An event dispatched when the volume of the videoplayer running the VPAIDElement changes - */ - public static const AD_VOLUME_CHANGE:String = "adVolumeChange"; - - /** - * An event dispatched when the videoplayer running the VPAIDElement is paused - */ - public static const AD_PAUSED:String = "adPaused"; - - /** - * An event dispatched when the videoplayer running the VPAIDElement plays - */ - public static const AD_PLAYING:String = "adPlaying"; - - //Tracking - /** - * A tracking event dispatched when expandAd() runs. - */ - public static const AD_EXPAND:String = "adExpand"; - - /** - * A tracking event dispatched when collapseAd() runs. - */ - public static const AD_COLLAPSE:String = "adCollapse"; - - - /** - * A tracking event dispatched when the creative's Impression call is sent from the videoplayer - */ - public static const AD_IMPRESSION:String = "adImpression"; - - /** - * A tracking event dispatched when the video has started playback - */ - public static const AD_VIDEO_START:String = "adVideoStart"; - - /** - * A tracking event dispatched when the video has reached 25% completion - */ - public static const AD_VIDEO_FIRST_QUARTILE:String = "adVideoFirstQuartile"; - - /** - * A tracking event dispatched when the video has reached 75% completion - */ - public static const AD_VIDEO_THIRD_QUARTILE:String = "adVideoThirdQuartile"; - - /** - * A tracking event dispatched when the video has reached 50% completion - */ - public static const AD_VIDEO_MID_POINT:String = "adVideoMidpoint"; - - /** - * A tracking event dispatched when the video has reached 100% completion - */ - public static const AD_VIDEO_COMPLETE:String = "adVideoComplete"; - - - /** - * An event dispatched when an error occurs during the load or playback of the ad - */ - public static const AD_ERROR:String = "adError"; - - /** - * An event dispatched.... - */ - public static const AD_CREATIVE_VIEW:String = "adCreativeView"; - - - /** - * A tracking event dispatched when the user unmutes the creative - */ - public static const AD_UNMUTE:String = "adUnmute"; - - /** - * A tracking event dispatched when the user mutes the creative - */ - public static const AD_MUTE:String = "adMute"; - - /** - * A tracking event dispatched when the user seeks backwards in the creative - */ - public static const AD_REWIND:String = "adRewind"; - - /** - * A tracking event dispatched when the user resumes playing a paused creative - */ - public static const AD_RESUME:String = "adResume"; - - /** - * A tracking event dispatched when the user enters fullscreen - */ - public static const AD_FULLSCREEN:String = "adFullscreen"; - - /** - * A tracking event dispatched when the user peforms a clickthru on the creative - * Usually, this results in the user being taken to a new window where a new website will load. - */ - public static const AD_CLICKTRK:String = "adClickThru"; - - /** - * A tracking event dispatched when the user interacts with a creative. Usually by mousing over, clicking, - * or following whatever prompt the creative calls for in order to delve deeper into the advertsement. - */ - public static const AD_USER_ACCEPT_INVITATION:String = "adUserAcceptInvitation"; - - /** - * A tracking event dispatched when the user closes the creative. - * Only applicable to nonlinear creatives and linear interactive creatives. - */ - public static const AD_USER_CLOSE:String = "adUserClose"; - - /** - * A tracking event dispatched when the user minimizes the creative - */ - public static const AD_USER_MINIMIZE:String = "adUserMinimize"; - - /** - * A tracking event dispatched when creative is closed at the end of playback - * Only applicable to linear creatives - */ - public static const AD_CLOSE:String = "adClose"; - - - /** - * The package location of the VPAIDMetadata class - */ - public static const NAMESPACE:String = "org.osmf.vpaid.metadata.VPAIDMetadata"; - - /** - * Constructor - * - * @param - */ - public function VPAIDMetadata() - { - super(); - } - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.metadata +{ + import org.osmf.metadata.Metadata; + + + /** + * Because some of VPAID's properties, methods, and events + * do not fit into OSMF's built in traits, this class is provided + * to allow publishers to access specific information such as + * adLinear, adExpanded, contactAd(), and expandAd() etc. + * + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public class VPAIDMetadata extends Metadata + { + + //VPAID Method and Property calls + /** + * An event dispatched when publishers want to call the collapseAd() function + */ + public static const COLLAPSE_AD:String = "collapseAd"; + + /** + * An event dispatched when publishers want to call the expandAd() function + */ + public static const EXPAND_AD:String = "expandAd"; + + /** + * An event dispatched when publishers want to call the resize() function + */ + public static const RESIZE_AD:String = "resizeAd"; + + /** + * An event dispatched when the creative's adLinear property is being changed + */ + public static const AD_LINEAR:String = "adLinear"; + + /** + * An event dispatched when the creative's adExpanded property is being changed + */ + public static const AD_EXPANDED:String = "adExpanded"; + + /** + * An event dispatched when... + */ + public static const NON_LINEAR_CREATIVE:String = "NonlinearCreative"; + + /** + * An event dispatched when the creative has finished loading + */ + public static const AD_LOADED:String = "adLoaded"; + + /** + * An event dispatched when the creative begins playing for the first + */ + public static const AD_STARTED:String = "adStarted"; + + /** + * An event dispatched in order to stop the ad. + * Usually results in the running of the stopAd() function + */ + public static const AD_STOPPED:String = "adStopped"; + + /** + * An event disptached with the purpose of stopping the ad and removing related + * event listeners and Objects. + * Results in the running of the endAd() function + */ + public static const END_AD:String = "endAd"; + + /** + * An event dispatched when any error occurs within the creative. + */ + public static const ERROR:String = "error"; + + /** + * An event that is dispatched whenever the time remaining in the playback of the creative + */ + public static const AD_REMAINING_TIME_CHANGE:String = "adRemainingTimeChange"; + + /** + * An event dispatched when the adLinear property has been changed + */ + public static const AD_LINEAR_CHANGE:String = "adLinearChange"; + + /** + * An event dispatched when the volume of the videoplayer running the VPAIDElement changes + */ + public static const AD_VOLUME_CHANGE:String = "adVolumeChange"; + + /** + * An event dispatched when the videoplayer running the VPAIDElement is paused + */ + public static const AD_PAUSED:String = "adPaused"; + + /** + * An event dispatched when the videoplayer running the VPAIDElement plays + */ + public static const AD_PLAYING:String = "adPlaying"; + + //Tracking + /** + * A tracking event dispatched when expandAd() runs. + */ + public static const AD_EXPAND:String = "adExpand"; + + /** + * A tracking event dispatched when collapseAd() runs. + */ + public static const AD_COLLAPSE:String = "adCollapse"; + + + /** + * A tracking event dispatched when the creative's Impression call is sent from the videoplayer + */ + public static const AD_IMPRESSION:String = "adImpression"; + + /** + * A tracking event dispatched when the video has started playback + */ + public static const AD_VIDEO_START:String = "adVideoStart"; + + /** + * A tracking event dispatched when the video has reached 25% completion + */ + public static const AD_VIDEO_FIRST_QUARTILE:String = "adVideoFirstQuartile"; + + /** + * A tracking event dispatched when the video has reached 75% completion + */ + public static const AD_VIDEO_THIRD_QUARTILE:String = "adVideoThirdQuartile"; + + /** + * A tracking event dispatched when the video has reached 50% completion + */ + public static const AD_VIDEO_MID_POINT:String = "adVideoMidpoint"; + + /** + * A tracking event dispatched when the video has reached 100% completion + */ + public static const AD_VIDEO_COMPLETE:String = "adVideoComplete"; + + + /** + * An event dispatched when an error occurs during the load or playback of the ad + */ + public static const AD_ERROR:String = "adError"; + + /** + * An event dispatched.... + */ + public static const AD_CREATIVE_VIEW:String = "adCreativeView"; + + + /** + * A tracking event dispatched when the user unmutes the creative + */ + public static const AD_UNMUTE:String = "adUnmute"; + + /** + * A tracking event dispatched when the user mutes the creative + */ + public static const AD_MUTE:String = "adMute"; + + /** + * A tracking event dispatched when the user seeks backwards in the creative + */ + public static const AD_REWIND:String = "adRewind"; + + /** + * A tracking event dispatched when the user resumes playing a paused creative + */ + public static const AD_RESUME:String = "adResume"; + + /** + * A tracking event dispatched when the user enters fullscreen + */ + public static const AD_FULLSCREEN:String = "adFullscreen"; + + /** + * A tracking event dispatched when the user peforms a clickthru on the creative + * Usually, this results in the user being taken to a new window where a new website will load. + */ + public static const AD_CLICKTRK:String = "adClickThru"; + + /** + * A tracking event dispatched when the user interacts with a creative. Usually by mousing over, clicking, + * or following whatever prompt the creative calls for in order to delve deeper into the advertsement. + */ + public static const AD_USER_ACCEPT_INVITATION:String = "adUserAcceptInvitation"; + + /** + * A tracking event dispatched when the user closes the creative. + * Only applicable to nonlinear creatives and linear interactive creatives. + */ + public static const AD_USER_CLOSE:String = "adUserClose"; + + /** + * A tracking event dispatched when the user minimizes the creative + */ + public static const AD_USER_MINIMIZE:String = "adUserMinimize"; + + /** + * A tracking event dispatched when creative is closed at the end of playback + * Only applicable to linear creatives + */ + public static const AD_CLOSE:String = "adClose"; + + + /** + * The package location of the VPAIDMetadata class + */ + public static const NAMESPACE:String = "org.osmf.vpaid.metadata.VPAIDMetadata"; + + /** + * Constructor + * + * @param + */ + public function VPAIDMetadata() + { + super(); + } + } +} diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/model/IVPAIDBase.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/model/IVPAIDBase.as index 8534eab..f327535 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/model/IVPAIDBase.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/model/IVPAIDBase.as @@ -1,179 +1,179 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.model -{ - - import flash.events.IEventDispatcher; - - /* - Interface: IVPAIDBase - */ - public interface IVPAIDBase extends IEventDispatcher - { - // Properties - - function get api():Object; - - function get version():Number; - - /** - * Indicates the ad’s current linear vs. non-linear mode of - * operation. linearVPAID when true indicates the ad is in a linear playback mode, false - * nonlinear. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function get linearVPAID() : Boolean; - - /** - * Indicates whether the ad is in a state where it - * occupies more UI area than its smallest area. If the ad has multiple expanded states, - * all expanded states show expandedVPAID being true. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function get expandedVPAID() : Boolean; - - /** - * The player may use the remainingTimeVPAID property to update player UI during ad - * playback. The remainingTimeVPAID property is in seconds and is relative to the time the - * property is accessed. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function get remainingTimeVPAID() : Number; - - /** - * The player uses the volumeVPAID property to attempt to set or get the ad volume. The - * volumeVPAID value is between 0 and 1 and is linear. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function get volumeVPAID() : Number; - function set volumeVPAID(value : Number) : void; - - // Methods - - function probeVersion():Boolean - - /** - * After the ad is loaded and the player calls handshakeVersion, the player calls initVPAID to - * initialize the ad experience. The player may pre-load the ad and delay calling initVPAID - * until nearing the ad playback time, however, the ad does not load its assets until initVPAID - * is called. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function initVPAID(width : Number, height : Number, viewMode : String, desiredBitrate : Number, creativeData : String, environmentVars : String) : void; - - /** - * Following a resize of the ad UI container, the player calls resizeAd to allow the ad to - * scale or reposition itself within its display area. The width and height always matches - * the maximum display area allotted for the ad, and resizeVPAID is only called when the - * player changes its video content container sizing. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function resizeVPAID(width : Number, height : Number, viewMode : String) : void; - - /** - * startVPAID is called by the player and is called when the player wants the ad to start - * displaying. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function startVPAID() : void; - - /** - * stopVPAID is called by the player when it will no longer display the ad. stopVPAID is also - * called if the player needs to cancel an ad. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function stopVPAID() : void; - - /** - * pauseVPAID is called to pause ad playback. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function pauseVPAID() : void; - - /** - * resumeVPAID is called to continue ad playback following a call to pauseAd. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function resumeVPAID() : void; - - /** - * expandVPAID is called by the player to request that the ad switch to its larger UI size. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function expandVPAID() : void; - - /** - * collapseVPAID is called by the player to request that the ad switch to its smallest UI size. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - function collapseVPAID() : void; - - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.model +{ + + import flash.events.IEventDispatcher; + + /* + Interface: IVPAIDBase + */ + public interface IVPAIDBase extends IEventDispatcher + { + // Properties + + function get api():Object; + + function get version():Number; + + /** + * Indicates the ad’s current linear vs. non-linear mode of + * operation. linearVPAID when true indicates the ad is in a linear playback mode, false + * nonlinear. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function get linearVPAID() : Boolean; + + /** + * Indicates whether the ad is in a state where it + * occupies more UI area than its smallest area. If the ad has multiple expanded states, + * all expanded states show expandedVPAID being true. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function get expandedVPAID() : Boolean; + + /** + * The player may use the remainingTimeVPAID property to update player UI during ad + * playback. The remainingTimeVPAID property is in seconds and is relative to the time the + * property is accessed. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function get remainingTimeVPAID() : Number; + + /** + * The player uses the volumeVPAID property to attempt to set or get the ad volume. The + * volumeVPAID value is between 0 and 1 and is linear. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function get volumeVPAID() : Number; + function set volumeVPAID(value : Number) : void; + + // Methods + + function probeVersion():Boolean + + /** + * After the ad is loaded and the player calls handshakeVersion, the player calls initVPAID to + * initialize the ad experience. The player may pre-load the ad and delay calling initVPAID + * until nearing the ad playback time, however, the ad does not load its assets until initVPAID + * is called. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function initVPAID(width : Number, height : Number, viewMode : String, desiredBitrate : Number, creativeData : String, environmentVars : String) : void; + + /** + * Following a resize of the ad UI container, the player calls resizeAd to allow the ad to + * scale or reposition itself within its display area. The width and height always matches + * the maximum display area allotted for the ad, and resizeVPAID is only called when the + * player changes its video content container sizing. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function resizeVPAID(width : Number, height : Number, viewMode : String) : void; + + /** + * startVPAID is called by the player and is called when the player wants the ad to start + * displaying. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function startVPAID() : void; + + /** + * stopVPAID is called by the player when it will no longer display the ad. stopVPAID is also + * called if the player needs to cancel an ad. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function stopVPAID() : void; + + /** + * pauseVPAID is called to pause ad playback. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function pauseVPAID() : void; + + /** + * resumeVPAID is called to continue ad playback following a call to pauseAd. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function resumeVPAID() : void; + + /** + * expandVPAID is called by the player to request that the ad switch to its larger UI size. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function expandVPAID() : void; + + /** + * collapseVPAID is called by the player to request that the ad switch to its smallest UI size. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + function collapseVPAID() : void; + + } +} diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/model/VPAID_1_1.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/model/VPAID_1_1.as index ecee9c8..4547063 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/model/VPAID_1_1.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/model/VPAID_1_1.as @@ -1,698 +1,698 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.model -{ - import flash.events.Event; - import flash.events.EventDispatcher; - - import org.osmf.vpaid.events.VPAIDEvent; - import org.osmf.vpaid.elements.VPAIDElement; - import org.osmf.vpaid.metadata.VPAIDMetadata; - - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } - - /** - Class: VPAID_1_1 - - This class handles communication with v1.1 VPAID ads - **/ - public class VPAID_1_1 extends EventDispatcher implements IVPAIDBase - { - private var _handshakeVersions:Array = ["1.1"]; - private var _vpaidElement:VPAIDElement; - - public var adVersion:String; - private var _vpaidAPI:*; - - /** - Constructor: VPAID_1_1 - - Initializes the VPAID_1_1 - - Parameters: - VPAIDController - A reference to an instantiated - **/ - - /** - * Constructor: VPAID_1_1 - * Initializes the VPAID_1_1 - * - * Parameters: - * - * VPAIDController - A reference to an instantiated - * - * - **/ - - - public function VPAID_1_1(vpaidSWF:Object, vpaidElement:VPAIDElement):void - { - _vpaidElement = vpaidElement; - try{ - _vpaidAPI = vpaidSWF.getVPAID(); - }catch(e:Error){ - _vpaidElement.error(); - } - - } - /** - * Performs a handshake with the loaded VPAID Ad passing it a VPAID version. - * If the version number passed to handshake is supported than the Ad is ready to start, - * otherwise an error is dispatched. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function probeVersion():Boolean - { - var result:Boolean = false; - - try - { - adVersion = _vpaidAPI.handshakeVersion("1.1"); - var handshakeReturn:Boolean = _checkHandShakeVersion(adVersion); - } - catch (e:Error) - { - return false; - } - - if (handshakeReturn) - { - result = true; - } - - return result; - } - - private function addVPAIDSWFListeners():void - { - _vpaidAPI.addEventListener("AdLoaded", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdCreativeView", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdStarted", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdStopped", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdLinearChange", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdExpandedChange", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdRemainingTimeChange", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdVolumeChange", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdImpression", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdVideoStart", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdVideoFirstQuartile", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdVideoMidpoint", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdVideoThirdQuartile", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdVideoComplete", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdClickThru", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdUserAcceptInvitation", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdUserMinimize", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdUserClose", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdPaused", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdPlaying", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdLog", _vpaidEventHandler); - _vpaidAPI.addEventListener("AdError", _vpaidEventHandler); - - - - - } - - private function removeVPAIDSwfListeners():void - { - _vpaidAPI.removeEventListener("AdLoaded", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdStarted", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdStopped", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdLinearChange", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdExpandedChange", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdRemainingTimeChange", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdVolumeChange", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdImpression", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdVideoStart", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdVideoFirstQuartile", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdVideoMidpoint", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdVideoThirdQuartile", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdVideoComplete", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdClickThru", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdUserAcceptInvitation", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdUserMinimize", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdUserClose", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdPaused", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdPlaying", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdLog", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdError", _vpaidEventHandler); - _vpaidAPI.removeEventListener("AdCreativeView", _vpaidEventHandler); - - - - - - } - - /* - Function: _checkHandShakeVersion - - Compares the version from the VPAID ad with the version-array of this class - - Return: - Boolean - Is true if the version of the ad is found inside the _handshakeVersions array - */ - private function _checkHandShakeVersion(_version:String):Boolean - { - for (var i:Object in _handshakeVersions) - { - if (_version.substring(0,3) == _handshakeVersions[i].substring(0,3)) - return true; - } - return false; - } - - /* - Function: _vpaidEventHandler - - Events that come from the ad are handled here event type is - intentionally set as asterisk, reasoning for this is - if the event comes from a external swf the type is not predictable. - - Events: - VPAIDEvent.LOADED - Loading of ad is done - VPAIDEvent.STARTED - Ad is displaying - VPAIDEvent.STOPPED - Ad has stopped displaying, and ressources have been cleaned up - VPAIDEvent.LINEAR_CHANGE - Ad has changed playback mode - VPAIDEvent.EXPANDED_CHANGE - Ad expanded state has being changed - VPAIDEvent.REMAINING_TIME_CHANGE - Remaining time of ad has been changed - VPAIDEvent.VOLUME_CHANGE - Ad has changed it's volume - VPAIDEvent.IMPRESSION - User-visible phase of ad has begun - VPAIDEvent.VIDEO_START - Video has started progress - VPAIDEvent.VIDEO_FIRST_QUARTILE - Ad video has reached first quartile - VPAIDEvent.VIDEO_MIDPOINT - Ad video has reached it's midpoint - VPAIDEvent.VIDEO_THIRD_QUARTILE - Ad video has reached third quartile - VPAIDEvent.VIDEO_COMPLETE - Ad video has been played completely - VPAIDEvent.CLICK_THRU - Click thru occured - VPAIDEvent.USER_ACCEPT_INVITATION - Triggered on user ineraction - VPAIDEvent.USER_MINIMIZE - Triggered on user ineraction - VPAIDEvent.USER_CLOSE - Triggered on user ineraction - VPAIDEvent.PAUSED - Response to method call - VPAIDEvent.PLAYING - Response to method call - VPAIDEvent.LOG - Ad sends debug message to relay - VPAIDEvent.ERROR - Fatal error occured - - Parameter: - event - The event that was sent by the ad. - */ - private function _vpaidEventHandler(event:Object):void - { - //Forward events - var myVPAIDEvent:VPAIDEvent = new VPAIDEvent(event.type, event.data, event.bubbles,event.cancelable); - _vpaidElement.dispatchEvent(myVPAIDEvent); - - - - if (event.type!="AdLog"){ - switch (event.type) { - - case "AdCreativeView": - dispatchEvent(new Event("AdCreativeView")); - break; - - case "AdLoaded" : - dispatchEvent(new Event("AdLoaded")); - break; - - - case "AdStarted" : - dispatchEvent(new Event("AdStarted")); - break; - - case "AdStopped" : - dispatchEvent(new Event("AdStopped")); - break; - - case "AdLinearChange" : - dispatchEvent(new Event("AdLinearChange")); - break; - - case "AdExpandedChange" : - dispatchEvent(new Event("AdExpandedChange")); - break; - - case "AdRemainingTimeChange" : - dispatchEvent(new Event("AdRemainingTimeChange")); - break; - - case "AdVolumeChange" : - dispatchEvent(new Event("AdVolumeChange")); - break; - - case "AdPaused" : - dispatchEvent(new Event("AdPaused")); - break; - - case "AdPlaying" : - dispatchEvent(new Event("AdPlaying")); - break; - - case"AdVideoStart": - dispatchEvent(new Event("AdVideoStart")); - break; - - case"AdVideoFirstQuartile": - dispatchEvent(new Event("AdVideoFirstQuartile")); - break; - - case"AdVideoMidpoint": - dispatchEvent(new Event("AdVideoMidPoint")); - break; - - case"AdVideoThirdQuartile": - dispatchEvent(new Event("AdVideoThirdQuartile")); - break; - - case"AdVideoComplete": - dispatchEvent(new Event("AdVideoComplete")); - break; - - case"AdClickThru": - dispatchEvent(new Event("AdClickThru")); - - break; - - case"AdUserAcceptInvitation": - dispatchEvent(new Event("AdUserAcceptInvitation")); - - break; - - case"AdUserMinimize": - dispatchEvent(new Event("AdUserMinimize")); - - break; - - case"AdUserClose": - dispatchEvent(new Event("AdUserClose")); - break; - - case"AdImpression": - dispatchEvent(new Event("AdImpression")); - break; - - case "AdLog" : - dispatchEvent(new Event("AdLog")); - break; - - case "AdError" : - dispatchEvent(new Event("AdError")); - break; - } - } - } - - - /** - * Property: linearVPAID - * Indicates the ad’s current linear vs. non-linear mode of operation. - * - * Returns: Boolean - Is true when the ad is in linear playback mode, false if it's nonlinear - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function get linearVPAID() : Boolean { - return _vpaidAPI.adLinear; - } - - - /** - * Property: expandedVPAID - * - * Indicates whether the ad is in a state where it - * occupies more UI area than its smallest area. If the ad has multiple expanded states, - * all expanded states show expandedVPAID being true. - * Returns: - Boolean - Returns true when ad is in a state where it occupies more UI area than its smallest area - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function get expandedVPAID() : Boolean { - return _vpaidAPI.adExpanded; - } - - - - /** - * Property: remainingTimeVPAID - * - The player may use the remainingTimeVPAID property to update player UI during ad - playback. The remainingTimeVPAID property is in seconds and is relative to the time the - property is accessed. - - Returns: - Number - Remaining time of the VPAID ad in Seconds - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function get remainingTimeVPAID() : Number { - return _vpaidAPI.adRemainingTime; - } - - - /** - * Property: volumeVPAID - - The player uses the volumeVPAID property to attempt to set or get the ad volume. - - Returns: - Number - A Number between 0 and 1, where 0 means muted. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function get volumeVPAID() : Number { - return _vpaidAPI.adVolume; - } - - /** - Property: volumeVPAID - - Sets the volume of the VPAID ad. - - Parameter: - Number - A Number between 0 and 1, where 0 means muted. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function set volumeVPAID(value : Number) : void { - _vpaidAPI.adVolume = value; - } - - // Methods - - /* - - */ - - /** - Function: handshakeVersion - - The player calls handshakeVersion immediately after loading the ad to indicate to the - ad that VPAID will be used. The player passes in its latest VPAID version string. The ad - returns a version string minimally set to “1.0”, and of the form “major.minor.patch”. - The player must verify that it supports the particular version of VPAID or cancel the ad. - - Parameter: - playerVPAIDVersion - The VPAID version string the player is able to speak, given in the form of "major.minor.patch" - - Returns: - adVPAIDversion - The VPAID version the ad speaks, given in the form of "major.minor.patch" - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function handshakeVersion(playerVPAIDVersion : String) : String - { - CONFIG::LOGGING - { - logger.debug("[VPAID] Player is calling handshakeversion on ad: Player version is "+ version); - } - try - { - adVersion = _vpaidAPI.handshakeVersion(playerVPAIDVersion); - } - catch (e:Error) - { - _vpaidElement.error(); - } - - return adVersion; - } - - /** - Function: initVPAID - - After the ad is loaded and the player calls handshakeVersion, the player calls initVPAID to - initialize the ad experience. The player may pre-load the ad and delay calling initVPAID - until nearing the ad playback time, however, the ad does not load its assets until initVPAID - is called. - - Parameters: - width - Content players width, given as Number - height - Content players width, given as Number - viewMode - Content players current view mode, may be one of "normal", "thumbnail" or "fullscreen" - desiredBitrate - Bitrate in kbps that the ad may use - creativeData - optional parameter for passing in additional ad initialization data - environmentVars - optional parameter for passing implementation-specific runtime variables - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function initVPAID(width : Number, height : Number, viewMode : String, desiredBitrate : Number, creativeData : String, environmentVars : String) : void { - CONFIG::LOGGING - { - logger.debug("[VPAID] Player is calling initAd on ad. [width="+ width +", height="+height+", viewMode="+viewMode+", desiredBitrate="+desiredBitrate+", creativeData="+creativeData+", environmentVars="+environmentVars+"]"); - } - addVPAIDSWFListeners(); - try - { - _vpaidAPI.initAd(width , height , viewMode , desiredBitrate , creativeData , environmentVars ); - } - catch (e:Error) - { - _vpaidElement.error(); - } - } - - /** - Function: resizeVPAID - - Following a resize of the ad UI container, the player calls resizeVPAID to allow the ad to - scale or reposition itself within its display area. The width and height always matches - the maximum display area allotted for the ad, and resizeVPAID is only called when the - player changes its video content container sizing. - - Parameters: - width - Content players width, given as Number - height - Content players width, given as Number - viewMode - "normal", "thumbnail" or "fullscreen" - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function resizeVPAID(width : Number, height : Number, viewMode : String) : void { - CONFIG::LOGGING - { - logger.debug("[VPAID] Player is calling resizeAd on ad: [width="+ width+", height="+height+" ,viewMode=" + viewMode); - } - try - { - _vpaidAPI.resizeAd(width , height , viewMode ); - } - catch (e:Error) - { - - } - } - - - /** - Function: startVPAID - - Is called by the player and is called when the player wants the ad to start - displaying. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function startVPAID() : void { - CONFIG::LOGGING - { - logger.debug("[VPAID] Player is scalling startAd on ad"); - } - try - { - _vpaidAPI.startAd(); - } - catch (e:Error) - { - _vpaidElement.error(); - } - - } - - /** - Function: stopVPAID - - Is called by the player when it will no longer display the ad. stopVPAID is also - called if the player needs to cancel an ad. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function stopVPAID() : void { - CONFIG::LOGGING - { - logger.debug("[VPAID] Player is stopAd on ad"); - } - try - { - _vpaidAPI.stopAd(); - } - catch (e:Error) - { - _vpaidElement.error(); - } - } - - - /** - Function: pauseVPAID - - Is called to pause ad playback. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function pauseVPAID() : void { - try - { - _vpaidAPI.pauseAd(); - } - catch (e:Error) - { - - } - } - - - /** - Function: resumeVPAID - - Is called to continue ad playback following a call to pauseVPAID. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function resumeVPAID() : void { - try - { - _vpaidAPI.resumeAd(); - } - catch (e:Error) - { - - } - } - - - /** - Function: expandVPAID - - Is called by the player to request that the ad switch to its larger UI size. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function expandVPAID() : void { - try - { - _vpaidAPI.expandAd(); - } - catch (e:Error) - { - - } - } - - /** - Function collapseVPAID - - Is called by the player to request that the ad return to its smallest UI size. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function collapseVPAID() : void { - try - { - _vpaidAPI.collapseAd(); - } - catch (e:Error) - { - - } - } - - /** - - Returns: version - Returns the currently supported VPAID version. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public function get version():Number - { - return 1.1; - } - - public function get api():Object - { - return _vpaidAPI; - } - - CONFIG::LOGGING - private static const logger:Logger = Log.getLogger("org.osmf.vpaid.model.VPAID_1_1"); - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.model +{ + import flash.events.Event; + import flash.events.EventDispatcher; + + import org.osmf.vpaid.events.VPAIDEvent; + import org.osmf.vpaid.elements.VPAIDElement; + import org.osmf.vpaid.metadata.VPAIDMetadata; + + CONFIG::LOGGING + { + import org.osmf.logging.Logger; + import org.osmf.logging.Log; + } + + /** + Class: VPAID_1_1 + + This class handles communication with v1.1 VPAID ads + **/ + public class VPAID_1_1 extends EventDispatcher implements IVPAIDBase + { + private var _handshakeVersions:Array = ["1.1"]; + private var _vpaidElement:VPAIDElement; + + public var adVersion:String; + private var _vpaidAPI:*; + + /** + Constructor: VPAID_1_1 + + Initializes the VPAID_1_1 + + Parameters: + VPAIDController - A reference to an instantiated + **/ + + /** + * Constructor: VPAID_1_1 + * Initializes the VPAID_1_1 + * + * Parameters: + * + * VPAIDController - A reference to an instantiated + * + * + **/ + + + public function VPAID_1_1(vpaidSWF:Object, vpaidElement:VPAIDElement):void + { + _vpaidElement = vpaidElement; + try{ + _vpaidAPI = vpaidSWF.getVPAID(); + }catch(e:Error){ + _vpaidElement.error(); + } + + } + /** + * Performs a handshake with the loaded VPAID Ad passing it a VPAID version. + * If the version number passed to handshake is supported than the Ad is ready to start, + * otherwise an error is dispatched. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function probeVersion():Boolean + { + var result:Boolean = false; + + try + { + adVersion = _vpaidAPI.handshakeVersion("1.1"); + var handshakeReturn:Boolean = _checkHandShakeVersion(adVersion); + } + catch (e:Error) + { + return false; + } + + if (handshakeReturn) + { + result = true; + } + + return result; + } + + private function addVPAIDSWFListeners():void + { + _vpaidAPI.addEventListener("AdLoaded", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdCreativeView", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdStarted", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdStopped", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdLinearChange", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdExpandedChange", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdRemainingTimeChange", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdVolumeChange", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdImpression", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdVideoStart", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdVideoFirstQuartile", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdVideoMidpoint", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdVideoThirdQuartile", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdVideoComplete", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdClickThru", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdUserAcceptInvitation", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdUserMinimize", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdUserClose", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdPaused", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdPlaying", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdLog", _vpaidEventHandler); + _vpaidAPI.addEventListener("AdError", _vpaidEventHandler); + + + + + } + + private function removeVPAIDSwfListeners():void + { + _vpaidAPI.removeEventListener("AdLoaded", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdStarted", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdStopped", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdLinearChange", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdExpandedChange", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdRemainingTimeChange", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdVolumeChange", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdImpression", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdVideoStart", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdVideoFirstQuartile", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdVideoMidpoint", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdVideoThirdQuartile", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdVideoComplete", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdClickThru", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdUserAcceptInvitation", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdUserMinimize", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdUserClose", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdPaused", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdPlaying", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdLog", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdError", _vpaidEventHandler); + _vpaidAPI.removeEventListener("AdCreativeView", _vpaidEventHandler); + + + + + + } + + /* + Function: _checkHandShakeVersion + + Compares the version from the VPAID ad with the version-array of this class + + Return: + Boolean - Is true if the version of the ad is found inside the _handshakeVersions array + */ + private function _checkHandShakeVersion(_version:String):Boolean + { + for (var i:Object in _handshakeVersions) + { + if (_version.substring(0,3) == _handshakeVersions[i].substring(0,3)) + return true; + } + return false; + } + + /* + Function: _vpaidEventHandler + + Events that come from the ad are handled here event type is + intentionally set as asterisk, reasoning for this is + if the event comes from a external swf the type is not predictable. + + Events: + VPAIDEvent.LOADED - Loading of ad is done + VPAIDEvent.STARTED - Ad is displaying + VPAIDEvent.STOPPED - Ad has stopped displaying, and ressources have been cleaned up + VPAIDEvent.LINEAR_CHANGE - Ad has changed playback mode + VPAIDEvent.EXPANDED_CHANGE - Ad expanded state has being changed + VPAIDEvent.REMAINING_TIME_CHANGE - Remaining time of ad has been changed + VPAIDEvent.VOLUME_CHANGE - Ad has changed it's volume + VPAIDEvent.IMPRESSION - User-visible phase of ad has begun + VPAIDEvent.VIDEO_START - Video has started progress + VPAIDEvent.VIDEO_FIRST_QUARTILE - Ad video has reached first quartile + VPAIDEvent.VIDEO_MIDPOINT - Ad video has reached it's midpoint + VPAIDEvent.VIDEO_THIRD_QUARTILE - Ad video has reached third quartile + VPAIDEvent.VIDEO_COMPLETE - Ad video has been played completely + VPAIDEvent.CLICK_THRU - Click thru occured + VPAIDEvent.USER_ACCEPT_INVITATION - Triggered on user ineraction + VPAIDEvent.USER_MINIMIZE - Triggered on user ineraction + VPAIDEvent.USER_CLOSE - Triggered on user ineraction + VPAIDEvent.PAUSED - Response to method call + VPAIDEvent.PLAYING - Response to method call + VPAIDEvent.LOG - Ad sends debug message to relay + VPAIDEvent.ERROR - Fatal error occured + + Parameter: + event - The event that was sent by the ad. + */ + private function _vpaidEventHandler(event:Object):void + { + //Forward events + var myVPAIDEvent:VPAIDEvent = new VPAIDEvent(event.type, event.data, event.bubbles,event.cancelable); + _vpaidElement.dispatchEvent(myVPAIDEvent); + + + + if (event.type!="AdLog"){ + switch (event.type) { + + case "AdCreativeView": + dispatchEvent(new Event("AdCreativeView")); + break; + + case "AdLoaded" : + dispatchEvent(new Event("AdLoaded")); + break; + + + case "AdStarted" : + dispatchEvent(new Event("AdStarted")); + break; + + case "AdStopped" : + dispatchEvent(new Event("AdStopped")); + break; + + case "AdLinearChange" : + dispatchEvent(new Event("AdLinearChange")); + break; + + case "AdExpandedChange" : + dispatchEvent(new Event("AdExpandedChange")); + break; + + case "AdRemainingTimeChange" : + dispatchEvent(new Event("AdRemainingTimeChange")); + break; + + case "AdVolumeChange" : + dispatchEvent(new Event("AdVolumeChange")); + break; + + case "AdPaused" : + dispatchEvent(new Event("AdPaused")); + break; + + case "AdPlaying" : + dispatchEvent(new Event("AdPlaying")); + break; + + case"AdVideoStart": + dispatchEvent(new Event("AdVideoStart")); + break; + + case"AdVideoFirstQuartile": + dispatchEvent(new Event("AdVideoFirstQuartile")); + break; + + case"AdVideoMidpoint": + dispatchEvent(new Event("AdVideoMidPoint")); + break; + + case"AdVideoThirdQuartile": + dispatchEvent(new Event("AdVideoThirdQuartile")); + break; + + case"AdVideoComplete": + dispatchEvent(new Event("AdVideoComplete")); + break; + + case"AdClickThru": + dispatchEvent(new Event("AdClickThru")); + + break; + + case"AdUserAcceptInvitation": + dispatchEvent(new Event("AdUserAcceptInvitation")); + + break; + + case"AdUserMinimize": + dispatchEvent(new Event("AdUserMinimize")); + + break; + + case"AdUserClose": + dispatchEvent(new Event("AdUserClose")); + break; + + case"AdImpression": + dispatchEvent(new Event("AdImpression")); + break; + + case "AdLog" : + dispatchEvent(new Event("AdLog")); + break; + + case "AdError" : + dispatchEvent(new Event("AdError")); + break; + } + } + } + + + /** + * Property: linearVPAID + * Indicates the ad’s current linear vs. non-linear mode of operation. + * + * Returns: Boolean - Is true when the ad is in linear playback mode, false if it's nonlinear + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function get linearVPAID() : Boolean { + return _vpaidAPI.adLinear; + } + + + /** + * Property: expandedVPAID + * + * Indicates whether the ad is in a state where it + * occupies more UI area than its smallest area. If the ad has multiple expanded states, + * all expanded states show expandedVPAID being true. + * Returns: + Boolean - Returns true when ad is in a state where it occupies more UI area than its smallest area + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function get expandedVPAID() : Boolean { + return _vpaidAPI.adExpanded; + } + + + + /** + * Property: remainingTimeVPAID + * + The player may use the remainingTimeVPAID property to update player UI during ad + playback. The remainingTimeVPAID property is in seconds and is relative to the time the + property is accessed. + + Returns: + Number - Remaining time of the VPAID ad in Seconds + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function get remainingTimeVPAID() : Number { + return _vpaidAPI.adRemainingTime; + } + + + /** + * Property: volumeVPAID + + The player uses the volumeVPAID property to attempt to set or get the ad volume. + + Returns: + Number - A Number between 0 and 1, where 0 means muted. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function get volumeVPAID() : Number { + return _vpaidAPI.adVolume; + } + + /** + Property: volumeVPAID + + Sets the volume of the VPAID ad. + + Parameter: + Number - A Number between 0 and 1, where 0 means muted. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function set volumeVPAID(value : Number) : void { + _vpaidAPI.adVolume = value; + } + + // Methods + + /* + + */ + + /** + Function: handshakeVersion + + The player calls handshakeVersion immediately after loading the ad to indicate to the + ad that VPAID will be used. The player passes in its latest VPAID version string. The ad + returns a version string minimally set to “1.0”, and of the form “major.minor.patch”. + The player must verify that it supports the particular version of VPAID or cancel the ad. + + Parameter: + playerVPAIDVersion - The VPAID version string the player is able to speak, given in the form of "major.minor.patch" + + Returns: + adVPAIDversion - The VPAID version the ad speaks, given in the form of "major.minor.patch" + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function handshakeVersion(playerVPAIDVersion : String) : String + { + CONFIG::LOGGING + { + logger.debug("[VPAID] Player is calling handshakeversion on ad: Player version is "+ version); + } + try + { + adVersion = _vpaidAPI.handshakeVersion(playerVPAIDVersion); + } + catch (e:Error) + { + _vpaidElement.error(); + } + + return adVersion; + } + + /** + Function: initVPAID + + After the ad is loaded and the player calls handshakeVersion, the player calls initVPAID to + initialize the ad experience. The player may pre-load the ad and delay calling initVPAID + until nearing the ad playback time, however, the ad does not load its assets until initVPAID + is called. + + Parameters: + width - Content players width, given as Number + height - Content players width, given as Number + viewMode - Content players current view mode, may be one of "normal", "thumbnail" or "fullscreen" + desiredBitrate - Bitrate in kbps that the ad may use + creativeData - optional parameter for passing in additional ad initialization data + environmentVars - optional parameter for passing implementation-specific runtime variables + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function initVPAID(width : Number, height : Number, viewMode : String, desiredBitrate : Number, creativeData : String, environmentVars : String) : void { + CONFIG::LOGGING + { + logger.debug("[VPAID] Player is calling initAd on ad. [width="+ width +", height="+height+", viewMode="+viewMode+", desiredBitrate="+desiredBitrate+", creativeData="+creativeData+", environmentVars="+environmentVars+"]"); + } + addVPAIDSWFListeners(); + try + { + _vpaidAPI.initAd(width , height , viewMode , desiredBitrate , creativeData , environmentVars ); + } + catch (e:Error) + { + _vpaidElement.error(); + } + } + + /** + Function: resizeVPAID + + Following a resize of the ad UI container, the player calls resizeVPAID to allow the ad to + scale or reposition itself within its display area. The width and height always matches + the maximum display area allotted for the ad, and resizeVPAID is only called when the + player changes its video content container sizing. + + Parameters: + width - Content players width, given as Number + height - Content players width, given as Number + viewMode - "normal", "thumbnail" or "fullscreen" + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function resizeVPAID(width : Number, height : Number, viewMode : String) : void { + CONFIG::LOGGING + { + logger.debug("[VPAID] Player is calling resizeAd on ad: [width="+ width+", height="+height+" ,viewMode=" + viewMode); + } + try + { + _vpaidAPI.resizeAd(width , height , viewMode ); + } + catch (e:Error) + { + + } + } + + + /** + Function: startVPAID + + Is called by the player and is called when the player wants the ad to start + displaying. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function startVPAID() : void { + CONFIG::LOGGING + { + logger.debug("[VPAID] Player is scalling startAd on ad"); + } + try + { + _vpaidAPI.startAd(); + } + catch (e:Error) + { + _vpaidElement.error(); + } + + } + + /** + Function: stopVPAID + + Is called by the player when it will no longer display the ad. stopVPAID is also + called if the player needs to cancel an ad. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function stopVPAID() : void { + CONFIG::LOGGING + { + logger.debug("[VPAID] Player is stopAd on ad"); + } + try + { + _vpaidAPI.stopAd(); + } + catch (e:Error) + { + _vpaidElement.error(); + } + } + + + /** + Function: pauseVPAID + + Is called to pause ad playback. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function pauseVPAID() : void { + try + { + _vpaidAPI.pauseAd(); + } + catch (e:Error) + { + + } + } + + + /** + Function: resumeVPAID + + Is called to continue ad playback following a call to pauseVPAID. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function resumeVPAID() : void { + try + { + _vpaidAPI.resumeAd(); + } + catch (e:Error) + { + + } + } + + + /** + Function: expandVPAID + + Is called by the player to request that the ad switch to its larger UI size. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function expandVPAID() : void { + try + { + _vpaidAPI.expandAd(); + } + catch (e:Error) + { + + } + } + + /** + Function collapseVPAID + + Is called by the player to request that the ad return to its smallest UI size. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function collapseVPAID() : void { + try + { + _vpaidAPI.collapseAd(); + } + catch (e:Error) + { + + } + } + + /** + + Returns: version - Returns the currently supported VPAID version. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function get version():Number + { + return 1.1; + } + + public function get api():Object + { + return _vpaidAPI; + } + + CONFIG::LOGGING + private static const logger:Logger = Log.getLogger("org.osmf.vpaid.model.VPAID_1_1"); + } +} diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/traits/VPAIDLoadTrait.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/traits/VPAIDLoadTrait.as index 1e8d148..e77d434 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/traits/VPAIDLoadTrait.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/traits/VPAIDLoadTrait.as @@ -1,89 +1,89 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.traits -{ - import flash.events.Event; - - import org.osmf.media.MediaResourceBase; - import org.osmf.traits.LoaderBase; - import org.osmf.utils.HTTPLoadTrait; - import org.osmf.events.LoadEvent; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoadState; - import org.osmf.elements.loaderClasses.LoaderLoadTrait; - import org.osmf.vpaid.events.VPAIDLoadEvent; - - - /** - * An VPAIDLoadEvent is dispatched when the properties of a VPAIDLoadTrait change. - * - * @eventType org.osmf.vpaid.events.LoadEvent.VPAID_READY - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - [Event(name="VPAIDReady",type="org.osmf.vpaid.events.VPAIDLoadEvent")] - - - /** - * Delays the Ready event until VPAID is loaded and initialized - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - - public class VPAIDLoadTrait extends LoaderLoadTrait - { - public function VPAIDLoadTrait(loader:LoaderBase, resource:MediaResourceBase) - { - super(loader, resource); - } - - /** - * Called once the VPAID Ad has finished loading - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - - public function vpaidReady():void - { - if(loadState == LoadState.READY) - dispatchEvent(new LoadEvent(LoadEvent.LOAD_STATE_CHANGE, false, false, loadState)); - } - - override protected function loadStateChangeEnd():void - { - if(loadState != LoadState.READY){ - dispatchEvent(new LoadEvent(LoadEvent.LOAD_STATE_CHANGE, false, false, loadState)); - }else{ - dispatchEvent(new VPAIDLoadEvent(VPAIDLoadEvent.INITIALIZE_VPAID, false, false)); - } - } - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.traits +{ + import flash.events.Event; + + import org.osmf.media.MediaResourceBase; + import org.osmf.traits.LoaderBase; + import org.osmf.utils.HTTPLoadTrait; + import org.osmf.events.LoadEvent; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.LoadState; + import org.osmf.elements.loaderClasses.LoaderLoadTrait; + import org.osmf.vpaid.events.VPAIDLoadEvent; + + + /** + * An VPAIDLoadEvent is dispatched when the properties of a VPAIDLoadTrait change. + * + * @eventType org.osmf.vpaid.events.LoadEvent.VPAID_READY + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + [Event(name="VPAIDReady",type="org.osmf.vpaid.events.VPAIDLoadEvent")] + + + /** + * Delays the Ready event until VPAID is loaded and initialized + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + + public class VPAIDLoadTrait extends LoaderLoadTrait + { + public function VPAIDLoadTrait(loader:LoaderBase, resource:MediaResourceBase) + { + super(loader, resource); + } + + /** + * Called once the VPAID Ad has finished loading + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + + public function vpaidReady():void + { + if(loadState == LoadState.READY) + dispatchEvent(new LoadEvent(LoadEvent.LOAD_STATE_CHANGE, false, false, loadState)); + } + + override protected function loadStateChangeEnd():void + { + if(loadState != LoadState.READY){ + dispatchEvent(new LoadEvent(LoadEvent.LOAD_STATE_CHANGE, false, false, loadState)); + }else{ + dispatchEvent(new VPAIDLoadEvent(VPAIDLoadEvent.INITIALIZE_VPAID, false, false)); + } + } + } +} diff --git a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/traits/VPAIDTimeTrait.as b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/traits/VPAIDTimeTrait.as index e392c85..a1b6299 100644 --- a/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/traits/VPAIDTimeTrait.as +++ b/lib/osmf/samples/VPAIDLibrary/src/org/osmf/vpaid/traits/VPAIDTimeTrait.as @@ -1,164 +1,164 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package org.osmf.vpaid.traits -{ - import flash.events.TimerEvent; - import flash.utils.Timer; - - import org.osmf.events.TimeEvent; - import org.osmf.traits.TimeTrait; - - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } - - /** - * Attached to Linear VPAIDElements. Takes the duration of the creative as a paramater. - * The VPAIDElement notifies the VPAIDTimeTrait with the remaining time left in the ad. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public class VPAIDTimeTrait extends TimeTrait - { - private var vpaidTimer:Timer; - - public function VPAIDTimeTrait(duration:Number=NaN) - { - super(duration); - - } - - - /** - VPAIDElement updates the timer. Timer keeps track of time - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function updateRemainingTime(remaingTime:Number):void - { - if(remaingTime <= 0){ - signalComplete(); - cleanUpTimer(); - }else{ - setDuration(remaingTime); - setCurrentTime(0); //Restart at zero everytime - countCurrentTime(duration); - } - } - - /** - Called to pause the counting of the current time - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function pauseTimer():void - { - CONFIG::LOGGING - { - if(duration && currentTime) - { - var remainingTime:Number = duration - currentTime; - logger.debug("[VPAID] Pausing timer, remaining time: " + remainingTime +" current time: " + currentTime); - } - } - cleanUpTimer(); - } - - /** - Called to resume the counting of the current time - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function resumeTimer():void - { - if(duration && currentTime) - { - var remainingTime:Number = duration - currentTime; - CONFIG::LOGGING - { - logger.debug("[VPAID] Resuming timer, remaining time: " + remainingTime +" current time: " + currentTime); - } - countCurrentTime(Math.max(0,remainingTime)); - } - } - - override protected function signalComplete():void - { - cleanUpTimer(); - dispatchEvent(new TimeEvent(TimeEvent.COMPLETE)); - } - - //Counts up to the duration of the VPAID creative. Calls onTimer every 1 sec. - private function countCurrentTime(time:Number):void - { - cleanUpTimer(); - vpaidTimer = new Timer(1000, time); - vpaidTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete); - vpaidTimer.addEventListener(TimerEvent.TIMER, onTimer); - vpaidTimer.start(); - - } - - //Timer needs to be completely cleared from memory so that it doesn't fire when it is not needed - private function cleanUpTimer():void - { - if(vpaidTimer) - { - vpaidTimer.stop(); - vpaidTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete); - vpaidTimer.removeEventListener(TimerEvent.TIMER, onTimer); - - } - } - - private function onTimerComplete(event:TimerEvent):void - { - setDuration(0); - cleanUpTimer(); - } - - //Adds one second to the current time - private function onTimer(event:TimerEvent):void - { - var newTime:Number = Math.min(duration, currentTime + 1); - setCurrentTime(newTime); - //trace("current time: " + currentTime); - } - - CONFIG::LOGGING - private static const logger:Logger = Log.getLogger("org.osmf.vpaid.traits.VPAIDTimeTrait"); - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package org.osmf.vpaid.traits +{ + import flash.events.TimerEvent; + import flash.utils.Timer; + + import org.osmf.events.TimeEvent; + import org.osmf.traits.TimeTrait; + + CONFIG::LOGGING + { + import org.osmf.logging.Logger; + import org.osmf.logging.Log; + } + + /** + * Attached to Linear VPAIDElements. Takes the duration of the creative as a paramater. + * The VPAIDElement notifies the VPAIDTimeTrait with the remaining time left in the ad. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public class VPAIDTimeTrait extends TimeTrait + { + private var vpaidTimer:Timer; + + public function VPAIDTimeTrait(duration:Number=NaN) + { + super(duration); + + } + + + /** + VPAIDElement updates the timer. Timer keeps track of time + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function updateRemainingTime(remaingTime:Number):void + { + if(remaingTime <= 0){ + signalComplete(); + cleanUpTimer(); + }else{ + setDuration(remaingTime); + setCurrentTime(0); //Restart at zero everytime + countCurrentTime(duration); + } + } + + /** + Called to pause the counting of the current time + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function pauseTimer():void + { + CONFIG::LOGGING + { + if(duration && currentTime) + { + var remainingTime:Number = duration - currentTime; + logger.debug("[VPAID] Pausing timer, remaining time: " + remainingTime +" current time: " + currentTime); + } + } + cleanUpTimer(); + } + + /** + Called to resume the counting of the current time + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function resumeTimer():void + { + if(duration && currentTime) + { + var remainingTime:Number = duration - currentTime; + CONFIG::LOGGING + { + logger.debug("[VPAID] Resuming timer, remaining time: " + remainingTime +" current time: " + currentTime); + } + countCurrentTime(Math.max(0,remainingTime)); + } + } + + override protected function signalComplete():void + { + cleanUpTimer(); + dispatchEvent(new TimeEvent(TimeEvent.COMPLETE)); + } + + //Counts up to the duration of the VPAID creative. Calls onTimer every 1 sec. + private function countCurrentTime(time:Number):void + { + cleanUpTimer(); + vpaidTimer = new Timer(1000, time); + vpaidTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete); + vpaidTimer.addEventListener(TimerEvent.TIMER, onTimer); + vpaidTimer.start(); + + } + + //Timer needs to be completely cleared from memory so that it doesn't fire when it is not needed + private function cleanUpTimer():void + { + if(vpaidTimer) + { + vpaidTimer.stop(); + vpaidTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete); + vpaidTimer.removeEventListener(TimerEvent.TIMER, onTimer); + + } + } + + private function onTimerComplete(event:TimerEvent):void + { + setDuration(0); + cleanUpTimer(); + } + + //Adds one second to the current time + private function onTimer(event:TimerEvent):void + { + var newTime:Number = Math.min(duration, currentTime + 1); + setCurrentTime(newTime); + //trace("current time: " + currentTime); + } + + CONFIG::LOGGING + private static const logger:Logger = Log.getLogger("org.osmf.vpaid.traits.VPAIDTimeTrait"); + } +} diff --git a/lib/osmf/samples/VPAIDNoAdUnitTest/.actionScriptProperties b/lib/osmf/samples/VPAIDNoAdUnitTest/.actionScriptProperties index aaa676f..a48518f 100644 --- a/lib/osmf/samples/VPAIDNoAdUnitTest/.actionScriptProperties +++ b/lib/osmf/samples/VPAIDNoAdUnitTest/.actionScriptProperties @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/AC_OETags.js b/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/AC_OETags.js +++ b/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '

      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/history/historyFrame.html b/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/history/historyFrame.html +++ b/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/index.template.html b/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/index.template.html index 20ee809..a8b3b64 100644 --- a/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/index.template.html +++ b/lib/osmf/samples/VPAIDNoAdUnitTest/html-template/index.template.html @@ -1,121 +1,121 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDNoAdUnitTest/readme.txt b/lib/osmf/samples/VPAIDNoAdUnitTest/readme.txt index d0b4629..5b36cf5 100644 --- a/lib/osmf/samples/VPAIDNoAdUnitTest/readme.txt +++ b/lib/osmf/samples/VPAIDNoAdUnitTest/readme.txt @@ -1,9 +1,9 @@ -The purpose of this unit test is to ensure that the inclusion of the VAST and VPAID SWCs will not -cause errors with the OSMF when ads are not present. - -Steps to test: -Publish VPAIDTestPlayer.fla -Launch VPAIDTestPlayer.html to test the video player - -Expected results: +The purpose of this unit test is to ensure that the inclusion of the VAST and VPAID SWCs will not +cause errors with the OSMF when ads are not present. + +Steps to test: +Publish VPAIDTestPlayer.fla +Launch VPAIDTestPlayer.html to test the video player + +Expected results: Content video will play. \ No newline at end of file diff --git a/lib/osmf/samples/VPAIDSample/.actionScriptProperties b/lib/osmf/samples/VPAIDSample/.actionScriptProperties index 45c6f6b..a259025 100644 --- a/lib/osmf/samples/VPAIDSample/.actionScriptProperties +++ b/lib/osmf/samples/VPAIDSample/.actionScriptProperties @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDSample/html-template/AC_OETags.js b/lib/osmf/samples/VPAIDSample/html-template/AC_OETags.js index 6366467..ba5d24a 100644 --- a/lib/osmf/samples/VPAIDSample/html-template/AC_OETags.js +++ b/lib/osmf/samples/VPAIDSample/html-template/AC_OETags.js @@ -1,292 +1,292 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += '= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); +BrowserHistoryUtils = { + addEvent: function(elm, evType, fn, useCapture) { + useCapture = useCapture || false; + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + var r = elm.attachEvent('on' + evType, fn); + return r; + } + else { + elm['on' + evType] = fn; + } + } +} + +BrowserHistory = (function() { + // type of browser + var browser = { + ie: false, + firefox: false, + safari: false, + opera: false, + version: -1 + }; + + // if setDefaultURL has been called, our first clue + // that the SWF is ready and listening + //var swfReady = false; + + // the URL we'll send to the SWF once it is ready + //var pendingURL = ''; + + // Default app state URL to use when no fragment ID present + var defaultHash = ''; + + // Last-known app state URL + var currentHref = document.location.href; + + // Initial URL (used only by IE) + var initialHref = document.location.href; + + // Initial URL (used only by IE) + var initialHash = document.location.hash; + + // History frame source URL prefix (used only by IE) + var historyFrameSourcePrefix = 'history/historyFrame.html?'; + + // History maintenance (used only by Safari) + var currentHistoryLength = -1; + + var historyHash = []; + + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); + + var backStack = []; + var forwardStack = []; + + var currentObjectId = null; + + //UserAgent detection + var useragent = navigator.userAgent.toLowerCase(); + + if (useragent.indexOf("opera") != -1) { + browser.opera = true; + } else if (useragent.indexOf("msie") != -1) { + browser.ie = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); + } else if (useragent.indexOf("safari") != -1) { + browser.safari = true; + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); + } else if (useragent.indexOf("gecko") != -1) { + browser.firefox = true; + } + + if (browser.ie == true && browser.version == 7) { + window["_ie_firstload"] = false; + } + + // Accessor functions for obtaining specific elements of the page. + function getHistoryFrame() + { + return document.getElementById('ie_historyFrame'); + } + + function getAnchorElement() + { + return document.getElementById('firefox_anchorDiv'); + } + + function getFormElement() + { + return document.getElementById('safari_formDiv'); + } + + function getRememberElement() + { + return document.getElementById("safari_remember_field"); + } + + // Get the Flash player object for performing ExternalInterface callbacks. + // Updated for changes to SWFObject2. + function getPlayer(id) { + if (id && document.getElementById(id)) { + var r = document.getElementById(id); + if (typeof r.SetVariable != "undefined") { + return r; + } + else { + var o = r.getElementsByTagName("object"); + var e = r.getElementsByTagName("embed"); + if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + } + } + else { + var o = document.getElementsByTagName("object"); + var e = document.getElementsByTagName("embed"); + if (e.length > 0 && typeof e[0].SetVariable != "undefined") { + return e[0]; + } + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { + return o[0]; + } + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { + return o[1]; + } + } + return undefined; + } + + function getPlayers() { + var players = []; + if (players.length == 0) { + var tmp = document.getElementsByTagName('object'); + players = tmp; + } + + if (players.length == 0 || players[0].object == null) { + var tmp = document.getElementsByTagName('embed'); + players = tmp; + } + return players; + } + + function getIframeHash() { + var doc = getHistoryFrame().contentWindow.document; + var hash = String(doc.location.search); + if (hash.length == 1 && hash.charAt(0) == "?") { + hash = ""; + } + else if (hash.length >= 2 && hash.charAt(0) == "?") { + hash = hash.substring(1); + } + return hash; + } + + /* Get the current location hash excluding the '#' symbol. */ + function getHash() { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + var idx = document.location.href.indexOf('#'); + return (idx >= 0) ? document.location.href.substr(idx+1) : ''; + } + + /* Get the current location hash excluding the '#' symbol. */ + function setHash(hash) { + // It would be nice if we could use document.location.hash here, + // but it's faulty sometimes. + if (hash == '') hash = '#' + document.location.hash = hash; + } + + function createState(baseUrl, newUrl, flexAppUrl) { + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; + } + + /* Add a history entry to the browser. + * baseUrl: the portion of the location prior to the '#' + * newUrl: the entire new URL, including '#' and following fragment + * flexAppUrl: the portion of the location following the '#' only + */ + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { + + //delete all the history entries + forwardStack = []; + + if (browser.ie) { + //Check to see if we are being asked to do a navigate for the first + //history entry, and if so ignore, because it's coming from the creation + //of the history iframe + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { + currentHref = initialHref; + return; + } + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { + newUrl = baseUrl + '#' + defaultHash; + flexAppUrl = defaultHash; + } else { + // for IE, tell the history frame to go somewhere without a '#' + // in order to get this entry into the browser history. + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; + } + setHash(flexAppUrl); + } else { + + //ADR + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { + initialState = createState(baseUrl, newUrl, flexAppUrl); + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); + } + + if (browser.safari) { + // for Safari, submit a form whose action points to the desired URL + if (browser.version <= 419.3) { + var file = window.location.pathname.toString(); + file = file.substring(file.lastIndexOf("/")+1); + getFormElement().innerHTML = '
      '; + //get the current elements and add them to the form + var qs = window.location.search.substring(1); + var qs_arr = qs.split("&"); + for (var i = 0; i < qs_arr.length; i++) { + var tmp = qs_arr[i].split("="); + var elem = document.createElement("input"); + elem.type = "hidden"; + elem.name = tmp[0]; + elem.value = tmp[1]; + document.forms.historyForm.appendChild(elem); + } + document.forms.historyForm.submit(); + } else { + top.location.hash = flexAppUrl; + } + // We also have to maintain the history by hand for Safari + historyHash[history.length] = flexAppUrl; + _storeStates(); + } else { + // Otherwise, write an anchor into the page and tell the browser to go there + addAnchor(flexAppUrl); + setHash(flexAppUrl); + } + } + backStack.push(createState(baseUrl, newUrl, flexAppUrl)); + } + + function _storeStates() { + if (browser.safari) { + getRememberElement().value = historyHash.join(","); + } + } + + function handleBackButton() { + //The "current" page is always at the top of the history stack. + var current = backStack.pop(); + if (!current) { return; } + var last = backStack[backStack.length - 1]; + if (!last && backStack.length == 0){ + last = initialState; + } + forwardStack.push(current); + } + + function handleForwardButton() { + //summary: private method. Do not call this directly. + + var last = forwardStack.pop(); + if (!last) { return; } + backStack.push(last); + } + + function handleArbitraryUrl() { + //delete all the history entries + forwardStack = []; + } + + /* Called periodically to poll to see if we need to detect navigation that has occurred */ + function checkForUrlChange() { + + if (browser.ie) { + if (currentHref != document.location.href && currentHref + '#' != document.location.href) { + //This occurs when the user has navigated to a specific URL + //within the app, and didn't use browser back/forward + //IE seems to have a bug where it stops updating the URL it + //shows the end-user at this point, but programatically it + //appears to be correct. Do a full app reload to get around + //this issue. + if (browser.version < 7) { + currentHref = document.location.href; + document.location.reload(); + } else { + if (getHash() != getIframeHash()) { + // this.iframe.src = this.blankURL + hash; + var sourceToSet = historyFrameSourcePrefix + getHash(); + getHistoryFrame().src = sourceToSet; + } + } + } + } + + if (browser.safari) { + // For Safari, we have to check to see if history.length changed. + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); + // If it did change, then we have to look the old state up + // in our hand-maintained array since document.location.hash + // won't have changed, then call back into BrowserManager. + currentHistoryLength = history.length; + var flexAppUrl = historyHash[currentHistoryLength]; + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + _storeStates(); + } + } + if (browser.firefox) { + if (currentHref != document.location.href) { + var bsl = backStack.length; + + var urlActions = { + back: false, + forward: false, + set: false + } + + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { + urlActions.back = true; + // FIXME: could this ever be a forward button? + // we can't clear it because we still need to check for forwards. Ugg. + // clearInterval(this.locationTimer); + handleBackButton(); + } + + // first check to see if we could have gone forward. We always halt on + // a no-hash item. + if (forwardStack.length > 0) { + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { + urlActions.forward = true; + handleForwardButton(); + } + } + + // ok, that didn't work, try someplace back in the history stack + if ((bsl >= 2) && (backStack[bsl - 2])) { + if (backStack[bsl - 2].flexAppUrl == getHash()) { + urlActions.back = true; + handleBackButton(); + } + } + + if (!urlActions.back && !urlActions.forward) { + var foundInStacks = { + back: -1, + forward: -1 + } + + for (var i = 0; i < backStack.length; i++) { + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.back = i; + } + } + for (var i = 0; i < forwardStack.length; i++) { + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { + arbitraryUrl = true; + foundInStacks.forward = i; + } + } + handleArbitraryUrl(); + } + + // Firefox changed; do a callback into BrowserManager to tell it. + currentHref = document.location.href; + var flexAppUrl = getHash(); + if (flexAppUrl == '') { + //flexAppUrl = defaultHash; + } + //ADR: to fix multiple + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + pl[i].browserURLChange(flexAppUrl); + } + } else { + getPlayer().browserURLChange(flexAppUrl); + } + } + } + //setTimeout(checkForUrlChange, 50); + } + + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ + function addAnchor(flexAppUrl) + { + if (document.getElementsByName(flexAppUrl).length == 0) { + getAnchorElement().innerHTML += "" + flexAppUrl + ""; + } + } + + var _initialize = function () { + if (browser.ie) + { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); + } + } + historyFrameSourcePrefix = iframe_location + "?"; + var src = historyFrameSourcePrefix; + + var iframe = document.createElement("iframe"); + iframe.id = 'ie_historyFrame'; + iframe.name = 'ie_historyFrame'; + //iframe.src = historyFrameSourcePrefix; + try { + document.body.appendChild(iframe); + } catch(e) { + setTimeout(function() { + document.body.appendChild(iframe); + }, 0); + } + } + + if (browser.safari) + { + var rememberDiv = document.createElement("div"); + rememberDiv.id = 'safari_rememberDiv'; + document.body.appendChild(rememberDiv); + rememberDiv.innerHTML = ''; + + var formDiv = document.createElement("div"); + formDiv.id = 'safari_formDiv'; + document.body.appendChild(formDiv); + + var reloader_content = document.createElement('div'); + reloader_content.id = 'safarireloader'; + var scripts = document.getElementsByTagName('script'); + for (var i = 0, s; s = scripts[i]; i++) { + if (s.src.indexOf("history.js") > -1) { + html = (new String(s.src)).replace(".js", ".html"); + } + } + reloader_content.innerHTML = ''; + document.body.appendChild(reloader_content); + reloader_content.style.position = 'absolute'; + reloader_content.style.left = reloader_content.style.top = '-9999px'; + iframe = reloader_content.getElementsByTagName('iframe')[0]; + + if (document.getElementById("safari_remember_field").value != "" ) { + historyHash = document.getElementById("safari_remember_field").value.split(","); + } + + } + + if (browser.firefox) + { + var anchorDiv = document.createElement("div"); + anchorDiv.id = 'firefox_anchorDiv'; + document.body.appendChild(anchorDiv); + } + + //setTimeout(checkForUrlChange, 50); + } + + return { + historyHash: historyHash, + backStack: function() { return backStack; }, + forwardStack: function() { return forwardStack }, + getPlayer: getPlayer, + initialize: function(src) { + _initialize(src); + }, + setURL: function(url) { + document.location.href = url; + }, + getURL: function() { + return document.location.href; + }, + getTitle: function() { + return document.title; + }, + setTitle: function(title) { + try { + backStack[backStack.length - 1].title = title; + } catch(e) { } + //if on safari, set the title to be the empty string. + if (browser.safari) { + if (title == "") { + try { + var tmp = window.location.href.toString(); + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); + } catch(e) { + title = ""; + } + } + } + document.title = title; + }, + setDefaultURL: function(def) + { + defaultHash = def; + def = getHash(); + //trailing ? is important else an extra frame gets added to the history + //when navigating back to the first page. Alternatively could check + //in history frame navigation to compare # and ?. + if (browser.ie) + { + window['_ie_firstload'] = true; + var sourceToSet = historyFrameSourcePrefix + def; + var func = function() { + getHistoryFrame().src = sourceToSet; + window.location.replace("#" + def); + setInterval(checkForUrlChange, 50); + } + try { + func(); + } catch(e) { + window.setTimeout(function() { func(); }, 0); + } + } + + if (browser.safari) + { + currentHistoryLength = history.length; + if (historyHash.length == 0) { + historyHash[currentHistoryLength] = def; + var newloc = "#" + def; + window.location.replace(newloc); + } else { + //alert(historyHash[historyHash.length-1]); + } + //setHash(def); + setInterval(checkForUrlChange, 50); + } + + + if (browser.firefox || browser.opera) + { + var reg = new RegExp("#" + def + "$"); + if (window.location.toString().match(reg)) { + } else { + var newloc ="#" + def; + window.location.replace(newloc); + } + setInterval(checkForUrlChange, 50); + //setHash(def); + } + + }, + + /* Set the current browser URL; called from inside BrowserManager to propagate + * the application state out to the container. + */ + setBrowserURL: function(flexAppUrl, objectId) { + if (browser.ie && typeof objectId != "undefined") { + currentObjectId = objectId; + } + //fromIframe = fromIframe || false; + //fromFlex = fromFlex || false; + //alert("setBrowserURL: " + flexAppUrl); + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; + + var pos = document.location.href.indexOf('#'); + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; + var newUrl = baseUrl + '#' + flexAppUrl; + + if (document.location.href != newUrl && document.location.href + '#' != newUrl) { + currentHref = newUrl; + addHistoryEntry(baseUrl, newUrl, flexAppUrl); + currentHistoryLength = history.length; + } + + return false; + }, + + browserURLChange: function(flexAppUrl) { + var objectId = null; + if (browser.ie && currentObjectId != null) { + objectId = currentObjectId; + } + pendingURL = ''; + + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { + var pl = getPlayers(); + for (var i = 0; i < pl.length; i++) { + try { + pl[i].browserURLChange(flexAppUrl); + } catch(e) { } + } + } else { + try { + getPlayer(objectId).browserURLChange(flexAppUrl); + } catch(e) { } + } + + currentObjectId = null; + } + + } + +})(); + +// Initialization + +// Automated unit testing and other diagnostics + +function setURL(url) +{ + document.location.href = url; +} + +function backButton() +{ + history.back(); +} + +function forwardButton() +{ + history.forward(); +} + +function goForwardOrBackInHistory(step) +{ + history.go(step); +} + +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); +(function(i) { + var u =navigator.userAgent;var e=/*@cc_on!@*/false; + var st = setTimeout; + if(/webkit/i.test(u)){ + st(function(){ + var dr=document.readyState; + if(dr=="loaded"||dr=="complete"){i()} + else{st(arguments.callee,10);}},10); + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ + document.addEventListener("DOMContentLoaded",i,false); + } else if(e){ + (function(){ + var t=document.createElement('doc:rdy'); + try{t.doScroll('left'); + i();t=null; + }catch(e){st(arguments.callee,0);}})(); + } else{ + window.onload=i; + } +})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/samples/VPAIDSample/html-template/history/historyFrame.html b/lib/osmf/samples/VPAIDSample/html-template/history/historyFrame.html index 07e3806..aebb8d8 100644 --- a/lib/osmf/samples/VPAIDSample/html-template/history/historyFrame.html +++ b/lib/osmf/samples/VPAIDSample/html-template/history/historyFrame.html @@ -1,29 +1,29 @@ - - - - - - - - Hidden frame for Browser History support. - - + + + + + + + + Hidden frame for Browser History support. + + diff --git a/lib/osmf/samples/VPAIDSample/html-template/index.template.html b/lib/osmf/samples/VPAIDSample/html-template/index.template.html index 5d942c4..781e143 100644 --- a/lib/osmf/samples/VPAIDSample/html-template/index.template.html +++ b/lib/osmf/samples/VPAIDSample/html-template/index.template.html @@ -1,124 +1,124 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - + + + + + + + + + + + + +${title} + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VPAIDSample/readme.txt b/lib/osmf/samples/VPAIDSample/readme.txt index b0556b6..67d6533 100644 --- a/lib/osmf/samples/VPAIDSample/readme.txt +++ b/lib/osmf/samples/VPAIDSample/readme.txt @@ -1,13 +1,13 @@ -This is a simple player to allow testers to test different VPAID creatives without the presence of VAST. - -Steps to test: -Publish VPAIDSample.fla -Launch VPAIDSample.html to test the video player - -Expected results: -Content video will play. - -Additional Instructions: -To test other creatives, change chosenLinear to any of the other constants in the list preceding it. E.g.: - public static const chosenLinear:String = LINEAR_VPAID; +This is a simple player to allow testers to test different VPAID creatives without the presence of VAST. + +Steps to test: +Publish VPAIDSample.fla +Launch VPAIDSample.html to test the video player + +Expected results: +Content video will play. + +Additional Instructions: +To test other creatives, change chosenLinear to any of the other constants in the list preceding it. E.g.: + public static const chosenLinear:String = LINEAR_VPAID; public static const chosenNonLinear:String = NONLINEAR_VPAID; \ No newline at end of file diff --git a/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/IVPAID.as b/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/IVPAID.as index a3f1f4b..ede2907 100644 --- a/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/IVPAID.as +++ b/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/IVPAID.as @@ -1,28 +1,28 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package { - - public interface IVPAID{ - //Properties - - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package { + + public interface IVPAID{ + //Properties + + } +} diff --git a/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/VPAIDAd.as b/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/VPAIDAd.as index 2ce88b4..d391650 100644 --- a/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/VPAIDAd.as +++ b/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/VPAIDAd.as @@ -1,230 +1,230 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ -package{ - import flash.display.MovieClip; - import flash.events.Event; - import flash.events.EventDispatcher; - - public class VPAIDAd extends EventDispatcher implements IVPAID - { - //Vars - private var _adRoot:MovieClip; - private var _adLinear:Boolean = true; - private var _adExpanded:Boolean; - private var _adRemainingTime:Number; - private var _adVolume:Number; - private var _adVPAIDVersion:String = "1.0"; - private var _playerVPAIDVersion:String; - private var _adWidth:Number; - private var _adHeight:Number; - private var _adViewMode:String; - private var _desiredBitrate:Number; - private var _creativeData:String; - private var _environmentVars:String; - - //VPAID 1.0 Variables - private var _linear:Boolean; - private var _expanded:Boolean; - private var _hasQuartileEvents:Boolean; - private var _remainingTime:Number; - private var _closeTime:Number; - private var _volume:Number; - - - - /** - * Constructor - * @param adRoot A reference to the mainTimeline of the creative swf. - */ - public function VPAIDAd(adRoot:MovieClip) - { - trace("[VPAIDAd] VPAIDAd instance created"); - _adRoot = adRoot; - - } - - //Properties - - public function handshakeVersion(playerVPAIDVersion:String):String - { - - return "1.1"; - } - - /** - * Starts the ad experience. - * - * @param width Indicates the width of the display area for the advertisement - * @param height Indicates the height of the display area for the advertisement - * @param viewMode Indicates the player current viewing mode as defined by the player. - */ - public function initAd(width:Number,height:Number,viewMode:String, desiredBitrate:Number, creativeData:String = null, environmentVars:String = null):void - { - - trace("Init Ad"); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdLoaded)); - } - - /** - * Called when the player wants the advertisement to start displaying. - */ - public function startAd():void - { - trace("Start Ad"); - - - - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdStarted)); - - } - - /** - * Called by the player to allow the advertisement to scale or reposition itself within its display area. - * @param width - * @param height - * @param viewMode - */ - public function resizeAd(width:Number, height:Number, viewMode:String):void - { - - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdLinearChange)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdUserAcceptInvitation)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdLinearChange)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdUserMinimize)); - - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdLog, {message:"This is a test Adlog message "})); - - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdImpression)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoStart)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoFirstQuartile)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoMidpoint)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoThirdQuartile)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoComplete)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdClickThru)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdError)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdExpandedChange)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdPlaying)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdPaused)); - - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdCreativeView)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdUnmute)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdMute)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdRewind)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdResume)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdFullscreen)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdExpand)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdCollapse)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdClose)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdStopped)); - dispatchEvent(new VPAIDEvent(VPAIDEvent.AdUserClose)); - - } - - /** - * Called when the player wants the advertisement to stop displaying. - */ - public function stopAd():void - { - } - - /** - * Called when the player wants the advertisement to pause. - */ - public function pauseAd():void - { - - } - - /** - * Called when the player wants the advertisement to resume. - */ - public function resumeAd():void - { - - } - - - /** - * Called when user rollover or click a call to action. - */ - public function expandAd():void - { - - } - - /** - * Called when user click close on an advertisement. - */ - public function collapseAd():void - { - - } - - /** - * - * @return - */ - public function set adVolume(value:Number) - { - - } - - /** - * - * @return - */ - public function get adWidth():Number - { - return 320; - } - - /** - * - * @return - */ - public function get adHeight():Number - { - return 240; - } - - public function get adExpanded():Boolean - { - return false; - } - - public function get adLinear():Boolean - { - return false; - } - - public function get adVolume():Number - { - return 1; - } - - public function get adRemainingTime():Number - { - return 30; - } - - } -} +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ +package{ + import flash.display.MovieClip; + import flash.events.Event; + import flash.events.EventDispatcher; + + public class VPAIDAd extends EventDispatcher implements IVPAID + { + //Vars + private var _adRoot:MovieClip; + private var _adLinear:Boolean = true; + private var _adExpanded:Boolean; + private var _adRemainingTime:Number; + private var _adVolume:Number; + private var _adVPAIDVersion:String = "1.0"; + private var _playerVPAIDVersion:String; + private var _adWidth:Number; + private var _adHeight:Number; + private var _adViewMode:String; + private var _desiredBitrate:Number; + private var _creativeData:String; + private var _environmentVars:String; + + //VPAID 1.0 Variables + private var _linear:Boolean; + private var _expanded:Boolean; + private var _hasQuartileEvents:Boolean; + private var _remainingTime:Number; + private var _closeTime:Number; + private var _volume:Number; + + + + /** + * Constructor + * @param adRoot A reference to the mainTimeline of the creative swf. + */ + public function VPAIDAd(adRoot:MovieClip) + { + trace("[VPAIDAd] VPAIDAd instance created"); + _adRoot = adRoot; + + } + + //Properties + + public function handshakeVersion(playerVPAIDVersion:String):String + { + + return "1.1"; + } + + /** + * Starts the ad experience. + * + * @param width Indicates the width of the display area for the advertisement + * @param height Indicates the height of the display area for the advertisement + * @param viewMode Indicates the player current viewing mode as defined by the player. + */ + public function initAd(width:Number,height:Number,viewMode:String, desiredBitrate:Number, creativeData:String = null, environmentVars:String = null):void + { + + trace("Init Ad"); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdLoaded)); + } + + /** + * Called when the player wants the advertisement to start displaying. + */ + public function startAd():void + { + trace("Start Ad"); + + + + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdStarted)); + + } + + /** + * Called by the player to allow the advertisement to scale or reposition itself within its display area. + * @param width + * @param height + * @param viewMode + */ + public function resizeAd(width:Number, height:Number, viewMode:String):void + { + + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdLinearChange)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdUserAcceptInvitation)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdLinearChange)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdUserMinimize)); + + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdLog, {message:"This is a test Adlog message "})); + + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdImpression)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoStart)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoFirstQuartile)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoMidpoint)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoThirdQuartile)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdVideoComplete)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdClickThru)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdError)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdExpandedChange)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdPlaying)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdPaused)); + + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdCreativeView)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdUnmute)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdMute)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdRewind)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdResume)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdFullscreen)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdExpand)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdCollapse)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdClose)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdStopped)); + dispatchEvent(new VPAIDEvent(VPAIDEvent.AdUserClose)); + + } + + /** + * Called when the player wants the advertisement to stop displaying. + */ + public function stopAd():void + { + } + + /** + * Called when the player wants the advertisement to pause. + */ + public function pauseAd():void + { + + } + + /** + * Called when the player wants the advertisement to resume. + */ + public function resumeAd():void + { + + } + + + /** + * Called when user rollover or click a call to action. + */ + public function expandAd():void + { + + } + + /** + * Called when user click close on an advertisement. + */ + public function collapseAd():void + { + + } + + /** + * + * @return + */ + public function set adVolume(value:Number) + { + + } + + /** + * + * @return + */ + public function get adWidth():Number + { + return 320; + } + + /** + * + * @return + */ + public function get adHeight():Number + { + return 240; + } + + public function get adExpanded():Boolean + { + return false; + } + + public function get adLinear():Boolean + { + return false; + } + + public function get adVolume():Number + { + return 1; + } + + public function get adRemainingTime():Number + { + return 30; + } + + } +} diff --git a/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/VPAIDEvent.as b/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/VPAIDEvent.as index 295a7af..32234b1 100644 --- a/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/VPAIDEvent.as +++ b/lib/osmf/samples/VPAIDSample/src/VPAIDLoader_as3/VPAIDEvent.as @@ -1,91 +1,91 @@ -/***************************************************** -* -* Copyright 2010 Eyewonder, LLC. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Eyewonder, LLC. -* Portions created by Eyewonder, LLC. are Copyright (C) 2010 -* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. -* -*****************************************************/ - package { - - import flash.events.Event; - - public class VPAIDEvent extends Event{ - - public static const AdLoaded:String = "AdLoaded"; - public static const AdStarted:String = "AdStarted"; - public static const AdStopped:String = "AdStopped"; - public static const AdLinearChange:String = "AdLinearChange"; - public static const AdExpandedChange:String = "AdExpandedChange"; - public static const AdRemainingTimeChange:String = "AdRemainingTimeChange"; - public static const AdVolumeChange:String = "AdVolumeChange"; - public static const AdImpression:String = "AdImpression"; - public static const AdVideoStart:String = "AdVideoStart"; - public static const AdVideoFirstQuartile:String = "AdVideoFirstQuartile"; - public static const AdVideoMidpoint:String = "AdVideoMidpoint"; - public static const AdVideoThirdQuartile:String = "AdVideoThirdQuartile"; - public static const AdVideoComplete:String = "AdVideoComplete"; - public static const AdClickThru:String = "AdClickThru"; - public static const AdUserAcceptInvitation:String = "AdUserAcceptInvitation"; - public static const AdUserMinimize:String = "AdUserMinimize"; - public static const AdUserClose:String = "AdUserClose"; - public static const AdPaused:String = "AdPaused"; - public static const AdPlaying:String = "AdPlaying"; - public static const AdLog:String = "AdLog"; - public static const AdError:String = "AdError"; - - public static const AdCreativeView:String = "AdCreativeView"; - public static const AdUnmute:String = "AdUnmute"; - public static const AdMute:String = "AdMute"; - public static const AdRewind:String = "AdRewind"; - public static const AdResume:String = "AdResume"; - public static const AdFullscreen:String = "AdFullscreen"; - public static const AdExpand:String = "AdExpand"; - public static const AdCollapse:String = "AdCollapse"; - public static const AdClose:String = "AdClose"; - - - public static const LOADED:String = "LOADED"; - public static const STARTED:String = "STARTED"; - public static const STOPPED:String = "STOPPED"; - public static const LINEAR_CHANGE:String = "LINEAR_CHANGE"; - public static const EXPANDED_CHANGE:String = "EXPANDED_CHANGE"; - public static const REMAININGTIME_CHANGE:String = "REMAININGTIME_CHANGE"; - public static const IMPRESSION:String = "IMPRESSION"; - public static const MIDPOINT:String = "MIDPOINT"; - public static const FIRSTQUARTILE:String = "FIRSTQUARTILE"; - public static const THIRDQUARTILE:String = "THIRDQUARTILE"; - public static const COMPLETE:String = "COMPLETE"; - public static const CLICK_THRU:String = "CLICK_THRU"; - public static const ACCEPT_INVITATION:String = "ACCEPT_INVITATION"; - public static const PAUSED:String = "PAUSED"; - public static const PLAYING:String = "PLAYING"; - public static const ERROR:String = "ERROR"; - - - private var _data:Object; - - public function VPAIDEvent(type:String, data:Object = null, bubbles:Boolean = false, cancelable:Boolean = false){ - super(type,bubbles,cancelable); - _data = data; - } - - public function get data():Object{ - return _data; - } - - } - } +/***************************************************** +* +* Copyright 2010 Eyewonder, LLC. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Eyewonder, LLC. +* Portions created by Eyewonder, LLC. are Copyright (C) 2010 +* Eyewonder, LLC. A Limelight Networks Business. All Rights Reserved. +* +*****************************************************/ + package { + + import flash.events.Event; + + public class VPAIDEvent extends Event{ + + public static const AdLoaded:String = "AdLoaded"; + public static const AdStarted:String = "AdStarted"; + public static const AdStopped:String = "AdStopped"; + public static const AdLinearChange:String = "AdLinearChange"; + public static const AdExpandedChange:String = "AdExpandedChange"; + public static const AdRemainingTimeChange:String = "AdRemainingTimeChange"; + public static const AdVolumeChange:String = "AdVolumeChange"; + public static const AdImpression:String = "AdImpression"; + public static const AdVideoStart:String = "AdVideoStart"; + public static const AdVideoFirstQuartile:String = "AdVideoFirstQuartile"; + public static const AdVideoMidpoint:String = "AdVideoMidpoint"; + public static const AdVideoThirdQuartile:String = "AdVideoThirdQuartile"; + public static const AdVideoComplete:String = "AdVideoComplete"; + public static const AdClickThru:String = "AdClickThru"; + public static const AdUserAcceptInvitation:String = "AdUserAcceptInvitation"; + public static const AdUserMinimize:String = "AdUserMinimize"; + public static const AdUserClose:String = "AdUserClose"; + public static const AdPaused:String = "AdPaused"; + public static const AdPlaying:String = "AdPlaying"; + public static const AdLog:String = "AdLog"; + public static const AdError:String = "AdError"; + + public static const AdCreativeView:String = "AdCreativeView"; + public static const AdUnmute:String = "AdUnmute"; + public static const AdMute:String = "AdMute"; + public static const AdRewind:String = "AdRewind"; + public static const AdResume:String = "AdResume"; + public static const AdFullscreen:String = "AdFullscreen"; + public static const AdExpand:String = "AdExpand"; + public static const AdCollapse:String = "AdCollapse"; + public static const AdClose:String = "AdClose"; + + + public static const LOADED:String = "LOADED"; + public static const STARTED:String = "STARTED"; + public static const STOPPED:String = "STOPPED"; + public static const LINEAR_CHANGE:String = "LINEAR_CHANGE"; + public static const EXPANDED_CHANGE:String = "EXPANDED_CHANGE"; + public static const REMAININGTIME_CHANGE:String = "REMAININGTIME_CHANGE"; + public static const IMPRESSION:String = "IMPRESSION"; + public static const MIDPOINT:String = "MIDPOINT"; + public static const FIRSTQUARTILE:String = "FIRSTQUARTILE"; + public static const THIRDQUARTILE:String = "THIRDQUARTILE"; + public static const COMPLETE:String = "COMPLETE"; + public static const CLICK_THRU:String = "CLICK_THRU"; + public static const ACCEPT_INVITATION:String = "ACCEPT_INVITATION"; + public static const PAUSED:String = "PAUSED"; + public static const PLAYING:String = "PLAYING"; + public static const ERROR:String = "ERROR"; + + + private var _data:Object; + + public function VPAIDEvent(type:String, data:Object = null, bubbles:Boolean = false, cancelable:Boolean = false){ + super(type,bubbles,cancelable); + _data = data; + } + + public function get data():Object{ + return _data; + } + + } + } diff --git a/lib/osmf/samples/VPAIDSample/src/VPAIDSample.as b/lib/osmf/samples/VPAIDSample/src/VPAIDSample.as index 7d81731..9081eb4 100644 --- a/lib/osmf/samples/VPAIDSample/src/VPAIDSample.as +++ b/lib/osmf/samples/VPAIDSample/src/VPAIDSample.as @@ -1,421 +1,421 @@ -package { - import fl.controls.Slider; - import fl.events.SliderEvent; - - import flash.display.MovieClip; - import flash.display.Sprite; - import flash.events.MouseEvent; - - import org.osmf.containers.MediaContainer; - import org.osmf.elements.DurationElement; - import org.osmf.elements.ParallelElement; - import org.osmf.elements.SerialElement; - import org.osmf.events.LoadEvent; - import org.osmf.events.MediaElementEvent; - import org.osmf.events.MediaErrorEvent; - import org.osmf.events.MetadataEvent; - import org.osmf.events.PlayEvent; - import org.osmf.layout.ScaleMode; - import org.osmf.media.*; - import org.osmf.metadata.Metadata; - import org.osmf.traits.LoadState; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.MediaTraitType; - import org.osmf.traits.PlayTrait; - import org.osmf.vpaid.elements.VPAIDElement; - import org.osmf.vpaid.metadata.VPAIDMetadata; - - /** - * Sample OSMF Player - * - * */ - [SWF(width="480",height="360", backgroundColor="0x333333")] - public class VPAIDSample extends Sprite - { - public static const OVERLAY_DELAY:Number = 5; - public static const OVERLAY_MAX_LENGTH:Number = 10; - - private var container:MediaContainer; - private var contentResource:URLResource; - private var vpaidLinearResource:URLResource; - private var vpaidNonLinearResource:URLResource; - private var videoElement:MediaElement; - private var mediaPlayer:MediaPlayer; - private var mediaFactory:MediaFactory; - private var pluginResource:PluginInfoResource; - private var serialElement:SerialElement; - private var parallelElement:ParallelElement; - private var vpaidPrerollLinear:VPAIDElement; - private var vpaidPostrollLinear:VPAIDElement; - private var vpaidNonLinear:VPAIDElement; - private var errorOccured:Boolean = false; - private var overlayMaxLengthEnabled:Boolean = true; - private var runOverlay:Boolean = false; - private var traitInterval:Number; - private var contentPlayTraitAdded:Boolean; - - public static const NONLINEAR_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/_modules/loaders/Custom/VPAID_as3/loader.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn1.eyewonder.com/200125/752457/1224933/&loaderCreative=Ticker_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn1.eyewonder.com/200125/752457/1224933/%26ewbase%3Dhttp%3A//cdn1.eyewonder.com/200125/752457/1224933/%26adLoaderWidth%3D320%26adLoaderHeight%3D240%26hAlign%3Dcenter%26vAlign%3Dbottom%26keywordNames%3DenableFriendlyIframe%2Cinflow_iframe_div%26keywordIDs%3D[48]%2C[52]%26ewbust%3D[timestamp]&adInstreamType=ticker&adTagAlignHorizontal=center&adTagAlignVertical=bottom&adMode=prog&qaReportUUID=common"; - public static const LINEAR_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/_modules/loaders/Custom/VPAID_as3/loader.swf?adLoaderWidth=300&adLoaderHeight=225&cp=http://cdn.eyewonder.com/100125/754851/1242700/&loaderCreative=Linear_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1242700/%26amp%3Bewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1242700/%26amp%3BadLoaderWidth%3D300%26amp%3BadLoaderHeight%3D225%26amp%3BhAlign%3Dcenter%26amp%3BvAlign%3Dmiddle%26amp%3BkeywordNames%3DenableFriendlyIframe%2Cinflow_iframe_div%26amp%3BkeywordIDs%3D%5B48%5D%2C%5B52%5D%26amp%3Bewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; - public static const WRONG_VERSION_LOW:String = "http://cdn1.eyewonder.com/200125/instream/osmf/VPAID_1_0.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn.eyewonder.com/100125/754851/1262098/&loaderCreative=Linear_Interactive_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26ewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26adLoaderWidth%3D300%26adLoaderHeight%3D225%26hAlign%3Dcenter%26vAlign%3Dmiddle%26keywordNames%3Dinstream_VAST_2_0_TEST%26keywordIDs%3D%5B103%5D%26ewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; - public static const WRONG_VERSION_HIGH:String = "http://cdn1.eyewonder.com/200125/instream/osmf/VPAID_2_0.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn.eyewonder.com/100125/754851/1262098/&loaderCreative=Linear_Interactive_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26ewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26adLoaderWidth%3D300%26adLoaderHeight%3D225%26hAlign%3Dcenter%26vAlign%3Dmiddle%26keywordNames%3Dinstream_VAST_2_0_TEST%26keywordIDs%3D%5B103%5D%26ewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; - public static const BROKEN:String = "http://cdn1.eyewonder.com/200125/instream/_modules/loaders/CustomVPAID_as3/loader.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn.eyewonder.com/100125/754851/1262098/&loaderCreative=Linear_Interactive_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26ewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26adLoaderWidth%3D300%26adLoaderHeight%3D225%26hAlign%3Dcenter%26vAlign%3Dmiddle%26keywordNames%3Dinstream_VAST_2_0_TEST%26keywordIDs%3D%5B103%5D%26ewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; - public static const EMPTY:String = "http://cdn1.eyewonder.com/200125/instream/osmf/empty.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn.eyewonder.com/100125/754851/1262098/&loaderCreative=Linear_Interactive_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26ewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26adLoaderWidth%3D300%26adLoaderHeight%3D225%26hAlign%3Dcenter%26vAlign%3Dmiddle%26keywordNames%3Dinstream_VAST_2_0_TEST%26keywordIDs%3D%5B103%5D%26ewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; - - public static const CONTENT_VIDEO:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; - - private var playBtn:MovieClip; - private var pauseBtn:MovieClip; - private var fullscreenBtn:MovieClip; - private var stopBtn:MovieClip; - private var volSlider:Slider; - private var muteBtn:MovieClip; - private var unmuteBtn:MovieClip; - - private var vol:Number; - - public function VPAIDSample() - { - trace("Starting VPAIDTestplayer Video Player"); - //create a new instance of the mediaFactory to create a new video element - mediaFactory = new DefaultMediaFactory(); - //create serialElement for content video and Ads to run concurrently - serialElement = new SerialElement(); - - //create an instance of the media container for the videoElement - container = new MediaContainer(); - container.layoutMetadata.width = 480; - container.layoutMetadata.height = 360; - container.layoutMetadata.scaleMode = ScaleMode.NONE; - container.addMediaElement(serialElement); - addChild(container); - - createPlayerButtons(); - - //create ParallelElement so nonlinear Ads can run alongside the content video - parallelElement = new ParallelElement(); - - mediaPlayer = new MediaPlayer(); - mediaPlayer.autoPlay = false; - mediaPlayer.volume = vol =(volSlider.value/10); - mediaPlayer.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - - //create a new url resource including the path to a video as a parameter. - contentResource = new URLResource(CONTENT_VIDEO); - vpaidLinearResource = new URLResource(LINEAR_VPAID); - vpaidNonLinearResource = new URLResource(NONLINEAR_VPAID); - - createVideoElement(); - createVPAIDAds(); - - updateSerialElement("preroll"); - updateMediaPlayer(); - } - - private function createPlayerButtons():void - { - playBtn = new PlayButton(); - playBtn.y = stage.stageHeight - (playBtn.height + 5); - playBtn.x = 10; - addChild(playBtn); - - stopBtn = new StopButton(); - stopBtn.y = playBtn.y; - stopBtn.x = playBtn.x + playBtn.width + 5; - addChild(stopBtn); - - pauseBtn = new PauseButton(); - pauseBtn.y = playBtn.y; - pauseBtn.x = 10; - pauseBtn.visible = false; - addChild(pauseBtn); - - volSlider = new Slider(); - volSlider.y = playBtn.y + 20; - volSlider.x = stopBtn.x + stopBtn.width + 10; - volSlider.value = 7.5; - addChild(volSlider); - - fullscreenBtn = new FullScreenButton(); - fullscreenBtn.y = playBtn.y; - fullscreenBtn.x = volSlider.x + volSlider.width + 10; - addChild(fullscreenBtn); - - muteBtn = new MuteButton(); - muteBtn.y = playBtn.y; - muteBtn.x = fullscreenBtn.x + fullscreenBtn.width + 5; - addChild(muteBtn); - - unmuteBtn = new UnmuteButton(); - unmuteBtn.y = muteBtn.y; - unmuteBtn.x = muteBtn.x; - unmuteBtn.visible = false; - addChild(unmuteBtn); - } - - private function createVideoElement():void - { - trace("OSMFPlayer.createVideoElement()"); - //create a new video element passing it the url resource and add the element to the media container. - videoElement = mediaFactory.createMediaElement(new URLResource(CONTENT_VIDEO)); - - container.addMediaElement(videoElement); - - playBtn.visible = true; - pauseBtn.visible = false; - playBtn.buttonMode = true; - pauseBtn.buttonMode = true; - stopBtn.buttonMode = true; - - playBtn.addEventListener(MouseEvent.CLICK, onPlayClicked); - pauseBtn.addEventListener(MouseEvent.CLICK, onPauseClicked); - stopBtn.addEventListener(MouseEvent.CLICK, onStopClicked); - fullscreenBtn.addEventListener(MouseEvent.CLICK, onFSClicked); - volSlider.addEventListener(SliderEvent.CHANGE, onVolChanged); - muteBtn.addEventListener(MouseEvent.CLICK, onMutePressed); - unmuteBtn.addEventListener(MouseEvent.CLICK, onMutePressed); - } - - private function createVPAIDAds():void - { - //create a new VPAIDElement passing it a urlResource for a linear Ad - vpaidPrerollLinear = new VPAIDElement(vpaidLinearResource); - container.addMediaElement(vpaidPrerollLinear); - - //create a new VPAIDElement passing it a urlResource for a linear Ad - vpaidPostrollLinear = new VPAIDElement(vpaidLinearResource); - container.addMediaElement(vpaidPostrollLinear); - - //create a new VPAIDElement passing it a urlResource for a nonlinear Ad - vpaidNonLinear = new VPAIDElement(vpaidNonLinearResource); - container.addMediaElement(vpaidNonLinear); - - /** - * In situations where publishers want to run both linear and nonlinear VPAIDElements, - it is possible to attach VPAIDMetadata to the VPAIDElement to determine if its linear or nonlinear. - One example may be creating a ParallelElement if it's a nonlinear VPAIDElement. - * */ - - var vpaidOverlayMetadata:Metadata = vpaidNonLinear.getMetadata(VPAIDMetadata.NAMESPACE); - vpaidOverlayMetadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); - vpaidOverlayMetadata.addEventListener(MetadataEvent.VALUE_CHANGE, onMetadataValueChange); - vpaidOverlayMetadata.addValue(VPAIDMetadata.NON_LINEAR_CREATIVE, true); - - var vpaidPrerollMetadata:Metadata = vpaidPrerollLinear.getMetadata(VPAIDMetadata.NAMESPACE); - vpaidPrerollMetadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); - - var vpaidPostrollMetadata:Metadata = vpaidPostrollLinear.getMetadata(VPAIDMetadata.NAMESPACE); - vpaidPostrollMetadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); - - getAdTraits(); - } - - private function getAdTraits():void - { - var prerollLoadTrait:LoadTrait = vpaidPrerollLinear.getTrait(MediaTraitType.LOAD) as LoadTrait; - prerollLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - - var postrollLoadTrait:LoadTrait = vpaidPostrollLinear.getTrait(MediaTraitType.LOAD) as LoadTrait; - postrollLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - - var overlayLoadTrait:LoadTrait = vpaidNonLinear.getTrait(MediaTraitType.LOAD) as LoadTrait; - overlayLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); - - var overlayPlayTrait:PlayTrait = vpaidNonLinear.getTrait(MediaTraitType.PLAY) as PlayTrait; - overlayPlayTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); - - var prerollPlayTrait:PlayTrait = vpaidPrerollLinear.getTrait(MediaTraitType.PLAY) as PlayTrait; - prerollPlayTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); - - var postrollPlayTrait:PlayTrait = vpaidPostrollLinear.getTrait(MediaTraitType.PLAY) as PlayTrait; - postrollPlayTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); - } - - /** - * This method accepts values based on the type of Ad sequence you want to run. - * @adSequence - String represent the requested Ad sequence. - * - * Options: preroll, postroll, preroll/postroll, overlay, preroll/overlay - * - * */ - private function updateSerialElement(adSequence:String = "preroll"):void - { - switch(adSequence) - { - case "preroll": - serialElement.addChild(vpaidPrerollLinear); - serialElement.addChild(videoElement); - break; - case "postroll": - serialElement.addChild(videoElement); - serialElement.addChild(vpaidPostrollLinear); - break; - case "preroll/postroll" : - serialElement.addChild(vpaidPrerollLinear); - serialElement.addChild(videoElement); - serialElement.addChild(vpaidPostrollLinear); - break; - case "overlay" : - var newSerial1:SerialElement = new SerialElement(); - newSerial1.addChild(new DurationElement(OVERLAY_DELAY)); - newSerial1.addChild(vpaidNonLinear); - - if(vpaidNonLinear.getMetadata(VPAIDMetadata.NAMESPACE).getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) - { - parallelElement.addChild(videoElement); - parallelElement.addChild(newSerial1); - } - - serialElement.addChild(parallelElement); - serialElement.addChild(new DurationElement(OVERLAY_DELAY)); - break; - case "preroll/overlay" : - var newSerial:SerialElement = new SerialElement(); - newSerial.addChild(new DurationElement(OVERLAY_DELAY)); - newSerial.addChild(vpaidNonLinear); - - if(vpaidNonLinear.getMetadata(VPAIDMetadata.NAMESPACE).getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) - { - parallelElement.addChild(videoElement); - parallelElement.addChild(newSerial); - } - - serialElement.addChild(vpaidPrerollLinear); - serialElement.addChild(parallelElement); - serialElement.addChild(new DurationElement(OVERLAY_DELAY)); - break; - default : - serialElement.addChild(vpaidPrerollLinear); - serialElement.addChild(videoElement); - break; - } - } - - private function updateMediaPlayer():void - { - //create an instance of the media player attaching the video element to it's media property. - mediaPlayer.media = serialElement; - trace("OSMFPlayer.createMediaPlayer("+ mediaPlayer.media +")"); - } - - private function onPlayClicked(e:MouseEvent):void - { - trace("OSMF_Player.onPlayClicked " ); - mediaPlayer.play(); - playBtn.visible = false; - pauseBtn.visible = true; - } - - private function onPauseClicked(e:MouseEvent):void - { - mediaPlayer.pause(); - pauseBtn.visible = false; - playBtn.visible = true; - } - - private function onStopClicked(e:MouseEvent):void - { - mediaPlayer.stop(); - } - - private function onTraitAdd(e:MediaElementEvent):void - { - trace("OSMF_Player.onTraitAdd - " + e.traitType); - if(e.traitType == MediaTraitType.PLAY) - { - contentPlayTraitAdded = true; - trace("OSMF_Player.onTraitAdd -- Content Play Trait Added " ); - playContent(); - } - } - - private function onMediaError(e:MediaErrorEvent):void - { - trace("OSMF_Player.onMediaError - There is an error with the player or the specified media cannot be played "); - mediaPlayer.media = videoElement; - videoElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - - private function onFSClicked(e:MouseEvent):void - { - switch(stage.displayState) - { - case "normal": - stage.displayState = "fullScreen"; - break; - case "fullScreen": - default: - stage.displayState = "normal"; - break; - } - } - - private function onLoadStateChange(e:LoadEvent):void - { - trace("EWTestplayer.onLoadStateChange " + e.loadState); - if(e.loadState == LoadState.UNINITIALIZED) - { - vpaidPrerollLinear = null; - trace("EWTestplayer.onLoadStateChange"); - } - } - - private function playContent():void - { - trace("Playing Content Video"); - mediaPlayer.play(); - } - - private function onMetadataValueAdded(e:MetadataEvent):void - { - trace("EWTestplayer.onMetadataValueAdded() " + e.key); - if(e.key == "error") - { - mediaPlayer.media = videoElement; - videoElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); - } - } - - private function onMetadataValueChange(e:MetadataEvent):void - { - trace("EWTestplayer.onMetadataValueChange() " + e.target.getValue(e.key)); - } - - private function onContentLoadChange(e:LoadEvent):void - { - trace("EWTestplayer.onContentLoadChange() " + e.loadState); - } - - private function onPlayStateChange(e:PlayEvent):void - { - trace("EWTestplayer.onPlayStateChange " + e.playState); - } - - private function onVolChanged(e:SliderEvent):void - { - trace("Slider Volume Changed " + (e.target.value/10) ); - vol = (e.target.value/10); - mediaPlayer.volume = vol; - } - - private function onMutePressed(event:MouseEvent):void - { - if(muteBtn.visible){ - muteBtn.visible = false; - unmuteBtn.visible = true; - }else{ - muteBtn.visible = true; - unmuteBtn.visible = false; - } - - if(vol != 0) - { - if(mediaPlayer.muted){ - mediaPlayer.muted = false; - }else{ - mediaPlayer.muted = true; - } - } - } - - } -} +package { + import fl.controls.Slider; + import fl.events.SliderEvent; + + import flash.display.MovieClip; + import flash.display.Sprite; + import flash.events.MouseEvent; + + import org.osmf.containers.MediaContainer; + import org.osmf.elements.DurationElement; + import org.osmf.elements.ParallelElement; + import org.osmf.elements.SerialElement; + import org.osmf.events.LoadEvent; + import org.osmf.events.MediaElementEvent; + import org.osmf.events.MediaErrorEvent; + import org.osmf.events.MetadataEvent; + import org.osmf.events.PlayEvent; + import org.osmf.layout.ScaleMode; + import org.osmf.media.*; + import org.osmf.metadata.Metadata; + import org.osmf.traits.LoadState; + import org.osmf.traits.LoadTrait; + import org.osmf.traits.MediaTraitType; + import org.osmf.traits.PlayTrait; + import org.osmf.vpaid.elements.VPAIDElement; + import org.osmf.vpaid.metadata.VPAIDMetadata; + + /** + * Sample OSMF Player + * + * */ + [SWF(width="480",height="360", backgroundColor="0x333333")] + public class VPAIDSample extends Sprite + { + public static const OVERLAY_DELAY:Number = 5; + public static const OVERLAY_MAX_LENGTH:Number = 10; + + private var container:MediaContainer; + private var contentResource:URLResource; + private var vpaidLinearResource:URLResource; + private var vpaidNonLinearResource:URLResource; + private var videoElement:MediaElement; + private var mediaPlayer:MediaPlayer; + private var mediaFactory:MediaFactory; + private var pluginResource:PluginInfoResource; + private var serialElement:SerialElement; + private var parallelElement:ParallelElement; + private var vpaidPrerollLinear:VPAIDElement; + private var vpaidPostrollLinear:VPAIDElement; + private var vpaidNonLinear:VPAIDElement; + private var errorOccured:Boolean = false; + private var overlayMaxLengthEnabled:Boolean = true; + private var runOverlay:Boolean = false; + private var traitInterval:Number; + private var contentPlayTraitAdded:Boolean; + + public static const NONLINEAR_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/_modules/loaders/Custom/VPAID_as3/loader.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn1.eyewonder.com/200125/752457/1224933/&loaderCreative=Ticker_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn1.eyewonder.com/200125/752457/1224933/%26ewbase%3Dhttp%3A//cdn1.eyewonder.com/200125/752457/1224933/%26adLoaderWidth%3D320%26adLoaderHeight%3D240%26hAlign%3Dcenter%26vAlign%3Dbottom%26keywordNames%3DenableFriendlyIframe%2Cinflow_iframe_div%26keywordIDs%3D[48]%2C[52]%26ewbust%3D[timestamp]&adInstreamType=ticker&adTagAlignHorizontal=center&adTagAlignVertical=bottom&adMode=prog&qaReportUUID=common"; + public static const LINEAR_VPAID:String = "http://cdn1.eyewonder.com/200125/instream/_modules/loaders/Custom/VPAID_as3/loader.swf?adLoaderWidth=300&adLoaderHeight=225&cp=http://cdn.eyewonder.com/100125/754851/1242700/&loaderCreative=Linear_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1242700/%26amp%3Bewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1242700/%26amp%3BadLoaderWidth%3D300%26amp%3BadLoaderHeight%3D225%26amp%3BhAlign%3Dcenter%26amp%3BvAlign%3Dmiddle%26amp%3BkeywordNames%3DenableFriendlyIframe%2Cinflow_iframe_div%26amp%3BkeywordIDs%3D%5B48%5D%2C%5B52%5D%26amp%3Bewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; + public static const WRONG_VERSION_LOW:String = "http://cdn1.eyewonder.com/200125/instream/osmf/VPAID_1_0.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn.eyewonder.com/100125/754851/1262098/&loaderCreative=Linear_Interactive_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26ewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26adLoaderWidth%3D300%26adLoaderHeight%3D225%26hAlign%3Dcenter%26vAlign%3Dmiddle%26keywordNames%3Dinstream_VAST_2_0_TEST%26keywordIDs%3D%5B103%5D%26ewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; + public static const WRONG_VERSION_HIGH:String = "http://cdn1.eyewonder.com/200125/instream/osmf/VPAID_2_0.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn.eyewonder.com/100125/754851/1262098/&loaderCreative=Linear_Interactive_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26ewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26adLoaderWidth%3D300%26adLoaderHeight%3D225%26hAlign%3Dcenter%26vAlign%3Dmiddle%26keywordNames%3Dinstream_VAST_2_0_TEST%26keywordIDs%3D%5B103%5D%26ewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; + public static const BROKEN:String = "http://cdn1.eyewonder.com/200125/instream/_modules/loaders/CustomVPAID_as3/loader.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn.eyewonder.com/100125/754851/1262098/&loaderCreative=Linear_Interactive_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26ewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26adLoaderWidth%3D300%26adLoaderHeight%3D225%26hAlign%3Dcenter%26vAlign%3Dmiddle%26keywordNames%3Dinstream_VAST_2_0_TEST%26keywordIDs%3D%5B103%5D%26ewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; + public static const EMPTY:String = "http://cdn1.eyewonder.com/200125/instream/osmf/empty.swf?adLoaderWidth=320&adLoaderHeight=240&cp=http://cdn.eyewonder.com/100125/754851/1262098/&loaderCreative=Linear_Interactive_Holder_as3.swf%3Fcp%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26ewbase%3Dhttp%3A//cdn.eyewonder.com/100125/754851/1262098/%26adLoaderWidth%3D300%26adLoaderHeight%3D225%26hAlign%3Dcenter%26vAlign%3Dmiddle%26keywordNames%3Dinstream_VAST_2_0_TEST%26keywordIDs%3D%5B103%5D%26ewbust%3D%5Btimestamp%5D&adInstreamType=fixedroll&adTagAlignHorizontal=center&adTagAlignVertical=middle&adMode=prog&qaReportUUID=common"; + + public static const CONTENT_VIDEO:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"; + + private var playBtn:MovieClip; + private var pauseBtn:MovieClip; + private var fullscreenBtn:MovieClip; + private var stopBtn:MovieClip; + private var volSlider:Slider; + private var muteBtn:MovieClip; + private var unmuteBtn:MovieClip; + + private var vol:Number; + + public function VPAIDSample() + { + trace("Starting VPAIDTestplayer Video Player"); + //create a new instance of the mediaFactory to create a new video element + mediaFactory = new DefaultMediaFactory(); + //create serialElement for content video and Ads to run concurrently + serialElement = new SerialElement(); + + //create an instance of the media container for the videoElement + container = new MediaContainer(); + container.layoutMetadata.width = 480; + container.layoutMetadata.height = 360; + container.layoutMetadata.scaleMode = ScaleMode.NONE; + container.addMediaElement(serialElement); + addChild(container); + + createPlayerButtons(); + + //create ParallelElement so nonlinear Ads can run alongside the content video + parallelElement = new ParallelElement(); + + mediaPlayer = new MediaPlayer(); + mediaPlayer.autoPlay = false; + mediaPlayer.volume = vol =(volSlider.value/10); + mediaPlayer.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); + + //create a new url resource including the path to a video as a parameter. + contentResource = new URLResource(CONTENT_VIDEO); + vpaidLinearResource = new URLResource(LINEAR_VPAID); + vpaidNonLinearResource = new URLResource(NONLINEAR_VPAID); + + createVideoElement(); + createVPAIDAds(); + + updateSerialElement("preroll"); + updateMediaPlayer(); + } + + private function createPlayerButtons():void + { + playBtn = new PlayButton(); + playBtn.y = stage.stageHeight - (playBtn.height + 5); + playBtn.x = 10; + addChild(playBtn); + + stopBtn = new StopButton(); + stopBtn.y = playBtn.y; + stopBtn.x = playBtn.x + playBtn.width + 5; + addChild(stopBtn); + + pauseBtn = new PauseButton(); + pauseBtn.y = playBtn.y; + pauseBtn.x = 10; + pauseBtn.visible = false; + addChild(pauseBtn); + + volSlider = new Slider(); + volSlider.y = playBtn.y + 20; + volSlider.x = stopBtn.x + stopBtn.width + 10; + volSlider.value = 7.5; + addChild(volSlider); + + fullscreenBtn = new FullScreenButton(); + fullscreenBtn.y = playBtn.y; + fullscreenBtn.x = volSlider.x + volSlider.width + 10; + addChild(fullscreenBtn); + + muteBtn = new MuteButton(); + muteBtn.y = playBtn.y; + muteBtn.x = fullscreenBtn.x + fullscreenBtn.width + 5; + addChild(muteBtn); + + unmuteBtn = new UnmuteButton(); + unmuteBtn.y = muteBtn.y; + unmuteBtn.x = muteBtn.x; + unmuteBtn.visible = false; + addChild(unmuteBtn); + } + + private function createVideoElement():void + { + trace("OSMFPlayer.createVideoElement()"); + //create a new video element passing it the url resource and add the element to the media container. + videoElement = mediaFactory.createMediaElement(new URLResource(CONTENT_VIDEO)); + + container.addMediaElement(videoElement); + + playBtn.visible = true; + pauseBtn.visible = false; + playBtn.buttonMode = true; + pauseBtn.buttonMode = true; + stopBtn.buttonMode = true; + + playBtn.addEventListener(MouseEvent.CLICK, onPlayClicked); + pauseBtn.addEventListener(MouseEvent.CLICK, onPauseClicked); + stopBtn.addEventListener(MouseEvent.CLICK, onStopClicked); + fullscreenBtn.addEventListener(MouseEvent.CLICK, onFSClicked); + volSlider.addEventListener(SliderEvent.CHANGE, onVolChanged); + muteBtn.addEventListener(MouseEvent.CLICK, onMutePressed); + unmuteBtn.addEventListener(MouseEvent.CLICK, onMutePressed); + } + + private function createVPAIDAds():void + { + //create a new VPAIDElement passing it a urlResource for a linear Ad + vpaidPrerollLinear = new VPAIDElement(vpaidLinearResource); + container.addMediaElement(vpaidPrerollLinear); + + //create a new VPAIDElement passing it a urlResource for a linear Ad + vpaidPostrollLinear = new VPAIDElement(vpaidLinearResource); + container.addMediaElement(vpaidPostrollLinear); + + //create a new VPAIDElement passing it a urlResource for a nonlinear Ad + vpaidNonLinear = new VPAIDElement(vpaidNonLinearResource); + container.addMediaElement(vpaidNonLinear); + + /** + * In situations where publishers want to run both linear and nonlinear VPAIDElements, + it is possible to attach VPAIDMetadata to the VPAIDElement to determine if its linear or nonlinear. + One example may be creating a ParallelElement if it's a nonlinear VPAIDElement. + * */ + + var vpaidOverlayMetadata:Metadata = vpaidNonLinear.getMetadata(VPAIDMetadata.NAMESPACE); + vpaidOverlayMetadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); + vpaidOverlayMetadata.addEventListener(MetadataEvent.VALUE_CHANGE, onMetadataValueChange); + vpaidOverlayMetadata.addValue(VPAIDMetadata.NON_LINEAR_CREATIVE, true); + + var vpaidPrerollMetadata:Metadata = vpaidPrerollLinear.getMetadata(VPAIDMetadata.NAMESPACE); + vpaidPrerollMetadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); + + var vpaidPostrollMetadata:Metadata = vpaidPostrollLinear.getMetadata(VPAIDMetadata.NAMESPACE); + vpaidPostrollMetadata.addEventListener(MetadataEvent.VALUE_ADD, onMetadataValueAdded); + + getAdTraits(); + } + + private function getAdTraits():void + { + var prerollLoadTrait:LoadTrait = vpaidPrerollLinear.getTrait(MediaTraitType.LOAD) as LoadTrait; + prerollLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + + var postrollLoadTrait:LoadTrait = vpaidPostrollLinear.getTrait(MediaTraitType.LOAD) as LoadTrait; + postrollLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + + var overlayLoadTrait:LoadTrait = vpaidNonLinear.getTrait(MediaTraitType.LOAD) as LoadTrait; + overlayLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange); + + var overlayPlayTrait:PlayTrait = vpaidNonLinear.getTrait(MediaTraitType.PLAY) as PlayTrait; + overlayPlayTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); + + var prerollPlayTrait:PlayTrait = vpaidPrerollLinear.getTrait(MediaTraitType.PLAY) as PlayTrait; + prerollPlayTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); + + var postrollPlayTrait:PlayTrait = vpaidPostrollLinear.getTrait(MediaTraitType.PLAY) as PlayTrait; + postrollPlayTrait.addEventListener(PlayEvent.PLAY_STATE_CHANGE, onPlayStateChange); + } + + /** + * This method accepts values based on the type of Ad sequence you want to run. + * @adSequence - String represent the requested Ad sequence. + * + * Options: preroll, postroll, preroll/postroll, overlay, preroll/overlay + * + * */ + private function updateSerialElement(adSequence:String = "preroll"):void + { + switch(adSequence) + { + case "preroll": + serialElement.addChild(vpaidPrerollLinear); + serialElement.addChild(videoElement); + break; + case "postroll": + serialElement.addChild(videoElement); + serialElement.addChild(vpaidPostrollLinear); + break; + case "preroll/postroll" : + serialElement.addChild(vpaidPrerollLinear); + serialElement.addChild(videoElement); + serialElement.addChild(vpaidPostrollLinear); + break; + case "overlay" : + var newSerial1:SerialElement = new SerialElement(); + newSerial1.addChild(new DurationElement(OVERLAY_DELAY)); + newSerial1.addChild(vpaidNonLinear); + + if(vpaidNonLinear.getMetadata(VPAIDMetadata.NAMESPACE).getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) + { + parallelElement.addChild(videoElement); + parallelElement.addChild(newSerial1); + } + + serialElement.addChild(parallelElement); + serialElement.addChild(new DurationElement(OVERLAY_DELAY)); + break; + case "preroll/overlay" : + var newSerial:SerialElement = new SerialElement(); + newSerial.addChild(new DurationElement(OVERLAY_DELAY)); + newSerial.addChild(vpaidNonLinear); + + if(vpaidNonLinear.getMetadata(VPAIDMetadata.NAMESPACE).getValue(VPAIDMetadata.NON_LINEAR_CREATIVE)) + { + parallelElement.addChild(videoElement); + parallelElement.addChild(newSerial); + } + + serialElement.addChild(vpaidPrerollLinear); + serialElement.addChild(parallelElement); + serialElement.addChild(new DurationElement(OVERLAY_DELAY)); + break; + default : + serialElement.addChild(vpaidPrerollLinear); + serialElement.addChild(videoElement); + break; + } + } + + private function updateMediaPlayer():void + { + //create an instance of the media player attaching the video element to it's media property. + mediaPlayer.media = serialElement; + trace("OSMFPlayer.createMediaPlayer("+ mediaPlayer.media +")"); + } + + private function onPlayClicked(e:MouseEvent):void + { + trace("OSMF_Player.onPlayClicked " ); + mediaPlayer.play(); + playBtn.visible = false; + pauseBtn.visible = true; + } + + private function onPauseClicked(e:MouseEvent):void + { + mediaPlayer.pause(); + pauseBtn.visible = false; + playBtn.visible = true; + } + + private function onStopClicked(e:MouseEvent):void + { + mediaPlayer.stop(); + } + + private function onTraitAdd(e:MediaElementEvent):void + { + trace("OSMF_Player.onTraitAdd - " + e.traitType); + if(e.traitType == MediaTraitType.PLAY) + { + contentPlayTraitAdded = true; + trace("OSMF_Player.onTraitAdd -- Content Play Trait Added " ); + playContent(); + } + } + + private function onMediaError(e:MediaErrorEvent):void + { + trace("OSMF_Player.onMediaError - There is an error with the player or the specified media cannot be played "); + mediaPlayer.media = videoElement; + videoElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + + private function onFSClicked(e:MouseEvent):void + { + switch(stage.displayState) + { + case "normal": + stage.displayState = "fullScreen"; + break; + case "fullScreen": + default: + stage.displayState = "normal"; + break; + } + } + + private function onLoadStateChange(e:LoadEvent):void + { + trace("EWTestplayer.onLoadStateChange " + e.loadState); + if(e.loadState == LoadState.UNINITIALIZED) + { + vpaidPrerollLinear = null; + trace("EWTestplayer.onLoadStateChange"); + } + } + + private function playContent():void + { + trace("Playing Content Video"); + mediaPlayer.play(); + } + + private function onMetadataValueAdded(e:MetadataEvent):void + { + trace("EWTestplayer.onMetadataValueAdded() " + e.key); + if(e.key == "error") + { + mediaPlayer.media = videoElement; + videoElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd); + } + } + + private function onMetadataValueChange(e:MetadataEvent):void + { + trace("EWTestplayer.onMetadataValueChange() " + e.target.getValue(e.key)); + } + + private function onContentLoadChange(e:LoadEvent):void + { + trace("EWTestplayer.onContentLoadChange() " + e.loadState); + } + + private function onPlayStateChange(e:PlayEvent):void + { + trace("EWTestplayer.onPlayStateChange " + e.playState); + } + + private function onVolChanged(e:SliderEvent):void + { + trace("Slider Volume Changed " + (e.target.value/10) ); + vol = (e.target.value/10); + mediaPlayer.volume = vol; + } + + private function onMutePressed(event:MouseEvent):void + { + if(muteBtn.visible){ + muteBtn.visible = false; + unmuteBtn.visible = true; + }else{ + muteBtn.visible = true; + unmuteBtn.visible = false; + } + + if(vol != 0) + { + if(mediaPlayer.muted){ + mediaPlayer.muted = false; + }else{ + mediaPlayer.muted = true; + } + } + } + + } +} diff --git a/lib/osmf/samples/VideoQoSPlugin/.actionScriptProperties b/lib/osmf/samples/VideoQoSPlugin/.actionScriptProperties index 5637d04..c59a6e0 100644 --- a/lib/osmf/samples/VideoQoSPlugin/.actionScriptProperties +++ b/lib/osmf/samples/VideoQoSPlugin/.actionScriptProperties @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/VideoQoSPlugin/src/VideoQoSPlugin.as b/lib/osmf/samples/VideoQoSPlugin/src/VideoQoSPlugin.as index f65f4ec..899b31f 100644 --- a/lib/osmf/samples/VideoQoSPlugin/src/VideoQoSPlugin.as +++ b/lib/osmf/samples/VideoQoSPlugin/src/VideoQoSPlugin.as @@ -1,44 +1,44 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package -{ - import flash.display.Sprite; - - import org.osmf.media.PluginInfo; - import org.osmf.qos.VideoQoSPluginInfo; - - public class VideoQoSPlugin extends Sprite - { - public function VideoQoSPlugin() - { - _pluginInfo = new VideoQoSPluginInfo(); - } - - public function get pluginInfo():PluginInfo - { - return _pluginInfo; - } - - private var _pluginInfo:VideoQoSPluginInfo; - } -} +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package +{ + import flash.display.Sprite; + + import org.osmf.media.PluginInfo; + import org.osmf.qos.VideoQoSPluginInfo; + + public class VideoQoSPlugin extends Sprite + { + public function VideoQoSPlugin() + { + _pluginInfo = new VideoQoSPluginInfo(); + } + + public function get pluginInfo():PluginInfo + { + return _pluginInfo; + } + + private var _pluginInfo:VideoQoSPluginInfo; + } +} diff --git a/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginInfo.as b/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginInfo.as index d7d22c4..c045fd5 100644 --- a/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginInfo.as +++ b/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginInfo.as @@ -1,66 +1,66 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.qos -{ - import __AS3__.vec.Vector; - - import org.osmf.media.MediaElement; - import org.osmf.media.MediaFactoryItem; - import org.osmf.media.MediaFactoryItemType; - import org.osmf.media.MediaResourceBase; - import org.osmf.media.PluginInfo; - - public class VideoQoSPluginInfo extends PluginInfo - { - public function VideoQoSPluginInfo() - { - var items:Vector. = new Vector.(); - items.push(mediaFactoryItem); - - super(items, mediaElementCreationNotificationFunction); - } - - public static function get mediaFactoryItem():MediaFactoryItem - { - return _mediaFactoryItem; - } - - private static function canHandleResourceFunction(resource:MediaResourceBase):Boolean - { - return true; - } - - private static function mediaElementCreationFunction():MediaElement - { - return new VideoQoSProxyElement(); - } - - private static var _mediaFactoryItem:MediaFactoryItem - = new MediaFactoryItem - ( "org.osmf.qos.VideoQoSPluginInfo" - , canHandleResourceFunction - , mediaElementCreationFunction - , MediaFactoryItemType.PROXY - ); - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.qos +{ + import __AS3__.vec.Vector; + + import org.osmf.media.MediaElement; + import org.osmf.media.MediaFactoryItem; + import org.osmf.media.MediaFactoryItemType; + import org.osmf.media.MediaResourceBase; + import org.osmf.media.PluginInfo; + + public class VideoQoSPluginInfo extends PluginInfo + { + public function VideoQoSPluginInfo() + { + var items:Vector. = new Vector.(); + items.push(mediaFactoryItem); + + super(items, mediaElementCreationNotificationFunction); + } + + public static function get mediaFactoryItem():MediaFactoryItem + { + return _mediaFactoryItem; + } + + private static function canHandleResourceFunction(resource:MediaResourceBase):Boolean + { + return true; + } + + private static function mediaElementCreationFunction():MediaElement + { + return new VideoQoSProxyElement(); + } + + private static var _mediaFactoryItem:MediaFactoryItem + = new MediaFactoryItem + ( "org.osmf.qos.VideoQoSPluginInfo" + , canHandleResourceFunction + , mediaElementCreationFunction + , MediaFactoryItemType.PROXY + ); + } } \ No newline at end of file diff --git a/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginMetadata.as b/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginMetadata.as index 53dec56..0160f1d 100644 --- a/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginMetadata.as +++ b/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginMetadata.as @@ -1,39 +1,39 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.qos -{ - import org.osmf.metadata.Metadata; - import org.osmf.metadata.MetadataSynthesizer; - - public class VideoQoSPluginMetadata extends Metadata - { - public static const NAMESPACE:String = "org.osmf.qos.VideoQoSPluginMetadata"; - public static const CURRENT_FPS:String = "currentFPS"; - public static const DROPPED_FRAMES:String = "droppedFrames"; - - override public function get synthesizer():MetadataSynthesizer - { - return new VideoQoSPluginMetadataSynthesizer(); - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.qos +{ + import org.osmf.metadata.Metadata; + import org.osmf.metadata.MetadataSynthesizer; + + public class VideoQoSPluginMetadata extends Metadata + { + public static const NAMESPACE:String = "org.osmf.qos.VideoQoSPluginMetadata"; + public static const CURRENT_FPS:String = "currentFPS"; + public static const DROPPED_FRAMES:String = "droppedFrames"; + + override public function get synthesizer():MetadataSynthesizer + { + return new VideoQoSPluginMetadataSynthesizer(); + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginMetadataSynthesizer.as b/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginMetadataSynthesizer.as index 354e3f6..39ef164 100644 --- a/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginMetadataSynthesizer.as +++ b/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSPluginMetadataSynthesizer.as @@ -1,70 +1,70 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.qos -{ - import __AS3__.vec.Vector; - - import org.osmf.elements.compositeClasses.CompositionMode; - import org.osmf.metadata.Metadata; - import org.osmf.metadata.MetadataSynthesizer; - - public class VideoQoSPluginMetadataSynthesizer extends MetadataSynthesizer - { - override public function synthesize - ( namespaceURL:String - , targetParentMetadata:Metadata - , metadatas:Vector. - , mode:String - , serialElementActiveChildMetadata:Metadata - ):Metadata - { - var result:VideoQoSPluginMetadata; - - if (mode == CompositionMode.SERIAL) - { - result = serialElementActiveChildMetadata as VideoQoSPluginMetadata; - } - else - { - result = new VideoQoSPluginMetadata(); - - var keys:Array = []; - for each (var metadata:Metadata in metadatas) - { - for each (var key:String in metadata.keys) - { - keys[key] ||= []; - keys[key].push(metadata.getValue(key)); - } - } - - for (key in keys) - { - result.addValue(key, keys[key].toString()); - } - } - - return result; - } - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.qos +{ + import __AS3__.vec.Vector; + + import org.osmf.elements.compositeClasses.CompositionMode; + import org.osmf.metadata.Metadata; + import org.osmf.metadata.MetadataSynthesizer; + + public class VideoQoSPluginMetadataSynthesizer extends MetadataSynthesizer + { + override public function synthesize + ( namespaceURL:String + , targetParentMetadata:Metadata + , metadatas:Vector. + , mode:String + , serialElementActiveChildMetadata:Metadata + ):Metadata + { + var result:VideoQoSPluginMetadata; + + if (mode == CompositionMode.SERIAL) + { + result = serialElementActiveChildMetadata as VideoQoSPluginMetadata; + } + else + { + result = new VideoQoSPluginMetadata(); + + var keys:Array = []; + for each (var metadata:Metadata in metadatas) + { + for each (var key:String in metadata.keys) + { + keys[key] ||= []; + keys[key].push(metadata.getValue(key)); + } + } + + for (key in keys) + { + result.addValue(key, keys[key].toString()); + } + } + + return result; + } + } } \ No newline at end of file diff --git a/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSProxyElement.as b/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSProxyElement.as index d425f24..ffc1c71 100644 --- a/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSProxyElement.as +++ b/lib/osmf/samples/VideoQoSPlugin/src/org/osmf/qos/VideoQoSProxyElement.as @@ -1,129 +1,129 @@ -/***************************************************** -* -* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ - -package org.osmf.qos -{ - import flash.events.TimerEvent; - import flash.net.NetStreamInfo; - import flash.utils.Timer; - - import org.osmf.elements.ProxyElement; - import org.osmf.elements.VideoElement; - import org.osmf.media.MediaElement; - import org.osmf.net.NetStreamLoadTrait; - import org.osmf.traits.MediaTraitType; - - public class VideoQoSProxyElement extends ProxyElement - { - // Public Interface - // - - public function VideoQoSProxyElement(proxiedElement:MediaElement=null) - { - instanceNumber = instanceCounter++; - - super(proxiedElement); - } - - // Overrides - // - - override public function set proxiedElement(value:MediaElement):void - { - reset(); - - if (value is VideoElement) - { - setup(VideoElement(value)); - } - - super.proxiedElement = value; - } - - // Internals - // - - private function reset():void - { - videoElement = null; - - if (timer != null) - { - timer.stop(); - timer.removeEventListener(TimerEvent.TIMER, onTimer); - timer = null; - } - } - - private function setup(videoElement:VideoElement):void - { - this.videoElement = videoElement; - - timer = new Timer(500); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - } - - private function onTimer(event:TimerEvent):void - { - var loadTrait:NetStreamLoadTrait - = videoElement.getTrait(MediaTraitType.LOAD) - as NetStreamLoadTrait; - - var metadata:VideoQoSPluginMetadata - = videoElement.getMetadata(VideoQoSPluginMetadata.NAMESPACE) - as VideoQoSPluginMetadata; - - if (metadata != null && (loadTrait == null || loadTrait.netStream == null)) - { - removeMetadata(VideoQoSPluginMetadata.NAMESPACE); - metadata = null; - } - else if (metadata == null) - { - metadata = new VideoQoSPluginMetadata(); - addMetadata(VideoQoSPluginMetadata.NAMESPACE, metadata); - } - - if (metadata != null && loadTrait.netStream != null) - { - var qos:NetStreamInfo = loadTrait.netStream.info; - - metadata.addValue - ( VideoQoSPluginMetadata.CURRENT_FPS - , loadTrait.netStream.currentFPS.toFixed(3) - ); - - metadata.addValue - ( VideoQoSPluginMetadata.DROPPED_FRAMES - , qos.droppedFrames.toString() - ); - - } - } - - private var instanceNumber:int; - private var timer:Timer; - private var videoElement:VideoElement; - private static var instanceCounter:int = 0; - } +/***************************************************** +* +* Copyright 2010 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ + +package org.osmf.qos +{ + import flash.events.TimerEvent; + import flash.net.NetStreamInfo; + import flash.utils.Timer; + + import org.osmf.elements.ProxyElement; + import org.osmf.elements.VideoElement; + import org.osmf.media.MediaElement; + import org.osmf.net.NetStreamLoadTrait; + import org.osmf.traits.MediaTraitType; + + public class VideoQoSProxyElement extends ProxyElement + { + // Public Interface + // + + public function VideoQoSProxyElement(proxiedElement:MediaElement=null) + { + instanceNumber = instanceCounter++; + + super(proxiedElement); + } + + // Overrides + // + + override public function set proxiedElement(value:MediaElement):void + { + reset(); + + if (value is VideoElement) + { + setup(VideoElement(value)); + } + + super.proxiedElement = value; + } + + // Internals + // + + private function reset():void + { + videoElement = null; + + if (timer != null) + { + timer.stop(); + timer.removeEventListener(TimerEvent.TIMER, onTimer); + timer = null; + } + } + + private function setup(videoElement:VideoElement):void + { + this.videoElement = videoElement; + + timer = new Timer(500); + timer.addEventListener(TimerEvent.TIMER, onTimer); + timer.start(); + } + + private function onTimer(event:TimerEvent):void + { + var loadTrait:NetStreamLoadTrait + = videoElement.getTrait(MediaTraitType.LOAD) + as NetStreamLoadTrait; + + var metadata:VideoQoSPluginMetadata + = videoElement.getMetadata(VideoQoSPluginMetadata.NAMESPACE) + as VideoQoSPluginMetadata; + + if (metadata != null && (loadTrait == null || loadTrait.netStream == null)) + { + removeMetadata(VideoQoSPluginMetadata.NAMESPACE); + metadata = null; + } + else if (metadata == null) + { + metadata = new VideoQoSPluginMetadata(); + addMetadata(VideoQoSPluginMetadata.NAMESPACE, metadata); + } + + if (metadata != null && loadTrait.netStream != null) + { + var qos:NetStreamInfo = loadTrait.netStream.info; + + metadata.addValue + ( VideoQoSPluginMetadata.CURRENT_FPS + , loadTrait.netStream.currentFPS.toFixed(3) + ); + + metadata.addValue + ( VideoQoSPluginMetadata.DROPPED_FRAMES + , qos.droppedFrames.toString() + ); + + } + } + + private var instanceNumber:int; + private var timer:Timer; + private var videoElement:VideoElement; + private static var instanceCounter:int = 0; + } } \ No newline at end of file diff --git a/lib/osmf/samples/YouTubePlugin/YouTubePlugin-build-config.xml b/lib/osmf/samples/YouTubePlugin/YouTubePlugin-build-config.xml index b9129d8..78e964a 100644 --- a/lib/osmf/samples/YouTubePlugin/YouTubePlugin-build-config.xml +++ b/lib/osmf/samples/YouTubePlugin/YouTubePlugin-build-config.xml @@ -31,8 +31,8 @@ - @@ -40,10 +40,10 @@ false - @@ -99,11 +99,11 @@ - @@ -111,8 +111,8 @@ - @@ -131,13 +131,13 @@ - @@ -147,12 +147,12 @@ flash.fonts.BatikFontManager - @@ -274,19 +274,19 @@
      - - - @@ -300,8 +300,8 @@ true - diff --git a/lib/osmf/samples/YouTubePluginTest/.FlexUnitSettings/FlexUnitApplicationLastRun.xml b/lib/osmf/samples/YouTubePluginTest/.FlexUnitSettings/FlexUnitApplicationLastRun.xml index 61e18b4..b348362 100644 --- a/lib/osmf/samples/YouTubePluginTest/.FlexUnitSettings/FlexUnitApplicationLastRun.xml +++ b/lib/osmf/samples/YouTubePluginTest/.FlexUnitSettings/FlexUnitApplicationLastRun.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/lib/osmf/samples/YouTubePluginTest/.FlexUnitSettings/FlexUnitApplicationLastSelection.xml b/lib/osmf/samples/YouTubePluginTest/.FlexUnitSettings/FlexUnitApplicationLastSelection.xml index 61e18b4..b348362 100644 --- a/lib/osmf/samples/YouTubePluginTest/.FlexUnitSettings/FlexUnitApplicationLastSelection.xml +++ b/lib/osmf/samples/YouTubePluginTest/.FlexUnitSettings/FlexUnitApplicationLastSelection.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/lib/osmf/samples/YouTubePluginTest/.actionScriptProperties b/lib/osmf/samples/YouTubePluginTest/.actionScriptProperties index 458c61e..e23ae8f 100644 --- a/lib/osmf/samples/YouTubePluginTest/.actionScriptProperties +++ b/lib/osmf/samples/YouTubePluginTest/.actionScriptProperties @@ -1,58 +1,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/samples/YouTubePluginTest/.flexProperties b/lib/osmf/samples/YouTubePluginTest/.flexProperties index f207211..0f603b0 100644 --- a/lib/osmf/samples/YouTubePluginTest/.flexProperties +++ b/lib/osmf/samples/YouTubePluginTest/.flexProperties @@ -1,2 +1,2 @@ - - + + diff --git a/lib/osmf/samples/YouTubePluginTest/YouTubePluginTest-build-config.xml b/lib/osmf/samples/YouTubePluginTest/YouTubePluginTest-build-config.xml index d3abd9b..02b56f7 100644 --- a/lib/osmf/samples/YouTubePluginTest/YouTubePluginTest-build-config.xml +++ b/lib/osmf/samples/YouTubePluginTest/YouTubePluginTest-build-config.xml @@ -1,37 +1,37 @@ - true - false true - - true - - @@ -42,17 +42,17 @@ CONFIG::FLASH_10_1 true - false - @@ -63,24 +63,24 @@ true - - - ${flexlib}/localFonts.ser @@ -97,34 +97,34 @@ 1000 - - - - - - false @@ -156,21 +156,21 @@ en_US - false - - - @@ -197,28 +197,28 @@ true - - - - true true - false @@ -313,8 +313,8 @@ false - 0xFFFFFF @@ -331,80 +331,80 @@ 375 - - halo - - - - ${flexlib}/${configname}-config.xml - - unknown - http://www.adobe.com/products/flex EN - - unknown @@ -412,49 +412,49 @@ Adobe Flex 4 Application - true - - - - - - true @@ -463,23 +463,23 @@ 10.1.0 - - - true false - diff --git a/lib/osmf/samples/YouTubePluginTest/src/FlexUnitApplication.mxml b/lib/osmf/samples/YouTubePluginTest/src/FlexUnitApplication.mxml deleted file mode 100644 index 4ca65a8..0000000 --- a/lib/osmf/samples/YouTubePluginTest/src/FlexUnitApplication.mxml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - diff --git a/lib/osmf/samples/YouTubePluginTest/src/YouTubePluginTest-app.xml b/lib/osmf/samples/YouTubePluginTest/src/YouTubePluginTest-app.xml deleted file mode 100644 index 5d599d0..0000000 --- a/lib/osmf/samples/YouTubePluginTest/src/YouTubePluginTest-app.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - YoutubePluginTest - - - YoutubePluginTest - - - YoutubePluginTest - - - v1 - - - - - - - - - - - - - - - [This value will be overwritten by Flash Builder in the output app.xml] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/osmf/samples/YouTubePluginTest/src/YouTubePluginTest.mxml b/lib/osmf/samples/YouTubePluginTest/src/YouTubePluginTest.mxml index 54cad69..8155703 100644 --- a/lib/osmf/samples/YouTubePluginTest/src/YouTubePluginTest.mxml +++ b/lib/osmf/samples/YouTubePluginTest/src/YouTubePluginTest.mxml @@ -50,7 +50,7 @@ //core.addListener( new TraceListener() ); - For AS3 Projects //core.addListener( TextListener.getDefaultTextListener( LogEventLevel.DEBUG ) ); - For Flex Projects - core.run(currentRunTestSuite()); + core.run(YoutubePluginTests.currentRunTestSuite()); } diff --git a/lib/osmf/samples/YouTubePluginTest/src/YoutubePluginTests.as b/lib/osmf/samples/YouTubePluginTest/src/YoutubePluginTests.as index 307da77..cca8125 100644 --- a/lib/osmf/samples/YouTubePluginTest/src/YoutubePluginTests.as +++ b/lib/osmf/samples/YouTubePluginTest/src/YoutubePluginTests.as @@ -15,28 +15,41 @@ * The Initial Developer of the Original Code is Adobe Systems Incorporated. * Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems * Incorporated. All Rights Reserved. - * **********************************************************/ package { - import org.osmf.youtube.*; - import org.osmf.youtube.media.*; - import org.osmf.youtube.net.*; - import org.osmf.youtube.traits.*; - - [Suite] - [RunWith("org.flexunit.runners.Suite")] - public class YoutubePluginTests - { - public var testYoutubeTimeTrait:TestYoutubeTimeTrait; - public var testYoutubeSeekTrait:TestYoutubeSeekTrait; - public var testYoutubeAudioTrait:TestYoutubeAudioTrait; - public var testYoutubePlayTrait:TestYoutubePlayTrait; - public var testYoutubeDynamicStreamTrait:TestYoutubeDynamicStreamTrait; - public var testYoutubePluginInfo:TestYoutubePluginInfo; - public var testYoutubePlugin:TestYouTubePlugin; - public var testYoutubeLoader:TestYoutubeLoader; - public var testYoutubeElement:TestYoutubeElement; - } + + import flexunit.framework.Test; + + import org.osmf.youtube.traits.TestYoutubeTimeTrait; + import org.osmf.youtube.traits.TestYoutubeSeekTrait; + import org.osmf.youtube.traits.TestYoutubePlayTrait; + import org.osmf.youtube.traits.TestYoutubeDynamicStreamTrait; + import org.osmf.youtube.traits.TestYoutubeAudioTrait; + import org.osmf.youtube.net.TestYoutubeLoader; + import org.osmf.youtube.media.TestYoutubeElement; + import org.osmf.youtube.TestYoutubePluginInfo; + + public class YoutubePluginTests + { + public static var testsToRun:Array = new Array(); + + public static function currentRunTestSuite():Array + { + + testsToRun.push(org.osmf.youtube.TestYoutubePluginInfo); + testsToRun.push(org.osmf.youtube.media.TestYoutubeElement); + testsToRun.push(org.osmf.youtube.net.TestYoutubeLoader); + testsToRun.push(org.osmf.youtube.traits.TestYoutubeAudioTrait); + testsToRun.push(org.osmf.youtube.traits.TestYoutubeDynamicStreamTrait); + testsToRun.push(org.osmf.youtube.traits.TestYoutubePlayTrait); + testsToRun.push(org.osmf.youtube.traits.TestYoutubeSeekTrait); + testsToRun.push(org.osmf.youtube.traits.TestYoutubeTimeTrait); + return testsToRun; + + return testsToRun; + + } + } } \ No newline at end of file diff --git a/lib/osmf/testing/NetMockerLibrary/.actionScriptProperties b/lib/osmf/testing/NetMockerLibrary/.actionScriptProperties index cc8f50f..faca7ac 100644 --- a/lib/osmf/testing/NetMockerLibrary/.actionScriptProperties +++ b/lib/osmf/testing/NetMockerLibrary/.actionScriptProperties @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/testing/NetMockerLibrary/.flexLibProperties b/lib/osmf/testing/NetMockerLibrary/.flexLibProperties index b55d206..094d92f 100644 --- a/lib/osmf/testing/NetMockerLibrary/.flexLibProperties +++ b/lib/osmf/testing/NetMockerLibrary/.flexLibProperties @@ -1,20 +1,19 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/lib/osmf/testing/NetMockerLibrary/NetMocker-build-config.xml b/lib/osmf/testing/NetMockerLibrary/NetMockerLibrary-build-config.xml similarity index 97% rename from lib/osmf/testing/NetMockerLibrary/NetMocker-build-config.xml rename to lib/osmf/testing/NetMockerLibrary/NetMockerLibrary-build-config.xml index 9b517cc..0ee9cc2 100644 --- a/lib/osmf/testing/NetMockerLibrary/NetMocker-build-config.xml +++ b/lib/osmf/testing/NetMockerLibrary/NetMockerLibrary-build-config.xml @@ -26,8 +26,8 @@ - @@ -42,10 +42,10 @@ false - @@ -102,11 +102,11 @@ - @@ -114,8 +114,8 @@ - @@ -134,13 +134,13 @@ - @@ -150,12 +150,12 @@ flash.fonts.BatikFontManager - @@ -275,19 +275,19 @@
      - - - @@ -301,10 +301,10 @@ true - - diff --git a/lib/osmf/testing/NetMockerLibrary/build.xml b/lib/osmf/testing/NetMockerLibrary/build.xml index 3a2dfda..0adb957 100644 --- a/lib/osmf/testing/NetMockerLibrary/build.xml +++ b/lib/osmf/testing/NetMockerLibrary/build.xml @@ -11,7 +11,7 @@ - + diff --git a/lib/osmf/testing/NetMockerLibrary/src/org/osmf/netmocker/MockHTTPNetStreamMetrics.as b/lib/osmf/testing/NetMockerLibrary/src/org/osmf/netmocker/MockHTTPNetStreamMetrics.as deleted file mode 100644 index eec7018..0000000 --- a/lib/osmf/testing/NetMockerLibrary/src/org/osmf/netmocker/MockHTTPNetStreamMetrics.as +++ /dev/null @@ -1,85 +0,0 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.netmocker -{ - import org.osmf.net.httpstreaming.HTTPNetStream; - import org.osmf.net.httpstreaming.HTTPNetStreamMetrics; - - public class MockHTTPNetStreamMetrics extends HTTPNetStreamMetrics - { - public function MockHTTPNetStreamMetrics(ns:HTTPNetStream) - { - super(ns); - } - - public function set downloadRatio(value:Number):void - { - _downloadRatio = value; - } - - override public function get downloadRatio():Number - { - return _downloadRatio; - } - - override public function get maxFPS():Number - { - return _maxFPS; - } - - public function set maxFPS(value:Number):void - { - _maxFPS = value; - } - - override public function get droppedFPS():Number - { - return _droppedFPS; - } - - public function set droppedFPS(value:Number):void - { - _droppedFPS = value; - } - - override public function get averageDroppedFPS():Number - { - return _averageDroppedFPS; - } - - public function set averageDroppedFPS(value:Number):void - { - _averageDroppedFPS = value; - } - - override public function getBitrateForIndex(index:int):Number - { - return resource.streamItems[index].bitrate; - } - - private var _downloadRatio:Number = 0; - private var _bitrates:Array; - private var _averageDroppedFPS:Number; - private var _droppedFPS:Number; - private var _maxFPS:Number; - } -} \ No newline at end of file diff --git a/lib/osmf/testing/NetMockerTest/.actionScriptProperties b/lib/osmf/testing/NetMockerTest/.actionScriptProperties deleted file mode 100644 index 81030eb..0000000 --- a/lib/osmf/testing/NetMockerTest/.actionScriptProperties +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/osmf/testing/NetMockerTest/.flexProperties b/lib/osmf/testing/NetMockerTest/.flexProperties deleted file mode 100644 index b5f031b..0000000 --- a/lib/osmf/testing/NetMockerTest/.flexProperties +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/lib/osmf/testing/NetMockerTest/NetMockerTest-build-config.xml b/lib/osmf/testing/NetMockerTest/NetMockerTest-build-config.xml deleted file mode 100644 index 7e21f4a..0000000 --- a/lib/osmf/testing/NetMockerTest/NetMockerTest-build-config.xml +++ /dev/null @@ -1,481 +0,0 @@ - - - - - - false - - - - false - - true - - - - - true - - - - - - - - false - - - - - - - - - true - - - - - - - - - ${flexlib}/localFonts.ser - - - flash.fonts.JREFontManager - flash.fonts.BatikFontManager - flash.fonts.AFEFontManager - flash.fonts.CFFFontManager - - - 20 - - 1000 - - - - - - - - - - - - - - - false - - - ${flexlib}/libs/framework.swc - ${flexlib}/libs/textLayout.swc - ${flexlib}/libs/spark.swc - ${flexlib}/libs/sparkskins.swc - ${flexlib}/libs/rpc.swc - ${flexlib}/libs/charts.swc - ${flexlib}/libs/spark_dmv.swc - ${flexlib}/libs/mx/mx.swc - ${flexlib}/libs/advancedgrids.swc - ${flexlib}/libs/authoringsupport.swc - ${flexlib}/libs/core.swc - ${flexlib}/libs/flash-integration.swc - ${flexlib}/locale/{locale} - libs - - ../NetMockerLibrary/#output.bin#/NetMocker.swc - #osmf.swc.path# - - - - - - en_US - - - - false - - - - - - - - - - http://ns.adobe.com/mxml/2009 - ${flexlib}/mxml-2009-manifest.xml - - - library://ns.adobe.com/flex/spark - ${flexlib}/spark-manifest.xml - - - library://ns.adobe.com/flex/mx - ${flexlib}/mx-manifest.xml - - - http://www.adobe.com/2006/mxml - ${flexlib}/mxml-manifest.xml - - - - true - - true - - - - - - - - - - true - - true - - - - false - - true - - - src - ../../framework/OSMFTest/src - - - true - - - ${flexlib}/themes/Spark/spark.css - - - true - - false - - false - - true - - true - - true - - true - - true - - true - - true - - true - - true - - true - - false - - false - - true - - true - - false - - false - - true - - true - - true - - true - - false - - true - - true - - true - - true - - true - - true - - false - - false - - true - - false - - false - - true - - true - - false - - - - - 0xFFFFFF - - 24 - - - 1000 - 60 - - - - 500 - 375 - - - - - - - - halo - - - - - - - - - - ${flexlib}/${configname}-config.xml - - - - - - - unknown - - - - http://www.adobe.com/products/flex - - EN - - - - - - unknown - - Adobe Flex 4 Application - - - - - true - - - - - - - - - - - - - - - - false - - 11 - - 10.2.0 - - - - - - - - true - - false - - - diff --git a/lib/osmf/testing/NetMockerTest/build.xml b/lib/osmf/testing/NetMockerTest/build.xml deleted file mode 100644 index 644adc0..0000000 --- a/lib/osmf/testing/NetMockerTest/build.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/osmf/testing/NetMockerTest/html-template/AC_OETags.js b/lib/osmf/testing/NetMockerTest/html-template/AC_OETags.js deleted file mode 100644 index ba5d24a..0000000 --- a/lib/osmf/testing/NetMockerTest/html-template/AC_OETags.js +++ /dev/null @@ -1,292 +0,0 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += ' 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
      '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - // If it did change, then we have to look the old state up - // in our hand-maintained array since document.location.hash - // won't have changed, then call back into BrowserManager. - currentHistoryLength = history.length; - var flexAppUrl = historyHash[currentHistoryLength]; - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - - return false; - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); diff --git a/lib/osmf/testing/NetMockerTest/html-template/history/historyFrame.html b/lib/osmf/testing/NetMockerTest/html-template/history/historyFrame.html deleted file mode 100644 index aebb8d8..0000000 --- a/lib/osmf/testing/NetMockerTest/html-template/history/historyFrame.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - Hidden frame for Browser History support. - - diff --git a/lib/osmf/testing/NetMockerTest/html-template/index.template.html b/lib/osmf/testing/NetMockerTest/html-template/index.template.html deleted file mode 100644 index a8b3b64..0000000 --- a/lib/osmf/testing/NetMockerTest/html-template/index.template.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - - - - -${title} - - - - - - - - - - - - - - - diff --git a/lib/osmf/testing/NetMockerTest/html-template/playerProductInstall.swf b/lib/osmf/testing/NetMockerTest/html-template/playerProductInstall.swf deleted file mode 100644 index bdc3437..0000000 Binary files a/lib/osmf/testing/NetMockerTest/html-template/playerProductInstall.swf and /dev/null differ diff --git a/lib/osmf/testing/NetMockerTest/libs/FlexUnit.swc b/lib/osmf/testing/NetMockerTest/libs/FlexUnit.swc deleted file mode 100644 index b4be965..0000000 Binary files a/lib/osmf/testing/NetMockerTest/libs/FlexUnit.swc and /dev/null differ diff --git a/lib/osmf/testing/NetMockerTest/src/NetMockerTest.mxml b/lib/osmf/testing/NetMockerTest/src/NetMockerTest.mxml deleted file mode 100644 index 8b3395d..0000000 --- a/lib/osmf/testing/NetMockerTest/src/NetMockerTest.mxml +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetConnection.as b/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetConnection.as deleted file mode 100644 index 0679599..0000000 --- a/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetConnection.as +++ /dev/null @@ -1,218 +0,0 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.netmocker -{ - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.NetStatusEvent; - - import flexunit.framework.TestCase; - - import org.osmf.net.NetConnectionCodes; - - public class TestMockNetConnection extends TestCase - { - override public function setUp():void - { - super.setUp(); - - netConnection = new MockNetConnection(); - netConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatusEventHandler); - netStatusEvents = new Array(); - eventDispatcher = new EventDispatcher(); - } - - override public function tearDown():void - { - super.tearDown(); - - netConnection.removeEventListener(NetStatusEvent.NET_STATUS, netStatusEventHandler); - netConnection = null; - netStatusEvents = null; - netStatusEventCallback = null; - eventDispatcher = null; - } - - public function testConstructor():void - { - assertTrue(netConnection.expectation == NetConnectionExpectation.VALID_CONNECTION); - } - - public function testClose():void - { - startAsyncTest(); - - netStatusEventCallback = function():void - { - assertTrue(netStatusEvents.length == 1) - assertTrue(netStatusEvents[0].code == NetConnectionCodes.CONNECT_CLOSED); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - - endAsyncTest(); - } - - netConnection.close(); - } - - public function testConnectProgressive():void - { - startAsyncTest(); - - netStatusEventCallback = function():void - { - assertTrue(netStatusEvents.length == 1) - assertTrue(netStatusEvents[0].code == NetConnectionCodes.CONNECT_SUCCESS); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - - endAsyncTest(); - } - - netConnection.connect(null); - } - - public function testConnectStreaming():void - { - startAsyncTest(); - - netStatusEventCallback = function():void - { - assertTrue(netStatusEvents.length == 1) - assertTrue(netStatusEvents[0].code == NetConnectionCodes.CONNECT_SUCCESS); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - - endAsyncTest(); - } - - netConnection.connect("rtmp://example.com/appName/streamName"); - } - - public function testConnectStreamingInvalidServer():void - { - startAsyncTest(); - - netConnection.expectation = NetConnectionExpectation.INVALID_FMS_SERVER; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetConnectionCodes.CONNECT_FAILED); - assertTrue(netStatusEvents[0].level == LEVEL_ERROR); - - endAsyncTest(); - } - else fail(); - } - - netConnection.connect("rtmp://example.com/appName/streamName"); - } - - public function testConnectStreamingInvalidApplication():void - { - startAsyncTest(); - - netConnection.expectation = NetConnectionExpectation.INVALID_FMS_APPLICATION; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetConnectionCodes.CONNECT_INVALIDAPP); - assertTrue(netStatusEvents[0].level == LEVEL_ERROR); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetConnectionCodes.CONNECT_CLOSED); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - - endAsyncTest(); - } - else fail(); - } - - netConnection.connect("rtmp://example.com/appName/streamName"); - } - - public function testConnectStreamingRejectedConnection():void - { - startAsyncTest(); - - netConnection.expectation = NetConnectionExpectation.REJECTED_CONNECTION; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetConnectionCodes.CONNECT_REJECTED); - assertTrue(netStatusEvents[0].level == LEVEL_ERROR); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetConnectionCodes.CONNECT_CLOSED); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - - endAsyncTest(); - } - else fail(); - } - - netConnection.connect("rtmp://example.com/appName/streamName"); - } - - // Internals - // - - private function netStatusEventHandler(event:NetStatusEvent):void - { - netStatusEvents.push(event.info); - - if (netStatusEventCallback != null) - { - netStatusEventCallback.call(); - } - } - - private function startAsyncTest(timeout:Number=1000):void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, timeout)); - } - - private function endAsyncTest():void - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder - } - - - private static const LEVEL_STATUS:String = "status"; - private static const LEVEL_ERROR:String = "error"; - - private var netConnection:MockNetConnection; - private var netStatusEvents:Array; - private var netStatusEventCallback:Function; - private var eventDispatcher:EventDispatcher; - } -} \ No newline at end of file diff --git a/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetLoader.as b/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetLoader.as deleted file mode 100644 index a5b3647..0000000 --- a/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetLoader.as +++ /dev/null @@ -1,103 +0,0 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.netmocker -{ - import flexunit.framework.Assert; - - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - import org.osmf.net.NetStreamLoadTrait; - import org.osmf.traits.LoadTrait; - import org.osmf.traits.LoaderBase; - import org.osmf.traits.TestLoaderBase; - import org.osmf.utils.NullResource; - import org.osmf.utils.TestConstants; - - public class TestMockNetLoader extends TestLoaderBase - { - override public function setUp():void - { - netLoader = new MockNetLoader(); - - super.setUp(); - } - - override public function tearDown():void - { - super.tearDown(); - - netLoader = null; - } - - public function testConstructor():void - { - Assert.assertTrue(netLoader.netConnectionExpectation == NetConnectionExpectation.VALID_CONNECTION); - Assert.assertTrue(netLoader.netStreamExpectedDuration == 0); - Assert.assertTrue(netLoader.netStreamExpectedHeight == 0); - Assert.assertTrue(netLoader.netStreamExpectedWidth == 0); - Assert.assertTrue(netLoader.netStreamExpectedEvents.length == 0); - } - - override protected function createInterfaceObject(... args):Object - { - return netLoader; - } - - override protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - if (resource == successfulResource) - { - netLoader.netConnectionExpectation = NetConnectionExpectation.VALID_CONNECTION; - } - else if (resource == failedResource) - { - netLoader.netConnectionExpectation = NetConnectionExpectation.REJECTED_CONNECTION; - } - else if (resource == unhandledResource) - { - netLoader.netConnectionExpectation = NetConnectionExpectation.REJECTED_CONNECTION; - } - return new NetStreamLoadTrait(netLoader, resource); - } - - override protected function get successfulResource():MediaResourceBase - { - return SUCCESSFUL_RESOURCE; - } - - override protected function get failedResource():MediaResourceBase - { - return UNSUCCESSFUL_RESOURCE; - } - - override protected function get unhandledResource():MediaResourceBase - { - return UNHANDLED_RESOURCE; - } - - private static const SUCCESSFUL_RESOURCE:URLResource = new URLResource(TestConstants.REMOTE_STREAMING_VIDEO); - private static const UNSUCCESSFUL_RESOURCE:URLResource = new URLResource(TestConstants.INVALID_STREAMING_VIDEO); - private static const UNHANDLED_RESOURCE:NullResource = new NullResource(); - - private var netLoader:MockNetLoader; - } -} \ No newline at end of file diff --git a/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetStream.as b/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetStream.as deleted file mode 100644 index 4e191f4..0000000 --- a/lib/osmf/testing/NetMockerTest/src/org/osmf/netmocker/TestMockNetStream.as +++ /dev/null @@ -1,483 +0,0 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.netmocker -{ - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.NetStatusEvent; - - import flexunit.framework.TestCase; - - import org.osmf.net.NetClient; - import org.osmf.net.NetStreamCodes; - - public class TestMockNetStream extends TestCase - { - override public function setUp():void - { - super.setUp(); - - netConnection = new MockNetConnection(); - netConnection.connect(null); - netStream = new MockNetStream(netConnection); - netStream.client = new NetClient(); - netStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusEventHandler); - netStatusEvents = new Array(); - eventDispatcher = new EventDispatcher(); - } - - override public function tearDown():void - { - super.tearDown(); - - netStream.removeEventListener(NetStatusEvent.NET_STATUS, netStatusEventHandler); - netStream = null; - netConnection = null; - netStatusEvents = null; - netStatusEventCallback = null; - eventDispatcher = null; - } - - public function testExpectedDuration():void - { - assertTrue(netStream.expectedDuration == 0); - - netStream.expectedDuration = 30; - assertTrue(netStream.expectedDuration == 30); - } - - public function testExpectedWidth():void - { - assertTrue(netStream.expectedWidth == 0); - - netStream.expectedWidth = 30; - assertTrue(netStream.expectedWidth == 30); - } - - public function testExpectedHeight():void - { - assertTrue(netStream.expectedHeight == 0); - - netStream.expectedHeight = 30; - assertTrue(netStream.expectedHeight == 30); - } - - public function testTime():void - { - assertTrue(netStream.time == 0); - } - - public function testGetMetaData():void - { - startAsyncTest(2000); - - var client:NetClient = new NetClient(); - client.addHandler("onMetaData", onMetaData); - netStream.client = client; - - netStream.expectedDuration = 33; - netStream.expectedWidth = 1920; - netStream.expectedHeight = 1080; - - netStream.play(); - - function onMetaData(info:Object):void - { - assertTrue(info.duration == 33); - assertTrue(info.width == 1920); - assertTrue(info.height == 1080); - - endAsyncTest(); - } - } - - public function testGetMetaDataWithNegativeDuration():void - { - startAsyncTest(2000); - - var client:NetClient = new NetClient(); - client.addHandler("onMetaData", onMetaData); - netStream.client = client; - - netStream.expectedDuration = -1; - netStream.expectedWidth = 1920; - netStream.expectedHeight = 1080; - - netStream.play(); - - function onMetaData(info:Object):void - { - assertTrue(info.duration == -1); - assertTrue(info.width == 1920); - assertTrue(info.height == 1080); - - endAsyncTest(); - } - } - - public function testPlay():void - { - startAsyncTest(2000); - - netStream.expectedDuration = 1; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetStreamCodes.NETSTREAM_PLAY_RESET); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 3) - { - assertTrue(netStatusEvents[2].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[2].level == LEVEL_STATUS); - - endAsyncTest(); - } - else fail(); - } - - netStream.play(); - } - - public function testPlayComplete():void - { - startAsyncTest(2000); - - netStream.expectedDuration = 1; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetStreamCodes.NETSTREAM_PLAY_RESET); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 3) - { - assertTrue(netStatusEvents[2].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[2].level == LEVEL_STATUS); - - assertTrue(netStream.time > 0); - } - else if (netStatusEvents.length == 4) - { - assertTrue(netStatusEvents[3].code == NetStreamCodes.NETSTREAM_PLAY_STOP); - assertTrue(netStatusEvents[3].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 5) - { - assertTrue(netStatusEvents[4].code == NetStreamCodes.NETSTREAM_BUFFER_FLUSH); - assertTrue(netStatusEvents[4].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 6) - { - assertTrue(netStatusEvents[5].code == NetStreamCodes.NETSTREAM_BUFFER_EMPTY); - assertTrue(netStatusEvents[5].level == LEVEL_STATUS); - - assertTrue(netStream.time == 1); - - endAsyncTest(); - } - else fail(); - } - - netStream.play(); - } - - public function testPause():void - { - startAsyncTest(2000); - - netStream.expectedDuration = 1; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetStreamCodes.NETSTREAM_PLAY_RESET); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 3) - { - assertTrue(netStatusEvents[2].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[2].level == LEVEL_STATUS); - - netStream.pause(); - } - else if (netStatusEvents.length == 4) - { - assertTrue(netStatusEvents[3].code == NetStreamCodes.NETSTREAM_PAUSE_NOTIFY); - assertTrue(netStatusEvents[3].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 5) - { - assertTrue(netStatusEvents[4].code == NetStreamCodes.NETSTREAM_BUFFER_FLUSH); - assertTrue(netStatusEvents[4].level == LEVEL_STATUS); - - endAsyncTest(); - } - else fail(); - } - - netStream.play(); - } - - public function testResume():void - { - startAsyncTest(2000); - - netStream.expectedDuration = 1; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetStreamCodes.NETSTREAM_PLAY_RESET); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 3) - { - assertTrue(netStatusEvents[2].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[2].level == LEVEL_STATUS); - - netStream.pause(); - } - else if (netStatusEvents.length == 4) - { - assertTrue(netStatusEvents[3].code == NetStreamCodes.NETSTREAM_PAUSE_NOTIFY); - assertTrue(netStatusEvents[3].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 5) - { - assertTrue(netStatusEvents[4].code == NetStreamCodes.NETSTREAM_BUFFER_FLUSH); - assertTrue(netStatusEvents[4].level == LEVEL_STATUS); - - netStream.resume(); - } - else if (netStatusEvents.length == 6) - { - assertTrue(netStatusEvents[5].code == NetStreamCodes.NETSTREAM_UNPAUSE_NOTIFY); - assertTrue(netStatusEvents[5].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 7) - { - assertTrue(netStatusEvents[6].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[6].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 8) - { - assertTrue(netStatusEvents[7].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[7].level == LEVEL_STATUS); - - endAsyncTest(); - } - else fail(); - } - - netStream.play(); - } - - public function testSeek():void - { - startAsyncTest(2000); - - netStream.expectedDuration = 10; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetStreamCodes.NETSTREAM_SEEK_NOTIFY); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - - // Due to bug FP-1705, the time doesn't get updated until some point - // after the NetStream.Seek.Notify event. - assertTrue(netStream.time == 0); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 3) - { - assertTrue(netStatusEvents[2].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[2].level == LEVEL_STATUS); - - endAsyncTest(); - } - else fail(); - } - - netStream.seek(2); - } - - public function testSeekWhilePlaying():void - { - startAsyncTest(2000); - - netStream.expectedDuration = 5; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetStreamCodes.NETSTREAM_PLAY_RESET); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 3) - { - assertTrue(netStatusEvents[2].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[2].level == LEVEL_STATUS); - - assertTrue(netStream.time > 0); - - netStream.seek(0); - } - else if (netStatusEvents.length == 4) - { - assertTrue(netStatusEvents[3].code == NetStreamCodes.NETSTREAM_SEEK_NOTIFY); - assertTrue(netStatusEvents[3].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 5) - { - assertTrue(netStatusEvents[4].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[4].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 6) - { - assertTrue(netStatusEvents[5].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[5].level == LEVEL_STATUS); - - assertTrue(netStream.time > 0); - - endAsyncTest(); - } - else fail(); - } - - netStream.play(); - } - - public function testClose():void - { - startAsyncTest(2000); - - netStream.expectedDuration = 1; - - netStatusEventCallback = function():void - { - if (netStatusEvents.length == 1) - { - assertTrue(netStatusEvents[0].code == NetStreamCodes.NETSTREAM_PLAY_RESET); - assertTrue(netStatusEvents[0].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 2) - { - assertTrue(netStatusEvents[1].code == NetStreamCodes.NETSTREAM_PLAY_START); - assertTrue(netStatusEvents[1].level == LEVEL_STATUS); - } - else if (netStatusEvents.length == 3) - { - assertTrue(netStatusEvents[2].code == NetStreamCodes.NETSTREAM_BUFFER_FULL); - assertTrue(netStatusEvents[2].level == LEVEL_STATUS); - - assertTrue(netStream.time > 0); - - netStream.close(); - - assertTrue(netStream.time == 0); - - endAsyncTest(); - } - else fail(); - } - - netStream.play(); - } - - // Internals - // - - private function netStatusEventHandler(event:NetStatusEvent):void - { - netStatusEvents.push(event.info); - - if (netStatusEventCallback != null) - { - netStatusEventCallback.call(); - } - } - - private function startAsyncTest(timeout:Number=1000):void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, timeout)); - } - - private function endAsyncTest():void - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder - } - - private static const LEVEL_STATUS:String = "status"; - private static const LEVEL_ERROR:String = "error"; - - private var useRealNetStream:Boolean; - private var netConnection:MockNetConnection; - private var netStream:MockNetStream; - private var netStatusEvents:Array; - private var netStatusEventCallback:Function; - private var eventDispatcher:EventDispatcher; - } -} \ No newline at end of file diff --git a/lib/osmf/testing/NetMockerTest/src/org/osmf/traits/TestLoaderBase.as b/lib/osmf/testing/NetMockerTest/src/org/osmf/traits/TestLoaderBase.as deleted file mode 100644 index 5435969..0000000 --- a/lib/osmf/testing/NetMockerTest/src/org/osmf/traits/TestLoaderBase.as +++ /dev/null @@ -1,415 +0,0 @@ -/***************************************************** -* -* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Adobe Systems Incorporated. -* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems -* Incorporated. All Rights Reserved. -* -*****************************************************/ -package org.osmf.traits -{ - import flash.errors.IllegalOperationError; - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.TimerEvent; - import flash.utils.Timer; - - import flexunit.framework.TestCase; - - import org.osmf.events.LoaderEvent; - import org.osmf.events.MediaError; - import org.osmf.events.MediaErrorEvent; - import org.osmf.media.MediaResourceBase; - import org.osmf.utils.SimpleResource; - - public class TestLoaderBase extends TestCase - { - override public function setUp():void - { - super.setUp(); - - _loader = createLoader(); - - eventDispatcher = new EventDispatcher(); - eventCount = 0; - mediaErrors = []; - doTwice = false; - } - - override public function tearDown():void - { - super.tearDown(); - - _loader = null; - eventDispatcher = null; - } - - protected function createInterfaceObject(... args):Object - { - return new LoaderBase(); - } - - //--------------------------------------------------------------------- - - public function testCanHandleResource():void - { - assertTrue(loader.canHandleResource(successfulResource) == true); - assertTrue(loader.canHandleResource(failedResource) == true); - assertTrue(loader.canHandleResource(unhandledResource) == false); - } - - public function testLoad():void - { - doTestLoad(); - } - - public function testLoadTwice():void - { - doTwice = true; - doTestLoad(); - } - - private function doTestLoad():void - { - eventDispatcher.addEventListener("testComplete",addAsync(mustReceiveEvent,TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoad); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestLoad(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - if (doTwice) - { - reload = true; - } - else - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Calling load a second time should throw an exception. - try - { - event.loader.load(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - } - } - - public function testLoadWithFailure():void - { - doTestLoadWithFailure(); - } - - public function testLoadWithFailureThenReload():void - { - doTwice = true; - doTestLoadWithFailure(); - } - - private function doTestLoadWithFailure():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, onTestLoadWithFailure); - var loadTrait:LoadTrait = createLoadTrait(loader, failedResource); - loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError); - loader.load(loadTrait); - } - - private function onTestLoadWithFailure(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var reload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - if (eventCount == 1 && doTwice) - { - reload = true; - } - else - { - markCompleteOnMediaError(1); - } - break; - case 2: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOAD_ERROR); - assertTrue(event.newState == LoadState.LOADING); - break; - case 3: - assertTrue(doTwice); - - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.LOAD_ERROR); - - markCompleteOnMediaError(2); - break; - default: - fail(); - } - - eventCount++; - - if (reload) - { - // Reloading should repeat the failure. - event.loader.load(event.loadTrait); - } - } - - private function markCompleteOnMediaError(numExpected:int):void - { - if (numExpected == mediaErrors.length) - { - // Just verify one of them. - verifyMediaErrorOnLoadFailure(mediaErrors[0] as MediaError); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - } - else - { - // Wait a bit, then check again. - var timer:Timer = new Timer(400); - timer.addEventListener(TimerEvent.TIMER, onTimer); - timer.start(); - - function onTimer(event:TimerEvent):void - { - timer.stop(); - timer.removeEventListener(TimerEvent.TIMER, onTimer); - - markCompleteOnMediaError(numExpected); - } - } - } - - public function testLoadWithInvalidResource():void - { - try - { - loader.load(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - public function testUnload():void - { - doTestUnload(); - } - - public function testUnloadTwice():void - { - doTwice = true; - doTestUnload(); - } - - private function doTestUnload():void - { - eventDispatcher.addEventListener("testComplete", addAsync(mustReceiveEvent, TEST_TIME)); - - loader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE,onTestUnload); - loader.load(createLoadTrait(loader, successfulResource)); - } - - private function onTestUnload(event:LoaderEvent):void - { - assertTrue(event.loader == loader); - assertTrue(event.loadTrait != null); - assertTrue(event.type == LoaderEvent.LOAD_STATE_CHANGE); - - var doUnload:Boolean = false; - - switch (eventCount) - { - case 0: - assertTrue(event.oldState == LoadState.UNINITIALIZED); - assertTrue(event.newState == LoadState.LOADING); - break; - case 1: - assertTrue(event.oldState == LoadState.LOADING); - assertTrue(event.newState == LoadState.READY); - - // Now unload. - doUnload = true; - - break; - case 2: - assertTrue(event.oldState == LoadState.READY); - assertTrue(event.newState == LoadState.UNLOADING); - break; - case 3: - assertTrue(event.oldState == LoadState.UNLOADING); - assertTrue(event.newState == LoadState.UNINITIALIZED); - - eventDispatcher.dispatchEvent(new Event("testComplete")); - break; - - default: - fail(); - } - - eventCount++; - - if (doUnload) - { - event.loader.unload(event.loadTrait); - - if (doTwice) - { - // Unloading a second time should throw an exception - // (but the first unload will complete). - try - { - event.loader.unload(event.loadTrait); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - } - } - - public function testUnloadWithInvalidResource():void - { - try - { - loader.unload(createLoadTrait(loader, unhandledResource)); - - fail(); - } - catch (error:IllegalOperationError) - { - } - } - - //--------------------------------------------------------------------- - - protected final function createLoader():LoaderBase - { - return createInterfaceObject() as LoaderBase; - } - - protected function setOverriddenLoader(value:LoaderBase):void - { - _loader = value; - } - - protected final function get loader():LoaderBase - { - return _loader; - } - - protected function createLoadTrait(loader:LoaderBase, resource:MediaResourceBase):LoadTrait - { - return new LoadTrait(loader, resource); - } - - - protected function get successfulResource():MediaResourceBase - { - throw new Error("Subclass must override get successfulResource!"); - } - - protected function get failedResource():MediaResourceBase - { - throw new Error("Subclass must override get failedResource!"); - } - - protected function get unhandledResource():MediaResourceBase - { - throw new Error("Subclass must override get unhandledResource!"); - } - - protected function verifyMediaErrorOnLoadFailure(error:MediaError):void - { - // Subclasses can override to check the error's properties. - } - - private function mustReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is received. - } - - private function mustNotReceiveEvent(event:Event):void - { - // Placeholder to ensure an event is NOT received. - fail(); - } - - private function onMediaError(event:MediaErrorEvent):void - { - mediaErrors.push(event.error); - } - - private static const TEST_TIME:int = 8000; - - private var eventDispatcher:EventDispatcher; - private var eventCount:int = 0; - private var mediaErrors:Array; - private var _loader:LoaderBase; - private var doTwice:Boolean; - } -} \ No newline at end of file diff --git a/lib/osmf/version.txt b/lib/osmf/version.txt new file mode 100644 index 0000000..dfc21a7 --- /dev/null +++ b/lib/osmf/version.txt @@ -0,0 +1 @@ +2.0.2494 \ No newline at end of file diff --git a/plugins/akamai/build.xml b/plugins/akamai/build.xml index b196243..47d14a4 100644 --- a/plugins/akamai/build.xml +++ b/plugins/akamai/build.xml @@ -3,13 +3,16 @@ - - + + + + + diff --git a/plugins/analytics/README.txt b/plugins/analytics/README.txt index 338d654..beed3ad 100644 --- a/plugins/analytics/README.txt +++ b/plugins/analytics/README.txt @@ -2,8 +2,8 @@ Version history: 3.2.9 ----- -- Refactored to changes in the google analytics library for Bridge mode support. Debug view support is removed but with the option of a build build. Reinstating the trackingObj config -to configure the bridge mode. +- Reinstating the trackingObj config to configure the bridge mode. Default value is "window.pageTracker". +- Debug view support was removed. 3.2.8 ----- diff --git a/plugins/analytics/build-debug.xml b/plugins/analytics/build-debug.xml index eeb5cd7..e41a644 100755 --- a/plugins/analytics/build-debug.xml +++ b/plugins/analytics/build-debug.xml @@ -3,8 +3,8 @@ - - + + diff --git a/plugins/analytics/build.properties b/plugins/analytics/build.properties index 0ad1778..de9b17b 100644 --- a/plugins/analytics/build.properties +++ b/plugins/analytics/build.properties @@ -1,2 +1,2 @@ -version=3.2.9-dev +version=3.2.9 devkit-dir=../../lib/devkit diff --git a/plugins/analytics/build.xml b/plugins/analytics/build.xml index 9197bc8..cba43b9 100755 --- a/plugins/analytics/build.xml +++ b/plugins/analytics/build.xml @@ -3,14 +3,17 @@ - - + + + + + diff --git a/plugins/analytics/src/actionscript/org/flowplayer/analytics/Config.as b/plugins/analytics/src/actionscript/org/flowplayer/analytics/Config.as index db29168..b9b6f69 100644 --- a/plugins/analytics/src/actionscript/org/flowplayer/analytics/Config.as +++ b/plugins/analytics/src/actionscript/org/flowplayer/analytics/Config.as @@ -15,7 +15,7 @@ package org.flowplayer.analytics { private var _debug:Boolean = false; private var _mode:String = "AS3"; private var _accountId:String; // required - private var _trackingObj:String; + private var _trackingObj:String = "window.pageTracker"; private var _events:Events = new Events(); // possible values are "video", "audio", "image" diff --git a/plugins/analytics/src/actionscript/org/flowplayer/analytics/GoogleTracker.as b/plugins/analytics/src/actionscript/org/flowplayer/analytics/GoogleTracker.as index 57a343c..365149d 100755 --- a/plugins/analytics/src/actionscript/org/flowplayer/analytics/GoogleTracker.as +++ b/plugins/analytics/src/actionscript/org/flowplayer/analytics/GoogleTracker.as @@ -172,6 +172,8 @@ package org.flowplayer.analytics { _log.debug("Tracking " + eventName + "[" + (clip.completeUrl + (clip.isInStream ? ": instream" : "")) + "] : " + time + " on page " + category); if (_tracker.isReady()) { _tracker.trackEvent(category, eventName, clip.completeUrl + (clip.isInStream ? ": instream" : ""), time); + } else { + _log.debug("tracker not ready"); } } catch (e:Error) { _log.error("Got error while tracking event " + eventName); diff --git a/plugins/audio/build.properties b/plugins/audio/build.properties index 9a7da9a..c41de08 100644 --- a/plugins/audio/build.properties +++ b/plugins/audio/build.properties @@ -1,2 +1,2 @@ -version=3.2.10 +version=3.2.11 devkit-dir=../../lib/devkit \ No newline at end of file diff --git a/plugins/audio/build.xml b/plugins/audio/build.xml index dca367e..e3c47b3 100644 --- a/plugins/audio/build.xml +++ b/plugins/audio/build.xml @@ -3,12 +3,15 @@ - - + + + + + diff --git a/plugins/audiovisual/build.xml b/plugins/audiovisual/build.xml index 1fb84eb..30dcc18 100644 --- a/plugins/audiovisual/build.xml +++ b/plugins/audiovisual/build.xml @@ -3,13 +3,15 @@ - - + + + + diff --git a/plugins/bitrateselect/README.txt b/plugins/bitrateselect/README.txt index 5eda8c2..b29fd1d 100644 --- a/plugins/bitrateselect/README.txt +++ b/plugins/bitrateselect/README.txt @@ -1,9 +1,5 @@ Version history: -3.2.14 ------- -- Added helper methods to hide / show the dock when autohide is enabled or not, issue #60 - 3.2.13 ------ - #7 add start event filter for clips with bitrateitems as well as bitrateselect resolver checks. diff --git a/plugins/bitrateselect/build.properties b/plugins/bitrateselect/build.properties index a551c3e..1f10d66 100644 --- a/plugins/bitrateselect/build.properties +++ b/plugins/bitrateselect/build.properties @@ -1,2 +1,2 @@ devkit-dir=../../lib/devkit -version=3.2.13 +version=3.2.14 diff --git a/plugins/bitrateselect/build.xml b/plugins/bitrateselect/build.xml index 5bd89cf..c6983e3 100644 --- a/plugins/bitrateselect/build.xml +++ b/plugins/bitrateselect/build.xml @@ -11,11 +11,14 @@ - - + + + + + diff --git a/plugins/bwcheck/.actionScriptProperties b/plugins/bwcheck/.actionScriptProperties deleted file mode 100644 index 3dc82b4..0000000 --- a/plugins/bwcheck/.actionScriptProperties +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/plugins/bwcheck/.flexProperties b/plugins/bwcheck/.flexProperties deleted file mode 100644 index 8ced38d..0000000 --- a/plugins/bwcheck/.flexProperties +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/plugins/bwcheck/README.txt b/plugins/bwcheck/README.txt index a1e8318..16d363c 100644 --- a/plugins/bwcheck/README.txt +++ b/plugins/bwcheck/README.txt @@ -1,5 +1,13 @@ Version history: +3.2.13 +------ +- Upgraded to OSMF 2.0 +- #70 Refactored changes with dynamic stream switching features for rtmp and httpstreaming. Switching rules and metrics differ between them. +- Fix for issue caused by #322 with bitrateselect plugin +- #96 possible confusion caused by the naming of the widgets with accessibility options for screen readers. Use the tooltip labels instead + of the widget name if set. + 3.2.12 ------ - #47 close the connection or else wowza dispatches two bwcheck events. @@ -8,6 +16,8 @@ Version history: 3.2.11 ------ - #6 cache control headers don't work on chrome windows, just use the cache busting url param. +- #47 close the connection or else wowza dispatches two bwcheck events. +- #47 regression with 417 disable screen checks with the qos screen property. 3.2.10 ------ diff --git a/plugins/bwcheck/build-httpstreaming.xml b/plugins/bwcheck/build-httpstreaming.xml index ed121ef..058fe51 100644 --- a/plugins/bwcheck/build-httpstreaming.xml +++ b/plugins/bwcheck/build-httpstreaming.xml @@ -6,14 +6,17 @@ - - + + - - + + - + + + + @@ -34,4 +37,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/bwcheck/build.properties b/plugins/bwcheck/build.properties index 0d83160..0c23dd7 100644 --- a/plugins/bwcheck/build.properties +++ b/plugins/bwcheck/build.properties @@ -1,4 +1,4 @@ devkit-dir=../../lib/devkit //osmf-dir=/Users/api/flex_sdk_4.5.0.19786/frameworks/libs osmf-dir=../../lib/osmf/framework/OSMF -version=3.2.12 +version=3.2.13 diff --git a/plugins/bwcheck/build.xml b/plugins/bwcheck/build.xml index cea7d89..b90ee65 100644 --- a/plugins/bwcheck/build.xml +++ b/plugins/bwcheck/build.xml @@ -6,14 +6,17 @@ - - + + - - + + + + + diff --git a/plugins/bwcheck/lib/externs.xml b/plugins/bwcheck/lib/externs.xml new file mode 100644 index 0000000..555e6a6 --- /dev/null +++ b/plugins/bwcheck/lib/externs.xml @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/BwCheckProvider.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/BwCheckProvider.as index 84d09e7..a1e43d4 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/BwCheckProvider.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/BwCheckProvider.as @@ -1 +1 @@ -/* * This file is part of Flowplayer, http://flowplayer.org * * By: Daniel Rossi , Anssi Piirainen Flowplayer Oy * Copyright (c) 2009, 2010 Electroteque Multimedia, Flowplayer Oy * * Released under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.bwcheck { import de.betriebsraum.video.BufferCalculator; import flash.display.DisplayObject; import flash.events.NetStatusEvent; import flash.net.NetStream; import flash.utils.Dictionary; import fp.HDSymbol; import org.flowplayer.bwcheck.net.OsmfLoggerFactory; import org.flowplayer.bwcheck.net.OsmfNetStreamClient; import org.flowplayer.net.BitrateItem; import org.flowplayer.net.StreamSelectionManager; import org.flowplayer.net.IStreamSelectionManager; import org.flowplayer.net.StreamSwitchManager; import org.flowplayer.net.BitrateResource; import org.flowplayer.bwcheck.config.Config; import org.flowplayer.bwcheck.detect.BandwidthDetectEvent; import org.flowplayer.bwcheck.detect.BandwidthDetector; import org.flowplayer.bwcheck.net.ScreenSizeRule; import org.flowplayer.bwcheck.net.BWStreamSelectionManager; import org.flowplayer.controller.ClipURLResolver; import org.flowplayer.controller.NetStreamClient; import org.flowplayer.controller.StreamProvider; import org.flowplayer.model.Clip; import org.flowplayer.model.ClipEvent; import org.flowplayer.model.PlayerEvent; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginEventType; import org.flowplayer.model.PluginModel; import org.flowplayer.util.PropertyBinder; import org.flowplayer.view.AbstractSprite; import org.flowplayer.view.Flowplayer; import org.osmf.net.DynamicStreamingItem; import org.osmf.net.DynamicStreamingResource; import org.osmf.net.NetStreamSwitchManager; import org.osmf.net.NetStreamMetricsBase; import org.osmf.net.SwitchingRuleBase; CONFIG::LOGGING { import org.osmf.logging.Log; } CONFIG::enableRtmpMetrics { import org.osmf.net.rtmpstreaming.RTMPNetStreamMetrics; import org.osmf.net.rtmpstreaming.DroppedFramesRule; import org.osmf.net.rtmpstreaming.InsufficientBandwidthRule; import org.osmf.net.rtmpstreaming.InsufficientBufferRule; import org.osmf.net.rtmpstreaming.SufficientBandwidthRule; } CONFIG::enableHttpMetrics { import org.osmf.net.rtmpstreaming.DroppedFramesRule; import org.osmf.net.httpstreaming.HTTPNetStreamMetrics; import org.osmf.net.httpstreaming.DownloadRatioRule; import org.osmf.net.httpstreaming.HTTPNetStream; } public class BwCheckProvider extends AbstractSprite implements ClipURLResolver, Plugin { private var _config:Config; private var _netStream:NetStream; private var _resolveSuccessListener:Function; private var _failureListener:Function; private var _clip:Clip; private var _hasDetectedBW:Boolean = false; private var _start:Number = 0; private var _model:PluginModel; private var _player:Flowplayer; private var _resolving:Boolean; private var _playButton:DisplayObject; private var _provider:StreamProvider; private var _bitrateStorage:BitrateStorage; private var _detector:BandwidthDetector; private var _switchManager:NetStreamSwitchManager; private var _netStreamMetrics:NetStreamMetricsBase; private var dsResource:DynamicStreamingResource; private var _streamSelectionManager:IStreamSelectionManager; private var _streamSwitchManager:StreamSwitchManager; public function onConfig(model:PluginModel):void { log.debug("onConfig(_)"); CONFIG::LOGGING { Log.loggerFactory = new OsmfLoggerFactory(); } _config = new PropertyBinder(new Config()).copyProperties(model.config) as Config; _model = model; _bitrateStorage = new BitrateStorage(_config.bitrateProfileName, "/"); _bitrateStorage.expiry = _config.cacheExpiry; log.debug("onConfig(), dynamic " + _config.dynamic); } private function applyForClip(clip:Clip):Boolean { var bw:Object = clip.getCustomProperty("bwcheck"); log.debug("applyForClip() ? " + bw); if (bw is Boolean && ! bw) return false; return true; } private function canSwitchOnFullscreen():Boolean { //disabling fullscreen switching on dynamic for now #336 return _config.switchOnFullscreen && _player.streamProvider.type != "http" && !_config.dynamic; } public function onLoad(player:Flowplayer):void { log.debug("onLoad()"); _player = player; lookupProvider(player.pluginRegistry.providers); _detector = new BandwidthDetector(_model, _config, _player.playlist); _detector.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE, onDetectorComplete); _detector.addEventListener(BandwidthDetectEvent.CLUSTER_FAILED, onClusterFailed); if (canSwitchOnFullscreen()) { _player.onFullscreen(onFullscreen); _player.onFullscreenExit(onFullscreen); } _player.playlist.onSwitch(function(event:ClipEvent):void { //fixes for #336 provide correction bitrateitem information when using dynamic stream switching //fixes for #352 for wowza streams with secure names that return the real name from the server, return the item from the metrics index instead. var newItem:DynamicStreamingItem = _streamSelectionManager.fromName(String(event.info)); log.info("new item is " + newItem + ", (" + event.info + "), current " + _streamSelectionManager.currentBitrateItem); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onStreamSwitchBegin", newItem, _streamSelectionManager.currentBitrateItem); }); _player.playlist.onSwitchFailed(function(event:ClipEvent):void { log.info("Transition failed with error " + event.info2.toString()); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onStreamSwitchFailed", "Transition failed with error " + event.info2.toString()); }); _player.playlist.onSwitchComplete(function(event:ClipEvent):void { log.info("Stream switch completed with item " + _streamSelectionManager.currentBitrateItem); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onStreamSwitch", _streamSelectionManager.currentBitrateItem); }); _player.playlist.onStart(function(event:ClipEvent):void { log.debug("onStart() clip == " + clip); var clip:Clip = event.target as Clip; if (alreadyResolved(clip)) { init(clip.getNetStream(), clip); //only setup dynamic stream switching in these conditions if (_config.dynamic && _streamSelectionManager is BWStreamSelectionManager) { initQoS(clip.getNetStream(), clip); } } }, applyForClip); var autoSwitch:Function = function(enable:Boolean):Function { return function(event:ClipEvent):void { if (! _switchManager) return; var newVal:Boolean = _config.dynamic && enable; log.info("setting QOS state to " + newVal); _switchManager.autoSwitch = newVal; } }; _player.playlist.onPause(autoSwitch(false), applyForClip); _player.playlist.onStop(autoSwitch(false), applyForClip); _player.playlist.onStart(autoSwitch(true), applyForClip); _player.playlist.onResume(autoSwitch(true)),applyForClip; _player.playlist.onFinish(autoSwitch(false), applyForClip); _model.dispatchOnLoad(); } private function onFullscreen(event:PlayerEvent):void { log.debug("onFullscreen(), checking bandwidth and switching stream"); checkBandwidthIfNotDetectedYet(); } private function alreadyResolved(clip:Clip):Boolean { return clip.getCustomProperty("bwcheckResolvedUrl") != null; } protected function hasDetectedBW():Boolean { if (! _config.rememberBitrate) return false; if (_hasDetectedBW) return true; if (isRememberedBitrateValid()) return true; return false; } public function set onFailure(listener:Function):void { _failureListener = listener; } public function handeNetStatusEvent(event:NetStatusEvent):Boolean { return true; } private function detect():void { log.debug("connectServer()"); _detector.detect(); } private function onClusterFailed(event:BandwidthDetectEvent):void { log.error("onClusterFailed(), will use default bitrate"); useDefaultBitrate(); } private function onDetectorComplete(event:BandwidthDetectEvent):void { log.debug("onDetectorComplete()"); event.stopPropagation(); log.info("\n\n kbit Down: " + event.info.kbitDown + " Delta Down: " + event.info.deltaDown + " Delta Time: " + event.info.deltaTime + " Latency: " + event.info.latency); _hasDetectedBW = true; // Set the detected bandwidth var bandwidth:Number = event.info.kbitDown; var mappedBitrate:BitrateItem = getMappedBitrate(bandwidth); log.debug("bandwidth (kbitDown) " + bandwidth); log.info("mapped to bitrate " + mappedBitrate.bitrate); rememberBandwidth(bandwidth); selectBitrate(mappedBitrate, bandwidth); } private function getMappedBitrate(bandwidth:Number = -1):BitrateItem { return _streamSelectionManager.getStream(bandwidth) as BitrateItem; } private function dynamicBuffering(mappedBitrate:Number, detectedBitrate:Number):void { if (_config.dynamicBuffer) { _clip.onMetaData(function(event:ClipEvent):void { _clip.bufferLength = BufferCalculator.calculate(_clip.metaData.duration, mappedBitrate, detectedBitrate); log.info("Dynamically setting buffer time to " + _clip.bufferLength + "s"); }); } } private function selectBitrate(mappedBitrate:BitrateItem, detectedBitrate:Number = -1):void { log.debug("selectBitrate()"); dynamicBuffering(mappedBitrate.bitrate, detectedBitrate); if (_playButton && _playButton.hasOwnProperty("stopBuffering")) { _playButton["stopBuffering"](); } //move this event up to give it time before onStreamSwitchBegin is called. log.info("dispatching onBwDone, mapped bitrate: " + mappedBitrate.bitrate + " detected bitrate " + detectedBitrate + " url: " + mappedBitrate.streamName); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onBwDone", mappedBitrate, detectedBitrate); if (_resolving) { _streamSelectionManager.changeStreamNames(mappedBitrate); _resolveSuccessListener(_clip); _resolving = false; } else if (_netStream && (_player.isPlaying() || _player.isPaused())) { switchStream(mappedBitrate); } else { _streamSelectionManager.changeStreamNames(mappedBitrate); } } private function switchStream(mappedBitrate:BitrateItem):void { _streamSwitchManager.switchStream(mappedBitrate); } private function addRule(prop:String, rules:Vector., rule:SwitchingRuleBase):void { if (_config.qos[prop]) { log.info("using QoS switching rules " + rule); rules.push(rule); } } [External] public function get bitrateItems():Vector. { return Vector.(_streamSelectionManager.bitrates); } /** * Store the detection and chosen bitrate if the rememberBitrate config property is set. */ protected function rememberBandwidth(bw:int):void { if (_config.rememberBitrate) { _bitrateStorage.bandwidth = bw; log.debug("stored bandwidth " + bw); } } private function isRememberedBitrateValid():Boolean { log.debug("isRememberedBitrateValid()"); if (! _bitrateStorage.bandwidth) { log.debug("bandwidth not in SO"); return false; } var expired:Boolean = _bitrateStorage.isExpired; log.info("is remembered bitrate expired?: " + expired + (expired ? ", age is " + _bitrateStorage.age : "")); return ! expired; } public function resolve(provider:StreamProvider, clip:Clip, successListener:Function):void { log.debug("resolve " + clip); if (!clip.getCustomProperty("bitrates") && !clip.getCustomProperty("bitrateItems")) { log.info("Bitrates configuration not enabled for this clip"); successListener(clip); return; } if (alreadyResolved(clip)) { log.info("resolve(): bandwidth already resolved for clip " + clip + ", will not detect again"); successListener(clip); return; } _provider = provider; _resolving = true; _resolveSuccessListener = successListener; init(provider.netStream, clip); checkBandwidthIfNotDetectedYet(); } private function useDefaultBitrate():void { selectBitrate(getMappedBitrate(), -1); } private function useStoredBitrate():void { var mappedBitrate:BitrateItem = getMappedBitrate(_bitrateStorage.bandwidth); log.info("using remembered bandwidth " + _bitrateStorage.bandwidth + ", maps to bitrate " + mappedBitrate.bitrate); selectBitrate(mappedBitrate, _bitrateStorage.bandwidth); } private function checkBandwidthIfNotDetectedYet():void { if (! applyForClip(_player.playlist.current)) return; if (hasDetectedBW()) { useStoredBitrate(); } else if (_config.checkOnStart) { log.info("not using remembered bandwidth, detecting now"); detect(); } else { log.info("using dynamic switching with default bitrate "); useDefaultBitrate(); } } private function init(netStream:NetStream, clip:Clip):void { log.debug("init(), netStream == " + netStream + ", clip == " + clip); _netStream = netStream; _clip = clip; _start = netStream ? netStream.time : 0; /* if (_resolving && _clip.getCustomProperty("streamSelectionManager") && !_clip.getCustomProperty("streamSelectionManager") is BWStreamSelectionManager) { _clip.setCustomProperty("streamSelectionManager", null); } */ if (!_clip.getCustomProperty("streamSelectionManager")) { _streamSelectionManager = new BWStreamSelectionManager(new BitrateResource(), _player, this, _config); _clip.setCustomProperty("streamSelectionManager",_streamSelectionManager); } else { _streamSelectionManager = _clip.getCustomProperty("streamSelectionManager") as IStreamSelectionManager; } initSwitchManager(); } private function initSwitchManager():void { _streamSwitchManager = new StreamSwitchManager(_netStream, _streamSelectionManager, _player); } private function initQoS(netStream:NetStream, clip:Clip):void { log.info("initQoS(), netStream == " + netStream + ", host == " + _detector.host); import org.osmf.net.StreamType; //save the streaming resource and load for each clip in the playlist if (clip.getCustomProperty("urlResource")) { dsResource = clip.getCustomProperty("urlResource") as DynamicStreamingResource; dsResource.initialIndex = _streamSelectionManager.currentIndex; } else { dsResource = new DynamicStreamingResource(_detector.host); dsResource.streamItems = bitrateItems; dsResource.initialIndex = _streamSelectionManager.currentIndex; dsResource.streamType = _config.live ? StreamType.LIVE : StreamType.RECORDED; //#369 set clip start time for adding to play2 arguments. //#547 don't set the start property unless set, causes problems for live streams. if (clip.start) dsResource.clipStartTime = clip.start; clip.setCustomProperty("urlResource", dsResource); } //#500 setup osmf netclient when configuring metrics. if (netStream && ! (netStream.client is OsmfNetStreamClient)) { var netStreamClient:OsmfNetStreamClient = new OsmfNetStreamClient(NetStreamClient(netStream.client)); netStream.client = netStreamClient; } setupMetrics(netStream); } private function setupMetrics(netStream:NetStream):void { CONFIG::enableRtmpMetrics { //#500 fix for netstream metrics, do not set to the clip properties as it causes errors with event callbacks. if (_provider.type == "rtmp") { _netStreamMetrics = new RTMPNetStreamMetrics(netStream); _netStreamMetrics.resource = dsResource; _switchManager = new NetStreamSwitchManager(_provider.netConnection, netStream, dsResource, _netStreamMetrics, getRTMPSwitchingRules(_netStreamMetrics as RTMPNetStreamMetrics)); log.debug("using switch manager " + _switchManager); _netStreamMetrics.startMeasurements(); } } CONFIG::enableHttpMetrics { if (_provider.type == "httpstreaming") { _netStreamMetrics = new HTTPNetStreamMetrics(netStream as HTTPNetStream); _netStreamMetrics.resource = dsResource; _switchManager = new NetStreamSwitchManager(_provider.netConnection, netStream, dsResource, _netStreamMetrics, getHTTPSwitchingRules(_netStreamMetrics as HTTPNetStreamMetrics)); log.debug("using switch manager " + _switchManager); _netStreamMetrics.startMeasurements(); } } if (_streamSelectionManager is BWStreamSelectionManager) BWStreamSelectionManager(_streamSelectionManager).qosSwitchManager = _switchManager; //set the clear failed count interval to the clip duration in milliseconds times a prescision value _switchManager.clearFailedCountInterval = _config.qos.clearFailedCountInterval * (Math.round(_player.playlist.current.duration) * 1000); _switchManager.maxUpSwitchesPerStream = _config.qos.maxUpSwitchesPerStream; _switchManager.ruleCheckInterval = _config.qos.ruleCheckInterval; _switchManager.waitDurationAfterDownSwitch = _config.qos.waitDurationAfterDownSwitch; } CONFIG::enableRtmpMetrics { private function getRTMPSwitchingRules(metrics:RTMPNetStreamMetrics):Vector. { var rules:Vector. = new Vector.(); addRule("bwUp", rules, new SufficientBandwidthRule(metrics, _config.qos.bitrateSafety, _config.qos.minDroppedFrames)); addRule("bwDown", rules, new InsufficientBandwidthRule(metrics, _config.qos.bitrateSafety)); addRule("frames", rules, new DroppedFramesRule(metrics, _config.qos.framesToOne, _config.qos.framesToTwo, _config.qos.framesToLow)); addRule("buffer", rules, new InsufficientBufferRule(metrics, _config.qos.minBufferLength)); addRule("screen", rules, new ScreenSizeRule(metrics, _streamSelectionManager, _player, _config)); return rules; } } CONFIG::enableHttpMetrics { private function getHTTPSwitchingRules(metrics:HTTPNetStreamMetrics):Vector. { var rules:Vector. = new Vector.(); addRule("ratio", rules, new DownloadRatioRule(metrics)); addRule("frames", rules, new DroppedFramesRule(metrics)); addRule("screen", rules, new ScreenSizeRule(metrics, _streamSelectionManager, _player, _config)); return rules; } } [External] public function currentItem():BitrateItem { log.info("currentItem(), _switchManager.currentIndex: " + (_switchManager ? _switchManager.currentIndex : "no switch manager") + ", streamSelectionManager.currentIndex: " + _streamSelectionManager.currentIndex ); return BitrateItem(_streamSelectionManager.streamItems[_switchManager ? _switchManager.currentIndex : _streamSelectionManager.currentIndex]); } protected function getClipUrl(clip:Clip, mappedBitrate:BitrateItem):String { log.info("Resolved stream url: " + mappedBitrate.url); return mappedBitrate.url; } private function checkCurrentClip():Boolean { var clip:Clip = _player.playlist.current; if (_clip == clip) return true; if (clip.urlResolvers && clip.urlResolvers.indexOf(_model.name) < 0) { return false; } _clip = clip; return true; } [External] public function checkBandwidth():void { log.debug("checkBandwidth"); if (! checkCurrentClip()) return; _start = _provider ? _provider.time : 0; _hasDetectedBW = false; _bitrateStorage.clear(); detect(); } [External] public function setBitrate(bitrate:Number):void { log.debug("set bitrate()"); if (! checkCurrentClip()) return; try { if (_player.isPlaying() || _player.isPaused()) { switchStream(getMappedBitrate(bitrate)); _config.dynamic = false; if (_switchManager) { _switchManager.autoSwitch = false; } } } catch (e:Error) { log.error("error when switching streams " + e); } } [External] public function enableDynamic(enabled:Boolean):void { log.debug("set dynamic(), currently " + _config.dynamic + ", new value " + enabled); if (_config.dynamic == enabled) return; _config.dynamic = enabled; if (enabled) { if (! _switchManager) { var clip:Clip = _player.playlist.current; initQoS(clip.getNetStream(), clip); } _switchManager.autoSwitch = true; } else { if (_switchManager) { _switchManager.autoSwitch = false; } } } [External] public function get labels():Object { var labels:Object = {}; for (var i:int = 0; i < bitrateItems.length; i++) { var item:BitrateItem = bitrateItems[i] as BitrateItem; if (item.label) { labels[item.bitrate] = item.label; } } return labels; } /** * Gets the current bitrate. The returned value is the bitrate in use after the latest bitrate transition has been completed. If * a transition is in progress the value reflects the bitrate right now being used, not the one we are changing to. * @return */ [External] public function get bitrate():Number { log.debug("get bitrate()"); if (! checkCurrentClip()) return undefined; if (_config.rememberBitrate && _bitrateStorage.bandwidth >= 0) { log.debug("get bitrate(), returning remembered bandwidth"); var mappedBitrate:BitrateItem = getMappedBitrate(_bitrateStorage.bandwidth); return mappedBitrate.bitrate; } log.debug("get bitrate(), returning current bitrate"); return currentItem().bitrate; } /** * Get the netstream metrics for external measurement monitoring. */ [External] public function get netStreamMetrics():NetStreamMetricsBase { return _netStreamMetrics; } public function getDefaultConfig():Object { return { top: "45%", left: "50%", opacity: 1, borderRadius: 15, border: 'none', width: "80%", height: "80%" }; } private function lookupProvider(providers:Dictionary):void { log.debug("lookupProvider() " + providers); if (_config.provider) { var model:PluginModel = _player.pluginRegistry.getPlugin(_config.provider) as PluginModel; if (! model) throw new Error("Failed to find plugin '" + _config.provider + "'"); if (! (model.pluginObject is StreamProvider)) throw new Error("The specified provider is not a StreamProvider"); _provider = StreamProvider(model.pluginObject); return; } for each (model in providers) { log.debug(model.name); if (model.name == "rtmp") { _provider = StreamProvider(model.pluginObject); return; } if (["http", "httpInstream"].indexOf(model.name) < 0 && model.pluginObject is StreamProvider) { _provider = StreamProvider(model.pluginObject); } } } } } \ No newline at end of file +/* * This file is part of Flowplayer, http://flowplayer.org * * By: Daniel Rossi , Anssi Piirainen Flowplayer Oy * Copyright (c) 2009, 2010 Electroteque Multimedia, Flowplayer Oy * * Released under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.bwcheck { import de.betriebsraum.video.BufferCalculator; import flash.display.DisplayObject; import flash.events.NetStatusEvent; import flash.net.NetStream; import org.flowplayer.bwcheck.net.OsmfLoggerFactory; import org.flowplayer.bwcheck.net.OsmfNetStreamClient; import org.flowplayer.net.BitrateItem; import org.flowplayer.net.IStreamSelectionManager; import org.flowplayer.net.StreamSwitchManager; import org.flowplayer.net.BitrateResource; import org.flowplayer.bwcheck.config.Config; import org.flowplayer.bwcheck.detect.BandwidthDetectEvent; import org.flowplayer.bwcheck.detect.BandwidthDetector; import org.flowplayer.bwcheck.net.ScreenSizeRule; import org.flowplayer.bwcheck.net.BWStreamSelectionManager; import org.flowplayer.controller.ClipURLResolver; import org.flowplayer.controller.NetStreamClient; import org.flowplayer.controller.StreamProvider; import org.flowplayer.model.Clip; import org.flowplayer.model.ClipEvent; import org.flowplayer.model.PlayerEvent; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginEventType; import org.flowplayer.model.PluginModel; import org.flowplayer.util.PropertyBinder; import org.flowplayer.view.AbstractSprite; import org.flowplayer.view.Flowplayer; import org.osmf.net.DynamicStreamingItem; import org.osmf.net.DynamicStreamingResource; import org.osmf.net.NetStreamMetricsBase; CONFIG::LOGGING { import org.osmf.logging.Log; } CONFIG::enableRtmpMetrics { import org.osmf.net.rtmpstreaming.RTMPNetStreamMetrics; import org.osmf.net.rtmpstreaming.DroppedFramesRule; import org.osmf.net.rtmpstreaming.InsufficientBandwidthRule; import org.osmf.net.rtmpstreaming.InsufficientBufferRule; import org.osmf.net.rtmpstreaming.SufficientBandwidthRule; import org.osmf.net.NetStreamSwitchManagerBase; import org.osmf.net.SwitchingRuleBase; import org.osmf.net.NetStreamSwitchManager; } CONFIG::enableHttpMetrics { import org.osmf.net.metrics.MetricFactory; import org.osmf.net.metrics.MetricRepository; import org.osmf.net.metrics.DefaultMetricFactory; import org.osmf.net.qos.QoSInfoHistory; import org.osmf.net.rules.AfterUpSwitchBufferBandwidthRule; import org.osmf.net.rules.BufferBandwidthRule; import org.osmf.net.rules.DroppedFPSRule; import org.osmf.net.rules.EmptyBufferRule; import org.osmf.net.NetStreamSwitcher; import org.osmf.net.rules.RuleBase; import org.osmf.net.httpstreaming.DefaultHTTPStreamingSwitchManager; import org.osmf.net.NetStreamSwitchManagerBase; } public class BwCheckProvider extends AbstractSprite implements ClipURLResolver, Plugin { protected var _config:Config; protected var _netStream:NetStream; protected var _resolveSuccessListener:Function; protected var _failureListener:Function; protected var _clip:Clip; protected var _hasDetectedBW:Boolean = false; protected var _model:PluginModel; protected var _player:Flowplayer; protected var _resolving:Boolean; protected var _playButton:DisplayObject; protected var _provider:StreamProvider; protected var _bitrateStorage:BitrateStorage; protected var _detector:BandwidthDetector; protected var _switchManager:NetStreamSwitchManagerBase; protected var _netStreamMetrics:NetStreamMetricsBase; protected var dsResource:DynamicStreamingResource; protected var _streamSelectionManager:IStreamSelectionManager; protected var _streamSwitchManager:StreamSwitchManager; CONFIG::enableHttpMetrics { protected var BANDWIDTH_BUFFER_RULE_WEIGHTS:Vector. = new [7, 3]; protected var BANDWIDTH_BUFFER_RULE_BUFFER_FRAGMENTS_THRESHOLD:uint = 2; protected var MAXIMUM_DROPPED_FPS_RATIO:Number = 0.1; protected var FPS_DESIRED_SAMPLE_LENGTH_IN_SECOND:int = 10; protected var AFTER_UP_SWITCH_BANDWIDTH_BUFFER_RULE_BUFFER_FRAGMENTS_THRESHOLD:uint = 2; protected var AFTER_UP_SWITCH_BANDWIDTH_BUFFER_RULE_MIN_RATIO:Number = 0.5; //protected var EMPTY_BUFFER_RULE_SCALE_DOWN_FACTOR:Number = 0.4; protected var QOS_MAX_HISTORY_LENGTH:Number = 10; } public function onConfig(model:PluginModel):void { log.debug("onConfig(_)"); CONFIG::LOGGING { Log.loggerFactory = new OsmfLoggerFactory(); } _config = new PropertyBinder(new Config()).copyProperties(model.config) as Config; _model = model; _bitrateStorage = new BitrateStorage(_config.bitrateProfileName, "/"); _bitrateStorage.expiry = _config.cacheExpiry; log.debug("onConfig(), dynamic " + _config.dynamic); } protected function applyForClip(clip:Clip):Boolean { var bw:Object = clip.getCustomProperty("bwcheck"); log.debug("applyForClip() ? " + bw); if (bw is Boolean && ! bw) return false; return true; } protected function canSwitchOnFullscreen():Boolean { //disabling fullscreen switching on dynamic for now #336 return _config.switchOnFullscreen && _player.playlist.current.provider != "http" && !_config.dynamic; } public function onLoad(player:Flowplayer):void { log.debug("onLoad()"); _player = player; _detector = new BandwidthDetector(_model, _config, _player.playlist); _detector.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE, onDetectorComplete); _detector.addEventListener(BandwidthDetectEvent.CLUSTER_FAILED, onClusterFailed); if (canSwitchOnFullscreen()) { _player.onFullscreen(onFullscreen); _player.onFullscreenExit(onFullscreen); } _player.playlist.onSwitch(function(event:ClipEvent):void { //fixes for #336 provide correction bitrateitem information when using dynamic stream switching //fixes for #352 for wowza streams with secure names that return the real name from the server, return the item from the metrics index instead. var newItem:DynamicStreamingItem = _streamSelectionManager.fromName(String(event.info)); log.info("new item is " + newItem + ", (" + event.info + "), current " + _streamSelectionManager.currentBitrateItem); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onStreamSwitchBegin", newItem, _streamSelectionManager.currentBitrateItem); }); _player.playlist.onSwitchFailed(function(event:ClipEvent):void { log.info("Transition failed with error " + event.info2.toString()); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onStreamSwitchFailed", "Transition failed with error " + event.info2.toString()); }); _player.playlist.onSwitchComplete(function(event:ClipEvent):void { log.info("Stream switch completed with item " + _streamSelectionManager.currentBitrateItem); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onStreamSwitch", _streamSelectionManager.currentBitrateItem); }); _player.playlist.onStart(function(event:ClipEvent):void { log.debug("onStart() clip == " + clip); var clip:Clip = event.target as Clip; if (alreadyResolved(clip)) { init(clip.getNetStream(), clip); //only setup dynamic stream switching in these conditions if (_config.dynamic && _streamSelectionManager is BWStreamSelectionManager) { initQoS(clip.getNetStream(), clip); } } }, applyForClip); var autoSwitch:Function = function(enable:Boolean):Function { return function(event:ClipEvent):void { if (! _switchManager) return; var newVal:Boolean = _config.dynamic && enable; log.info("setting QOS state to " + newVal); _switchManager.autoSwitch = newVal; } }; _player.playlist.onPause(autoSwitch(false), applyForClip); _player.playlist.onStop(autoSwitch(false), applyForClip); _player.playlist.onStart(autoSwitch(true), applyForClip); _player.playlist.onResume(autoSwitch(true)),applyForClip; _player.playlist.onFinish(autoSwitch(false), applyForClip); _model.dispatchOnLoad(); } protected function onFullscreen(event:PlayerEvent):void { log.debug("onFullscreen(), checking bandwidth and switching stream"); checkBandwidthIfNotDetectedYet(); } protected function alreadyResolved(clip:Clip):Boolean { return clip.getCustomProperty("bwcheckResolvedUrl") != null; } protected function hasDetectedBW():Boolean { if (! _config.rememberBitrate) return false; if (_hasDetectedBW) return true; if (isRememberedBitrateValid()) return true; return false; } public function set onFailure(listener:Function):void { _failureListener = listener; } public function handeNetStatusEvent(event:NetStatusEvent):Boolean { return true; } protected function detect():void { log.debug("connectServer()"); _detector.detect(); } protected function onClusterFailed(event:BandwidthDetectEvent):void { log.error("onClusterFailed(), will use default bitrate"); useDefaultBitrate(); } protected function onDetectorComplete(event:BandwidthDetectEvent):void { log.debug("onDetectorComplete()"); event.stopPropagation(); log.info("\n\n kbit Down: " + event.info.kbitDown + " Delta Down: " + event.info.deltaDown + " Delta Time: " + event.info.deltaTime + " Latency: " + event.info.latency); _hasDetectedBW = true; // Set the detected bandwidth var bandwidth:Number = event.info.kbitDown; var mappedBitrate:BitrateItem = getMappedBitrate(bandwidth); log.debug("bandwidth (kbitDown) " + bandwidth); log.info("mapped to bitrate " + mappedBitrate.bitrate); rememberBandwidth(bandwidth); selectBitrate(mappedBitrate, bandwidth); } protected function getMappedBitrate(bandwidth:Number = -1):BitrateItem { return _streamSelectionManager.getStream(bandwidth) as BitrateItem; } protected function dynamicBuffering(mappedBitrate:Number, detectedBitrate:Number):void { if (_config.dynamicBuffer) { _clip.onMetaData(function(event:ClipEvent):void { _clip.bufferLength = BufferCalculator.calculate(_clip.metaData.duration, mappedBitrate, detectedBitrate); log.info("Dynamically setting buffer time to " + _clip.bufferLength + "s"); }); } } protected function selectBitrate(mappedBitrate:BitrateItem, detectedBitrate:Number = -1):void { log.debug("selectBitrate()"); dynamicBuffering(mappedBitrate.bitrate, detectedBitrate); if (_playButton && _playButton.hasOwnProperty("stopBuffering")) { _playButton["stopBuffering"](); } //move this event up to give it time before onStreamSwitchBegin is called. log.info("dispatching onBwDone, mapped bitrate: " + mappedBitrate.bitrate + " detected bitrate " + detectedBitrate + " url: " + mappedBitrate.streamName); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onBwDone", mappedBitrate, detectedBitrate); if (_resolving) { _streamSelectionManager.changeStreamNames(mappedBitrate); _resolveSuccessListener(_clip); _resolving = false; } else if (_netStream && (_player.isPlaying() || _player.isPaused())) { switchStream(mappedBitrate); } else { _streamSelectionManager.changeStreamNames(mappedBitrate); } } protected function switchStream(mappedBitrate:BitrateItem):void { _streamSwitchManager.switchStream(mappedBitrate); } [External] public function get bitrateItems():Vector. { return Vector.(_streamSelectionManager.bitrates); } /** * Store the detection and chosen bitrate if the rememberBitrate config property is set. */ protected function rememberBandwidth(bw:int):void { if (_config.rememberBitrate) { _bitrateStorage.bandwidth = bw; log.debug("stored bandwidth " + bw); } } protected function isRememberedBitrateValid():Boolean { log.debug("isRememberedBitrateValid()"); if (! _bitrateStorage.bandwidth) { log.debug("bandwidth not in SO"); return false; } var expired:Boolean = _bitrateStorage.isExpired; log.info("is remembered bitrate expired?: " + expired + (expired ? ", age is " + _bitrateStorage.age : "")); return ! expired; } public function resolve(provider:StreamProvider, clip:Clip, successListener:Function):void { log.debug("resolve " + clip); if (!clip.getCustomProperty("bitrates") && !clip.getCustomProperty("bitrateItems")) { log.info("Bitrates configuration not enabled for this clip"); successListener(clip); return; } if (alreadyResolved(clip)) { log.info("resolve(): bandwidth already resolved for clip " + clip + ", will not detect again"); successListener(clip); return; } _provider = provider; _resolving = true; _resolveSuccessListener = successListener; init(provider.netStream, clip); checkBandwidthIfNotDetectedYet(); } protected function useDefaultBitrate():void { selectBitrate(getMappedBitrate(), -1); } protected function useStoredBitrate():void { var mappedBitrate:BitrateItem = getMappedBitrate(_bitrateStorage.bandwidth); log.info("using remembered bandwidth " + _bitrateStorage.bandwidth + ", maps to bitrate " + mappedBitrate.bitrate); selectBitrate(mappedBitrate, _bitrateStorage.bandwidth); } protected function checkBandwidthIfNotDetectedYet():void { if (! applyForClip(_player.playlist.current)) return; if (hasDetectedBW()) { useStoredBitrate(); } else if (_config.checkOnStart) { log.info("not using remembered bandwidth, detecting now"); detect(); } else { log.info("using dynamic switching with default bitrate "); useDefaultBitrate(); } } protected function init(netStream:NetStream, clip:Clip):void { log.debug("init(), netStream == " + netStream + ", clip == " + clip); _netStream = netStream; _clip = clip; if (!_clip.getCustomProperty("streamSelectionManager")) { _streamSelectionManager = new BWStreamSelectionManager(new BitrateResource(), _player, this, _config); _clip.setCustomProperty("streamSelectionManager",_streamSelectionManager); } else { _streamSelectionManager = _clip.getCustomProperty("streamSelectionManager") as IStreamSelectionManager; } initSwitchManager(); } protected function initSwitchManager():void { _streamSwitchManager = new StreamSwitchManager(_netStream, _streamSelectionManager, _player); } protected function initQoS(netStream:NetStream, clip:Clip):void { log.info("initQoS(), netStream == " + netStream + ", host == " + _detector.host); import org.osmf.net.StreamType; //save the streaming resource and load for each clip in the playlist if (clip.getCustomProperty("urlResource")) { dsResource = clip.getCustomProperty("urlResource") as DynamicStreamingResource; dsResource.initialIndex = _streamSelectionManager.currentIndex; } else { dsResource = new DynamicStreamingResource(_detector.host); dsResource.streamItems = bitrateItems; dsResource.initialIndex = _streamSelectionManager.currentIndex; dsResource.streamType = _config.live ? StreamType.LIVE : StreamType.RECORDED; //#369 set clip start time for adding to play2 arguments. //#547 don't set the start property unless set, causes problems for live streams. if (clip.start) dsResource.clipStartTime = clip.start; clip.setCustomProperty("urlResource", dsResource); } //#500 setup osmf netclient when configuring metrics. if (netStream && ! (netStream.client is OsmfNetStreamClient)) { var netStreamClient:OsmfNetStreamClient = new OsmfNetStreamClient(NetStreamClient(netStream.client)); netStream.client = netStreamClient; } setupMetrics(netStream); } protected function setupMetrics(netStream:NetStream):void { CONFIG::enableRtmpMetrics { //#500 fix for netstream metrics, do not set to the clip properties as it causes errors with event callbacks. setupRtmpMetrics(netStream); } CONFIG::enableHttpMetrics { setupHttpStreamingMetrics(netStream); } if (_streamSelectionManager is BWStreamSelectionManager) BWStreamSelectionManager(_streamSelectionManager).qosSwitchManager = _switchManager; } /** * rtmp streaming metrics */ CONFIG::enableRtmpMetrics { protected function setupRtmpMetrics(netStream:NetStream):void { if (_provider.type == "rtmp") { _netStreamMetrics = new RTMPNetStreamMetrics(netStream); _netStreamMetrics.resource = dsResource; _switchManager = new NetStreamSwitchManager(_provider.netConnection, netStream, dsResource, _netStreamMetrics, getRTMPSwitchingRules(_netStreamMetrics as RTMPNetStreamMetrics)); //set the clear failed count interval to the clip duration in milliseconds times a prescision value NetStreamSwitchManager(_switchManager).clearFailedCountInterval = _config.qos.clearFailedCountInterval * (Math.round(_player.playlist.current.duration) * 1000); NetStreamSwitchManager(_switchManager).maxUpSwitchesPerStream = _config.qos.maxUpSwitchesPerStream; NetStreamSwitchManager(_switchManager).ruleCheckInterval = _config.qos.ruleCheckInterval; NetStreamSwitchManager(_switchManager).waitDurationAfterDownSwitch = _config.qos.waitDurationAfterDownSwitch; log.debug("using switch manager " + _switchManager); _netStreamMetrics.startMeasurements(); } } protected function getRTMPSwitchingRules(metrics:RTMPNetStreamMetrics):Vector. { var rules:Vector. = new Vector.(); addRule("bwUp", rules, new SufficientBandwidthRule(metrics, _config.qos.bitrateSafety, _config.qos.minDroppedFrames)); addRule("bwDown", rules, new InsufficientBandwidthRule(metrics, _config.qos.bitrateSafety)); addRule("frames", rules, new DroppedFramesRule(metrics, _config.qos.framesToOne, _config.qos.framesToTwo, _config.qos.framesToLow)); addRule("buffer", rules, new InsufficientBufferRule(metrics, _config.qos.minBufferLength)); addRule("screen", rules, new ScreenSizeRule(metrics, _streamSelectionManager, _player, _config)); return rules; } protected function addRule(prop:String, rules:Vector., rule:SwitchingRuleBase):void { if (_config.qos[prop]) { log.info("using QoS switching rules " + rule); rules.push(rule); } } } /** * http streaming metrics */ CONFIG::enableHttpMetrics { protected function setupHttpStreamingMetrics(netStream:NetStream):void { if (_provider.type == "httpstreaming") { //#70 refactored changes to dynamic stream switching support for httpstreaming with OSMF 2.0 //the switching apis and metrics are different between rtmp and httpstreaming therefore requires different setups. //#70 change httpstreaming metrics to overridable methods. /* AdobePatentID="2278US01" */ // Create a QoSInfoHistory, to hold a history of QoSInfo provided by the NetStream var netStreamQoSInfoHistory:QoSInfoHistory = createQosInfoHistory(netStream); // Create a MetricFactory, to be used by the metric repository for instantiating metrics var metricFactory:MetricFactory = createMetricFactory(netStreamQoSInfoHistory); // Create the MetricRepository, which caches metrics var metricRepository:MetricRepository = createMetricRepository(metricFactory); // Create the normal rule var normalRules:Vector. = createNormalRules(metricRepository); var normalRuleWeights:Vector. = new Vector.(); normalRuleWeights.push(1); // Create the emergency rules var emergencyRules:Vector. = createEmergencyRules(metricRepository); // Create a NetStreamSwitcher, which will handle the low-level details of NetStream // stream switching var nsSwitcher:NetStreamSwitcher = createNetStreamSwitcher(netStream); // Finally, return an instance of the DefaultSwitchManager, passing it // the objects we instatiated above _switchManager = new DefaultHTTPStreamingSwitchManager ( netStream , nsSwitcher , metricRepository , emergencyRules , true , normalRules , normalRuleWeights ); } } //#70 changes to httpstreaming metrics rules protected function addHttpRule(prop:String, rules:Vector., rule:RuleBase):void { if (_config.qos[prop]) { log.info("using QoS switching rules " + rule); rules.push(rule); } } protected function createQosInfoHistory(netStream:NetStream):QoSInfoHistory { return new QoSInfoHistory(netStream, QOS_MAX_HISTORY_LENGTH); } protected function createMetricFactory(qosInfoHistory:QoSInfoHistory):MetricFactory { return new DefaultMetricFactory(qosInfoHistory); } protected function createMetricRepository(metricFactory:MetricFactory):MetricRepository { return new MetricRepository(metricFactory); } protected function createNormalRules(metricRepository:MetricRepository):Vector. { var normalRules:Vector. = new Vector.(); addHttpRule("bwUp", normalRules, new BufferBandwidthRule( metricRepository, BANDWIDTH_BUFFER_RULE_WEIGHTS, BANDWIDTH_BUFFER_RULE_BUFFER_FRAGMENTS_THRESHOLD)); return normalRules; } protected function createEmergencyRules(metricRepository:MetricRepository):Vector. { var emergencyRules:Vector. = new Vector.(); addHttpRule("frames", emergencyRules, new DroppedFPSRule(metricRepository, FPS_DESIRED_SAMPLE_LENGTH_IN_SECOND, MAXIMUM_DROPPED_FPS_RATIO)); //#127 set a configurable scale down factor for the empty buffer rule, default was 0.4 set it to 0.6 to recommend a higher rate to switch back up to. addHttpRule("buffer", emergencyRules, new EmptyBufferRule( metricRepository, _config.qos.bufferScaleDownFactor)); addHttpRule("bwDown", emergencyRules, new AfterUpSwitchBufferBandwidthRule( metricRepository , AFTER_UP_SWITCH_BANDWIDTH_BUFFER_RULE_BUFFER_FRAGMENTS_THRESHOLD , AFTER_UP_SWITCH_BANDWIDTH_BUFFER_RULE_MIN_RATIO)); return emergencyRules; } protected function createNetStreamSwitcher(netStream:NetStream):NetStreamSwitcher { return new NetStreamSwitcher(netStream, dsResource); } } [External] public function currentItem():BitrateItem { log.info("currentItem(), _switchManager.currentIndex: " + (_switchManager ? _switchManager.currentIndex : "no switch manager") + ", streamSelectionManager.currentIndex: " + _streamSelectionManager.currentIndex ); return BitrateItem(_streamSelectionManager.streamItems[_switchManager ? _switchManager.currentIndex : _streamSelectionManager.currentIndex]); } protected function getClipUrl(clip:Clip, mappedBitrate:BitrateItem):String { log.info("Resolved stream url: " + mappedBitrate.url); return mappedBitrate.url; } protected function checkCurrentClip():Boolean { var clip:Clip = _player.playlist.current; if (_clip == clip) return true; if (clip.urlResolvers && clip.urlResolvers.indexOf(_model.name) < 0) { return false; } _clip = clip; return true; } [External] public function checkBandwidth():void { log.debug("checkBandwidth"); if (! checkCurrentClip()) return; _hasDetectedBW = false; _bitrateStorage.clear(); detect(); } [External] public function setBitrate(bitrate:Number):void { log.debug("set bitrate()"); if (! checkCurrentClip()) return; try { if (_player.isPlaying() || _player.isPaused()) { switchStream(getMappedBitrate(bitrate)); _config.dynamic = false; if (_switchManager) { _switchManager.autoSwitch = false; } } } catch (e:Error) { log.error("error when switching streams " + e); } } [External] public function enableDynamic(enabled:Boolean):void { log.debug("set dynamic(), currently " + _config.dynamic + ", new value " + enabled); if (_config.dynamic == enabled) return; _config.dynamic = enabled; if (enabled) { if (! _switchManager) { var clip:Clip = _player.playlist.current; initQoS(clip.getNetStream(), clip); } _switchManager.autoSwitch = true; } else { if (_switchManager) { _switchManager.autoSwitch = false; } } } [External] public function get labels():Object { var labels:Object = {}; for (var i:int = 0; i < bitrateItems.length; i++) { var item:BitrateItem = bitrateItems[i] as BitrateItem; if (item.label) { labels[item.bitrate] = item.label; } } return labels; } /** * Gets the current bitrate. The returned value is the bitrate in use after the latest bitrate transition has been completed. If * a transition is in progress the value reflects the bitrate right now being used, not the one we are changing to. * @return */ [External] public function get bitrate():Number { log.debug("get bitrate()"); if (! checkCurrentClip()) return undefined; if (_config.rememberBitrate && _bitrateStorage.bandwidth >= 0) { log.debug("get bitrate(), returning remembered bandwidth"); var mappedBitrate:BitrateItem = getMappedBitrate(_bitrateStorage.bandwidth); return mappedBitrate.bitrate; } log.debug("get bitrate(), returning current bitrate"); return currentItem().bitrate; } /** * Get the netstream metrics for external measurement monitoring. */ [External] public function get netStreamMetrics():NetStreamMetricsBase { return _netStreamMetrics; } public function getDefaultConfig():Object { return { top: "45%", left: "50%", opacity: 1, borderRadius: 15, border: 'none', width: "80%", height: "80%" }; } } } \ No newline at end of file diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/config/QosRulesConfig.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/config/QosRulesConfig.as index aa93cb1..068b081 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/config/QosRulesConfig.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/config/QosRulesConfig.as @@ -37,11 +37,20 @@ package org.flowplayer.bwcheck.config { private var _maxUpSwitchesPerStream:int = 3; private var _waitDurationAfterDownSwitch:int = 30000; private var _clearFailedCountInterval:Number = 1; + private var _bufferScaleDownFactor:Number = 0.6; public function reset():void { _values = new Object(); } + public function get bufferScaleDownFactor():Number { + return _bufferScaleDownFactor; + } + + public function set bufferScaleDownFactor(value:Number):void { + _bufferScaleDownFactor = value; + } + public function get minBufferLength():Number { return _minBufferLength; } diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetector.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetector.as index b77e25e..89e31da 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetector.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetector.as @@ -8,28 +8,27 @@ * http://www.opensource.org/licenses/mit-license.php */ -package org.flowplayer.bwcheck.detect { -import flash.events.EventDispatcher; -import flash.events.NetStatusEvent; -import flash.net.NetConnection; - -import flash.utils.setTimeout; - -import org.flowplayer.bwcheck.config.Config; -import org.flowplayer.bwcheck.net.NullNetConnectionClient; - -import org.flowplayer.cluster.RTMPCluster; -import org.flowplayer.model.ClipEvent; -import org.flowplayer.model.Playlist; -import org.flowplayer.model.PluginEventType; -import org.flowplayer.model.PluginModel; -import org.flowplayer.util.Log; -import org.flowplayer.view.Flowplayer; - -/** - * @author danielr - */ -public class BandwidthDetector extends EventDispatcher { + package org.flowplayer.bwcheck.detect { + import flash.events.EventDispatcher; + import flash.events.NetStatusEvent; + import flash.net.NetConnection; + + import flash.utils.setTimeout; + + import org.flowplayer.bwcheck.config.Config; + import org.flowplayer.bwcheck.net.NullNetConnectionClient; + + import org.flowplayer.cluster.RTMPCluster; + import org.flowplayer.model.ClipEvent; + import org.flowplayer.model.Playlist; + import org.flowplayer.model.PluginEventType; + import org.flowplayer.model.PluginModel; + import org.flowplayer.util.Log; + + /** + * @author danielr + */ + public class BandwidthDetector extends EventDispatcher { private var log:Log = new Log(this); // --------- These references are needed here, so that the classes get compiled in! diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorFms.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorFms.as index a3a407d..3ad1a83 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorFms.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorFms.as @@ -8,15 +8,11 @@ */ package org.flowplayer.bwcheck.detect { -import org.flowplayer.bwcheck.detect.*; -import org.flowplayer.bwcheck.detect.AbstractDetectionStrategy; -import flash.utils.setTimeout; - -/** - * @author danielr - */ -public class BandwidthDetectorFms extends AbstractDetectionStrategy { + /** + * @author danielr + */ + public class BandwidthDetectorFms extends AbstractDetectionStrategy { private var _host:String; diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorHttp.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorHttp.as index 17c0204..cf78bc3 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorHttp.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorHttp.as @@ -13,7 +13,6 @@ package org.flowplayer.bwcheck.detect { import flash.events.ProgressEvent; import flash.net.URLLoader; import flash.net.URLRequest; - import flash.net.URLRequestHeader; import flash.net.URLRequestMethod; import flash.utils.getTimer; @@ -28,7 +27,6 @@ package org.flowplayer.bwcheck.detect { private var _bandwidth:Number; private var _downloadTime:Number; public var maximumBytes:uint; - private var _nocache:URLRequestHeader; private var _referenceFileUrl:String; public function BandwidthDetectorHttp() { diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorOldfms.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorOldfms.as index cd6dbec..b20a502 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorOldfms.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorOldfms.as @@ -8,7 +8,6 @@ */ package org.flowplayer.bwcheck.detect { - import org.flowplayer.bwcheck.detect.AbstractDetectionStrategy; /** * @author danielr diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorRed5.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorRed5.as index a83d65c..ffce95b 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorRed5.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorRed5.as @@ -8,9 +8,6 @@ */ package org.flowplayer.bwcheck.detect { - import flash.net.Responder; - - import org.flowplayer.bwcheck.detect.AbstractDetectionStrategy; /** * @author danielr diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorWowza.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorWowza.as index 498a1e7..ee6a0cb 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorWowza.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/BandwidthDetectorWowza.as @@ -8,15 +8,11 @@ */ package org.flowplayer.bwcheck.detect { - import flash.net.Responder; - - import org.flowplayer.bwcheck.detect.AbstractDetectionStrategy; /** * @author danielr */ public class BandwidthDetectorWowza extends AbstractDetectionStrategy { - private var info:Object = new Object(); public function onBwCheck(obj:Object):Boolean { return onBWCheck(obj); diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/DynamicStreamEvent.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/DynamicStreamEvent.as deleted file mode 100644 index 0cc76ac..0000000 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/detect/DynamicStreamEvent.as +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of Flowplayer, http://flowplayer.org - * - * By: Daniel Rossi, , Anssi Piirainen Flowplayer Oy - * Copyright (c) 2008-2011 Flowplayer Oy * - * Released under the MIT License: - * http://www.opensource.org/licenses/mit-license.php - */ - -package org.flowplayer.bwcheck.detect { - import flash.events.Event; - - public class DynamicStreamEvent extends Event { - public static const SWITCH_STREAM:String = "switch_stream"; - - private var _info:Object; - - public function DynamicStreamEvent(eventName:String) { - super(eventName); - } - - public function set info(obj:Object):void { - _info = obj; - } - - public function get info():Object { - return _info; - } - - } -} \ No newline at end of file diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/net/BWStreamSelectionManager.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/net/BWStreamSelectionManager.as index 0e974a2..88d93f2 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/net/BWStreamSelectionManager.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/net/BWStreamSelectionManager.as @@ -16,9 +16,6 @@ package org.flowplayer.bwcheck.net { import org.flowplayer.view.Flowplayer; import org.flowplayer.controller.ClipURLResolver; import org.flowplayer.util.Log; - import org.flowplayer.util.PropertyBinder; - - import org.flowplayer.model.DisplayProperties; @@ -27,17 +24,17 @@ package org.flowplayer.bwcheck.net { import org.flowplayer.bwcheck.config.Config; - import org.osmf.net.DynamicStreamingItem; - import org.osmf.net.NetStreamMetricsBase; -import org.osmf.net.NetStreamSwitchManager; + import org.osmf.net.NetStreamSwitchManagerBase; + + CONFIG::enableRtmpMetrics { + import org.osmf.net.NetStreamSwitchManager; + } -public class BWStreamSelectionManager extends StreamSelectionManager { + public class BWStreamSelectionManager extends StreamSelectionManager { private var _config:Config; private static var bwSelectLog:Log = new Log("org.flowplayer.bwcheck.net::BWStreamSelectionManager"); - private var dynamicStreamingItems:Vector.; - //private var _netStreamMetrics:NetStreamMetricsBase; - private var _netStreamSwitchManager:NetStreamSwitchManager; + private var _netStreamSwitchManager:NetStreamSwitchManagerBase; public function BWStreamSelectionManager(bitrateResource:BitrateResource, player:Flowplayer, resolver:ClipURLResolver, config:Config) { super(bitrateResource, player, resolver); @@ -95,8 +92,16 @@ public class BWStreamSelectionManager extends StreamSelectionManager { override public function fromName(name:String):BitrateItem { var item:BitrateItem = super.fromName(name); - if (_netStreamSwitchManager) { - return item ? item : getItem(_netStreamSwitchManager.netStreamMetrics.currentIndex); + CONFIG::enableRtmpMetrics { + if (_netStreamSwitchManager) { + return item ? item : getItem(NetStreamSwitchManager(_netStreamSwitchManager).netStreamMetrics.currentIndex); + } + } + + CONFIG::enableHttpMetrics { + if (_netStreamSwitchManager) { + return item ? item : getItem(_netStreamSwitchManager.currentIndex); + } } return item; @@ -119,7 +124,7 @@ public class BWStreamSelectionManager extends StreamSelectionManager { if (_netStreamSwitchManager) _netStreamSwitchManager.currentIndex = value.index; } - public function set qosSwitchManager(value:NetStreamSwitchManager):void { + public function set qosSwitchManager(value:NetStreamSwitchManagerBase):void { _netStreamSwitchManager = value; } } diff --git a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/net/ScreenSizeRule.as b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/net/ScreenSizeRule.as index a9ef6a4..e13c3b1 100644 --- a/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/net/ScreenSizeRule.as +++ b/plugins/bwcheck/src/actionscript/org/flowplayer/bwcheck/net/ScreenSizeRule.as @@ -9,16 +9,13 @@ */ package org.flowplayer.bwcheck.net { - import org.flowplayer.bwcheck.detect.*; import org.flowplayer.bwcheck.config.Config; import org.flowplayer.util.Log; import org.flowplayer.view.Flowplayer; - import org.flowplayer.net.BitrateItem; import org.flowplayer.net.IStreamSelectionManager; - import org.osmf.net.DynamicStreamingItem; import org.osmf.net.SwitchingRuleBase; import org.osmf.net.rtmpstreaming.RTMPNetStreamMetrics; import org.osmf.net.NetStreamMetricsBase; @@ -37,7 +34,6 @@ package org.flowplayer.bwcheck.net { } override public function getNewIndex():int { - var screenWidth:Number = _player.screen.getDisplayObject().width; for (var i:Number = _bitrates.length - 1; i >= 0; i--) { var item:BitrateItem = _bitrates[i]; diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamMetricsBase.as b/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamMetricsBase.as index 10890c3..91bbce2 100644 --- a/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamMetricsBase.as +++ b/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamMetricsBase.as @@ -1,28 +1,28 @@ /***************************************************** - * - * Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. - * - ***************************************************** - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Akamai Technologies, Inc. - * Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai - * Technologies, Inc. All Rights Reserved. - * - * Contributor: Adobe Systems Inc. - * - *****************************************************/ -package org.osmf.net { - +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +* Contributor: Adobe Systems Inc. +* +*****************************************************/ +package org.osmf.net +{ import flash.events.EventDispatcher; import flash.events.NetStatusEvent; import flash.events.TimerEvent; @@ -30,52 +30,54 @@ package org.osmf.net { import flash.utils.Timer; CONFIG::LOGGING - { - import org.osmf.logging.Log; - import org.osmf.logging.Logger; + { + import org.osmf.logging.Log; + import org.osmf.logging.Logger; } - /** - * The NetStreamMetricsBase class serves as a base class for a provider of - * run-time metrics to the NetStreamSwitchManager and its set of switching - * rules. It calculates running averages for metrics that apply to all - * delivery methods. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public class NetStreamMetricsBase extends EventDispatcher { - /** - * Constructor. - * - * Note that for correct operation of this class, the caller must set the - * resource which the monitored stream is playing. - * - * @param netStream The NetStream instance the class will monitor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function NetStreamMetricsBase(netStream:NetStream) { - super(); - - _netStream = netStream; - - _droppedFPS = 0; - _lastFrameDropCounter = 0; - _lastFrameDropValue = 0; - _maxFPS = 0; - _averageDroppedFPSArray = new Array(); - - _timer = new Timer(DEFAULT_UPDATE_INTERVAL); - _timer.addEventListener(TimerEvent.TIMER, onTimerEvent); - - netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent); - } + /** + * The NetStreamMetricsBase class serves as a base class for a provider of + * run-time metrics to the NetStreamSwitchManager and its set of switching + * rules. It calculates running averages for metrics that apply to all + * delivery methods. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public class NetStreamMetricsBase extends EventDispatcher + { + /** + * Constructor. + * + * Note that for correct operation of this class, the caller must set the + * resource which the monitored stream is playing. + * + * @param netStream The NetStream instance the class will monitor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function NetStreamMetricsBase(netStream:NetStream) + { + super(); + + _netStream = netStream; + + _droppedFPS = 0; + _lastFrameDropCounter = 0; + _lastFrameDropValue = 0; + _maxFPS = 0; + _averageDroppedFPSArray = new Array(); + + _timer = new Timer(DEFAULT_UPDATE_INTERVAL); + _timer.addEventListener(TimerEvent.TIMER, onTimerEvent); + + netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent); + } // flowplayer addition public function startMeasurements():void { @@ -86,208 +88,233 @@ package org.osmf.net { _timer.start(); } - /** - * Returns the DynamicStreamingResource which the class is referencing. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get resource():DynamicStreamingResource { - return _resource; - } - - public function set resource(value:DynamicStreamingResource):void { - _resource = value; - _maxAllowedIndex = value != null ? value.streamItems.length - 1 : 0; - } - - /** - * The NetStream object supplied to the constructor. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get netStream():NetStream { - return _netStream; - } - - /** - * The current stream index. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get currentIndex():int { - return _currentIndex; - } - - public function set currentIndex(value:int):void { - _currentIndex = value; - } - - /** - * The maximum allowed index value. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get maxAllowedIndex():int { - return _maxAllowedIndex; - } - - public function set maxAllowedIndex(value:int):void { - _maxAllowedIndex = value; - } - - /** - * The update interval (in milliseconds) at which metrics are recalculated. If - * set to zero, then metrics will not be recalculated. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get updateInterval():Number { - return _timer.delay; - } - - public function set updateInterval(value:Number):void { - _timer.delay = value; - - if (value <= 0) { - _timer.stop(); - } - } - - /** - * The maximum achieved frame rate for this NetStream. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get maxFPS():Number { - return _maxFPS; - } - - /** - * The frame drop rate calculated over the last interval. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get droppedFPS():Number { - return _droppedFPS; - } - - /** - * The average frame-drop rate calculated over the life of the NetStream. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get averageDroppedFPS():Number { - return _averageDroppedFPS; - } - - // Protected - // - - /** - * Method invoked when the metrics should be recalculated. If - * updateInterval is set, this method will be invoked whenever the - * updateInterval is reached. - **/ - protected function calculateMetrics():void { - try { - // Estimate max (true) framerate. - _maxFPS = netStream.currentFPS > _maxFPS ? netStream.currentFPS : _maxFPS; - - // Frame drop rate, per second, calculated over last second. - if (_timer.currentCount - _lastFrameDropCounter > 1000 / _timer.delay) { - _droppedFPS = (netStream.info.droppedFrames - _lastFrameDropValue) / ((_timer.currentCount - _lastFrameDropCounter) * _timer.delay / 1000); - _lastFrameDropCounter = _timer.currentCount; - _lastFrameDropValue = netStream.info.droppedFrames; - } - _averageDroppedFPSArray.unshift(_droppedFPS); - if (_averageDroppedFPSArray.length > DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE) { - _averageDroppedFPSArray.pop(); - } - var totalDroppedFrameRate:Number = 0; - for (var f:uint = 0; f < _averageDroppedFPSArray.length; f++) { - totalDroppedFrameRate += _averageDroppedFPSArray[f]; - } - - _averageDroppedFPS = _averageDroppedFPSArray.length < DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE ? 0 : totalDroppedFrameRate / _averageDroppedFPSArray.length; - - } - catch (error:Error) { - CONFIG::LOGGING - { - logger.debug(".calculateMetrics() - " + error); - } - throw(error); - } - } - - // Internals - // - - private function onNetStatusEvent(event:NetStatusEvent):void { - switch (event.info.code) { - case NetStreamCodes.NETSTREAM_PLAY_START: - if (!_timer.running && updateInterval > 0) { - _timer.start(); - } - break; - case NetStreamCodes.NETSTREAM_PLAY_STOP: - _timer.stop(); - break; - } - } - - private function onTimerEvent(event:TimerEvent):void { - if (isNaN(netStream.time)) { - _timer.stop(); - } - else { - calculateMetrics(); - } - } - - private var _netStream:NetStream; - private var _resource:DynamicStreamingResource; - private var _currentIndex:int; - private var _maxAllowedIndex:int; - - private var _timer:Timer; - private var _averageDroppedFPSArray:Array; - private var _averageDroppedFPS:Number; - private var _droppedFPS:Number; - private var _lastFrameDropValue:Number; - private var _lastFrameDropCounter:Number; - private var _maxFPS:Number; - - private static const DEFAULT_UPDATE_INTERVAL:Number = 100; - private static const DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE:Number = 50; - - CONFIG::LOGGING - { - private static const logger:Logger = Log.getLogger("org.osmf.net.NetStreamMetricsBase"); - } - } + /** + * Returns the DynamicStreamingResource which the class is referencing. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get resource():DynamicStreamingResource + { + return _resource; + } + + public function set resource(value:DynamicStreamingResource):void + { + _resource = value; + _maxAllowedIndex = value != null ? value.streamItems.length - 1 : 0; + } + + /** + * The NetStream object supplied to the constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get netStream():NetStream + { + return _netStream; + } + + /** + * The current stream index. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get currentIndex():int + { + return _currentIndex; + } + + public function set currentIndex(value:int):void + { + _currentIndex = value; + } + + /** + * The maximum allowed index value. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get maxAllowedIndex():int + { + return _maxAllowedIndex; + } + + public function set maxAllowedIndex(value:int):void + { + _maxAllowedIndex = value; + } + + /** + * The update interval (in milliseconds) at which metrics are recalculated. If + * set to zero, then metrics will not be recalculated. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get updateInterval():Number + { + return _timer.delay; + } + + public function set updateInterval(value:Number):void + { + _timer.delay = value; + + if (value <= 0) + { + _timer.stop(); + } + } + + /** + * The maximum achieved frame rate for this NetStream. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get maxFPS():Number + { + return _maxFPS; + } + + /** + * The frame drop rate calculated over the last interval. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get droppedFPS():Number + { + return _droppedFPS; + } + + /** + * The average frame-drop rate calculated over the life of the NetStream. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get averageDroppedFPS():Number + { + return _averageDroppedFPS; + } + + // Protected + // + + /** + * Method invoked when the metrics should be recalculated. If + * updateInterval is set, this method will be invoked whenever the + * updateInterval is reached. + **/ + protected function calculateMetrics():void + { + try + { + // Estimate max (true) framerate. + _maxFPS = netStream.currentFPS > _maxFPS ? netStream.currentFPS : _maxFPS; + + // Frame drop rate, per second, calculated over last second. + if (_timer.currentCount - _lastFrameDropCounter > 1000 / _timer.delay) + { + _droppedFPS = (netStream.info.droppedFrames - _lastFrameDropValue) / ((_timer.currentCount - _lastFrameDropCounter) * _timer.delay/1000); + _lastFrameDropCounter = _timer.currentCount; + _lastFrameDropValue = netStream.info.droppedFrames; + } + _averageDroppedFPSArray.unshift(_droppedFPS); + if (_averageDroppedFPSArray.length > DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE) + { + _averageDroppedFPSArray.pop(); + } + var totalDroppedFrameRate:Number = 0; + for (var f:uint=0;f < _averageDroppedFPSArray.length;f++) + { + totalDroppedFrameRate += _averageDroppedFPSArray[f]; + } + + _averageDroppedFPS = _averageDroppedFPSArray.length < DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE ? 0 : totalDroppedFrameRate / _averageDroppedFPSArray.length; + + } + catch (error:Error) + { + CONFIG::LOGGING + { + logger.debug(".calculateMetrics() - " + error); + } + throw(error); + } + } + + // Internals + // + + private function onNetStatusEvent(event:NetStatusEvent):void + { + switch (event.info.code) + { + case NetStreamCodes.NETSTREAM_PLAY_START: + if (!_timer.running && updateInterval > 0) + { + _timer.start(); + } + break; + case NetStreamCodes.NETSTREAM_PLAY_STOP: + _timer.stop(); + break; + } + } + + private function onTimerEvent(event:TimerEvent):void + { + if (isNaN(netStream.time)) + { + _timer.stop(); + } + else + { + calculateMetrics(); + } + } + + private var _netStream:NetStream; + private var _resource:DynamicStreamingResource; + private var _currentIndex:int; + private var _maxAllowedIndex:int; + + private var _timer:Timer; + private var _averageDroppedFPSArray:Array; + private var _averageDroppedFPS:Number; + private var _droppedFPS:Number; + private var _lastFrameDropValue:Number; + private var _lastFrameDropCounter:Number; + private var _maxFPS:Number; + + private static const DEFAULT_UPDATE_INTERVAL:Number = 100; + private static const DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE:Number = 50; + + CONFIG::LOGGING + { + private static const logger:Logger = Log.getLogger("org.osmf.net.NetStreamMetricsBase"); + } + } } diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitchManager.as b/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitchManager.as index c75e302..f60201d 100644 --- a/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitchManager.as +++ b/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitchManager.as @@ -1,157 +1,185 @@ /***************************************************** - * - * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. - * - ***************************************************** - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems - * Incorporated. All Rights Reserved. - * - *****************************************************/ -package org.osmf.net { - import __AS3__.vec.Vector; - - import flash.errors.IllegalOperationError; - import flash.events.NetStatusEvent; - import flash.events.TimerEvent; - import flash.net.NetConnection; - import flash.net.NetStream; - import flash.net.NetStreamPlayOptions; - import flash.net.NetStreamPlayTransitions; - import flash.utils.Dictionary; - import flash.utils.Timer; - import flash.utils.getTimer; - - import org.osmf.utils.OSMFStrings; - +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.net +{ + import __AS3__.vec.Vector; + + import flash.errors.IllegalOperationError; + import flash.events.NetStatusEvent; + import flash.events.TimerEvent; + import flash.net.NetConnection; + import flash.net.NetStream; + import flash.net.NetStreamPlayOptions; + import flash.net.NetStreamPlayTransitions; + import flash.utils.Dictionary; + import flash.utils.Timer; + import flash.utils.getTimer; + + import org.osmf.utils.OSMFStrings; + CONFIG::LOGGING { import org.osmf.logging.Logger; import org.osmf.logging.Log; } + + /** + * NetStreamSwitchManager is a default implementation of + * NetStreamSwitchManagerBase. It manages transitions between + * multi-bitrate (MBR) streams using configurable switching rules. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public class NetStreamSwitchManager extends NetStreamSwitchManagerBase + { + /** + * Constructor. + * + * @param connection The NetConnection for the NetStream that will be managed. + * @param netStream The NetStream to manage. + * @param resource The DynamicStreamingResource that is playing in the NetStream. + * @param metrics The provider of runtime metrics. + * @param switchingRules The switching rules that this manager will use. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + **/ + public function NetStreamSwitchManager + ( connection:NetConnection + , netStream:NetStream + , resource:DynamicStreamingResource + , metrics:NetStreamMetricsBase + , switchingRules:Vector., + autoSwitch:Boolean = true) + { + super(); + + this.connection = connection; + this.netStream = netStream; + this.dsResource = resource; + this.metrics = metrics; + metrics.resource = resource; + this.switchingRules = switchingRules || new Vector.(); + + _currentIndex = Math.max(0, Math.min(maxAllowedIndex, dsResource.initialIndex)); + + checkRulesTimer = new Timer(_ruleCheckInterval); + checkRulesTimer.addEventListener(TimerEvent.TIMER, checkRules); + super.autoSwitch = autoSwitch; + + failedDSI = new Dictionary(); + initDSIFailedCounts(); + + // We set the bandwidth in both directions based on a multiplier applied to the bitrate level. + _bandwidthLimit = 1.4 * resource.streamItems[resource.streamItems.length-1].bitrate * 1000/8; + + netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); + + // Make sure we get onPlayStatus first (by setting a higher priority) + // so that we can expose a consistent state to clients. + NetClient(netStream.client).addHandler(NetStreamCodes.ON_PLAY_STATUS, onPlayStatus, int.MAX_VALUE); + } + + /** + * @private + */ + override public function set autoSwitch(value:Boolean):void + { + super.autoSwitch = value; + + CONFIG::LOGGING + { + logger.debug("autoSwitch() - setting to " + value); + } + + if (_autoSwitch) + { + CONFIG::LOGGING + { + logger.debug("autoSwitch() - starting check rules timer."); + } + checkRulesTimer.start(); + } + else + { + CONFIG::LOGGING + { + logger.debug("autoSwitch() - stopping check rules timer."); + } + checkRulesTimer.stop(); + } + } - /** - * NetStreamSwitchManager is a default implementation of - * NetStreamSwitchManagerBase. It manages transitions between - * multi-bitrate (MBR) streams using configurable switching rules. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - public class NetStreamSwitchManager extends NetStreamSwitchManagerBase { /** - * Constructor. - * - * @param connection The NetConnection for the NetStream that will be managed. - * @param netStream The NetStream to manage. - * @param resource The DynamicStreamingResource that is playing in the NetStream. - * @param metrics The provider of runtime metrics. - * @param switchingRules The switching rules that this manager will use. + * flowplayer addition + * Get the netstream metrics to obtain it's index before switch completion if needed * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - **/ - - public function NetStreamSwitchManager - ( connection:NetConnection - , netStream:NetStream - , resource:DynamicStreamingResource - , metrics:NetStreamMetricsBase - , switchingRules:Vector., - autoSwitch:Boolean = true) - { - super(); - - this.connection = connection; - this.netStream = netStream; - this.dsResource = resource; - this.metrics = metrics; - metrics.resource = resource; - this.switchingRules = switchingRules || new Vector.(); - - _currentIndex = Math.max(0, Math.min(maxAllowedIndex, dsResource.initialIndex)); - - checkRulesTimer = new Timer(_ruleCheckInterval); - checkRulesTimer.addEventListener(TimerEvent.TIMER, checkRules); - super.autoSwitch = autoSwitch; - - failedDSI = new Dictionary(); - initDSIFailedCounts(); - - // We set the bandwidth in both directions based on a multiplier applied to the bitrate level. - _bandwidthLimit = 1.4 * resource.streamItems[resource.streamItems.length-1].bitrate * 1000/8; - - netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); - - // Make sure we get onPlayStatus first (by setting a higher priority) - // so that we can expose a consistent state to clients. - NetClient(netStream.client).addHandler(NetStreamCodes.ON_PLAY_STATUS, onPlayStatus, int.MAX_VALUE); - } - - /** - * @private + * @return NetStreamMetricsBase */ - override public function set autoSwitch(value:Boolean):void - { - super.autoSwitch = value; - - CONFIG::LOGGING - { - logger.debug("autoSwitch() - setting to " + value); - } - - if (_autoSwitch) - { - CONFIG::LOGGING - { - logger.debug("autoSwitch() - starting check rules timer."); - } - checkRulesTimer.start(); - } - else - { - CONFIG::LOGGING - { - logger.debug("autoSwitch() - stopping check rules timer."); - } - checkRulesTimer.stop(); - } - } - - override public function get maxAllowedIndex():int - { - var count:int = dsResource.streamItems.length - 1; - return (count < super.maxAllowedIndex ? count : super.maxAllowedIndex); + public function get netStreamMetrics():NetStreamMetricsBase { + return metrics; } + + /** + * @private + */ + override public function get currentIndex():uint + { + return _currentIndex; + } - /** - * @private - */ - override public function set maxAllowedIndex(value:int):void - { - if (value > dsResource.streamItems.length) - { - throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX)); - } - super.maxAllowedIndex = value; - metrics.maxAllowedIndex = value; + //flowplayer addition - set the current index + override public function set currentIndex(index:uint):void { + _currentIndex = index; } + /** + * @private + */ + override public function get maxAllowedIndex():int + { + var count:int = dsResource.streamItems.length - 1; + return (count < super.maxAllowedIndex ? count : super.maxAllowedIndex); + } + + /** + * @private + */ + override public function set maxAllowedIndex(value:int):void + { + if (value > dsResource.streamItems.length) + { + throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX)); + } + super.maxAllowedIndex = value; + metrics.maxAllowedIndex = value; + } + + //flowplayer additions make switching settings configurable /** * Rule check timer interval * @param value @@ -184,452 +212,419 @@ package org.osmf.net { public function set maxUpSwitchesPerStream(value:int):void { _maxUpSwitchesPerStream = value; } - - /** - * Get the netstream metrics to obtain it's index before switch completion if needed - * - * @return NetStreamMetricsBase - */ - public function get netStreamMetrics():NetStreamMetricsBase { - return metrics; - } - - /** - * @private - */ - override public function get currentIndex():uint { - return _currentIndex; - } - - public function set currentIndex(index:uint):void { - _currentIndex = index; - } - - - - /** - * @private - **/ - override public function switchTo(index:int):void - { - if (!_autoSwitch) - { - if (index < 0 || index > maxAllowedIndex) - { - throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX)); - } - else - { - CONFIG::LOGGING - { - logger.debug("switchTo() - manually switching to index: " + index); - } - - if (actualIndex == -1) - { - prepareForSwitching(); - } - executeSwitch(index); - } - } - else - { - throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_STREAM_NOT_IN_MANUAL_MODE)); - } - } - - // Protected - // - - /** - * Override this method to provide additional decisioning around - * allowing automatic switches to occur. This method will be invoked - * just prior to a switch request. If false is returned, that switch - * request will not take place. - * - *

      By default, the implementation does the following:

      - *

      1) When a switch down occurs, the stream being switched from has its - * failed count incremented. If, when the switching rules are evaluated - * again, a rule suggests switching up, since the stream previously - * failed, it won't be tried again until a duration (30s) elapses. This - * provides a better user experience by preventing a situation where - * the switch up is attempted but then fails almost immediately.

      - *

      2) Once a stream item has 3 failures, there will be no more - * attempts to switch to it until an interval (5m) has expired. At the - * end of this interval, all failed counts are reset to zero.

      - * - * @param newIndex The new index to switch to. - **/ - protected function canAutoSwitchNow(newIndex:int):Boolean - { - // If this stream has failed, we don't want to try it again until - // the wait period has elapsed - if (dsiFailedCounts[newIndex] >= 1) - { - var current:int = getTimer(); - if (current - failedDSI[newIndex] < _waitDurationAfterDownSwitch) - { - CONFIG::LOGGING - { - logger.debug("canAutoSwitchNow() - ignoring switch request because index has " + dsiFailedCounts[newIndex]+" failure(s) and only "+ (current - failedDSI[newIndex])/1000 + " seconds have passed since the last failure."); - } - return false; - } - } - // If the requested index is currently locked out, then we don't - // allow the switch. - else if (dsiFailedCounts[newIndex] > _maxUpSwitchesPerStream) - { - return false; - } - - return true; - } - - /** - * The multiplier to apply to the maximum bandwidth for the client. The - * default is 140% of the highest bitrate stream. - **/ - protected final function get bandwidthLimit():Number { - return _bandwidthLimit; - } - - protected final function set bandwidthLimit(value:Number):void { - _bandwidthLimit = value; - } - - /** - * Forces the evaluation of all the rules. - * - * @private - **/ - protected function doCheckRules():void - { - checkRules(null); - } - - // Internals - // - - /** - * Executes the switch to the specified index. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - private function executeSwitch(targetIndex:int):void - { - var nso:NetStreamPlayOptions = new NetStreamPlayOptions(); - - var playArgs:Object = NetStreamUtils.getPlayArgsForResource(dsResource); - - //#547 don't set the start property unless set, causes problems for live streams. - if (playArgs.start) nso.start = playArgs.start; - nso.len = playArgs.len; - - nso.streamName = dsResource.streamItems[targetIndex].streamName; - // - // FM-925, it seems that the oldStreamName cannot contain parameters, - // therefore we must remove them - // - var sn:String = oldStreamName; - if (sn != null && sn.indexOf("?") >= 0) - { - nso.oldStreamName = sn.substr(0, sn.indexOf("?")); - } - else - { - nso.oldStreamName = oldStreamName; - } - - nso.transition = NetStreamPlayTransitions.SWITCH; - - CONFIG::LOGGING - { - logger.debug("executeSwitch() - Switching to index " + (targetIndex) + " at " + Math.round(dsResource.streamItems[targetIndex].bitrate) + " kbps"); - } - - switching = true; - - //set the target index to be used after the transition - _targetIndex = targetIndex; - - netStream.play2(nso); - - oldStreamName = dsResource.streamItems[targetIndex].streamName; - - if (targetIndex < actualIndex && _autoSwitch) - { - // This is a failure for the current stream, so let's tag it as such. - incrementDSIFailedCount(actualIndex); - - // Keep track of when it failed so we don't try it again for - // another failedItemWaitPeriod milliseconds to improve the - // user experience. - failedDSI[actualIndex] = getTimer(); - } - } - - /** - * Checks all the switching rules. If a switching rule returns -1, it is - * recommending no change. If a switching rule returns a number greater than - * -1 it is recommending a switch to that index. This method uses the lesser of - * all the recommended indices that are greater than -1. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - private function checkRules(event:TimerEvent):void - { - if (switchingRules == null || switching || dsResource == null) - { - return; - } - - var newIndex:int = int.MAX_VALUE; - - for (var i:int = 0; i < switchingRules.length; i++) - { - var n:int = switchingRules[i].getNewIndex(); - - if (n != -1 && n < newIndex) - { - newIndex = n; - } - } - - // if the rules recommended a new bitrate index - // then make sure we respect the maximum allowed index - if ( newIndex != -1 - && newIndex != int.MAX_VALUE - && newIndex != actualIndex - ) - { - newIndex = Math.min(newIndex, maxAllowedIndex); - } - - // if no change was recommended then make sure that - // the current index is still respecting the maximum - // allowed index - if ( - (newIndex == -1 || newIndex == int.MAX_VALUE) - && actualIndex > maxAllowedIndex - ) - { - newIndex = maxAllowedIndex; - } - - if ( newIndex != -1 - && newIndex != int.MAX_VALUE - && newIndex != actualIndex - && !switching - && newIndex <= maxAllowedIndex - ) - { - if (actualIndex == -1) - { - prepareForSwitching(); - } - if (canAutoSwitchNow(newIndex)) - { - CONFIG::LOGGING - { - logger.debug("checkRules() - Calling for switch to " + newIndex + " at " + dsResource.streamItems[newIndex].bitrate + " kbps"); - } - executeSwitch(newIndex); - } - } - } - - private function onNetStatus(event:NetStatusEvent):void - { - CONFIG::LOGGING - { - logger.debug("onNetStatus() - event.info.code=" + event.info.code); - } - - switch (event.info.code) - { - case NetStreamCodes.NETSTREAM_PLAY_START: - if (actualIndex == -1) - { - prepareForSwitching(); - } - else if (_autoSwitch && checkRulesTimer.running == false) - { - //checkRulesTimer.start(); - } - break; - case NetStreamCodes.NETSTREAM_PLAY_TRANSITION: - //#352 for setups where the configured secure name is different to the file returned from the server use the configured targetIndex - var indexFromName:int = dsResource.indexFromName(event.info.details); - actualIndex = indexFromName > -1 ? indexFromName : _targetIndex; - if (actualIndex > -1) - { - switching = false; - metrics.currentIndex = actualIndex; - lastTransitionIndex = actualIndex; - } - break; - case NetStreamCodes.NETSTREAM_PLAY_FAILED: - switching = false; - break; - case NetStreamCodes.NETSTREAM_SEEK_NOTIFY: - switching = false; - if (lastTransitionIndex >= 0) - { - _currentIndex = lastTransitionIndex; - } - break; - case NetStreamCodes.NETSTREAM_PLAY_STOP: - checkRulesTimer.stop(); - CONFIG::LOGGING - { - logger.debug("onNetStatus() - Stopping rules since server has stopped sending data"); - } - break; - } - } - - //fix for wowza sending random arguments - private function onPlayStatus(...rest):void + + /** + * @private + **/ + override public function switchTo(index:int):void { - var info:Object = rest.length > 1 ? rest[2] : rest[0]; - CONFIG::LOGGING - { - logger.debug("onPlayStatus() - info.code=" + info.code); - } - - - switch (info.code) { - case NetStreamCodes.NETSTREAM_PLAY_TRANSITION_COMPLETE: - if (lastTransitionIndex >= 0) - { - _currentIndex = lastTransitionIndex; - lastTransitionIndex = -1; - } - - CONFIG::LOGGING - { - logger.debug("onPlayStatus() - Transition complete to index: " + currentIndex + " at " + Math.round(dsResource.streamItems[currentIndex].bitrate) + " kbps"); - } - - break; - } - } - - /** - * Prepare the manager for switching. Note that this doesn't necessarily - * mean a switch is imminent. - **/ - private function prepareForSwitching():void - { - // --- flowplayer addition - //if (prepared) { - // return; - //} - //prepared = true; - - initDSIFailedCounts(); - - metrics.resource = dsResource; - - actualIndex = 0; - lastTransitionIndex = -1; - - if ((dsResource.initialIndex >= 0) && (dsResource.initialIndex < dsResource.streamItems.length)) - { - actualIndex = dsResource.initialIndex; - } - - if (_autoSwitch) - { - checkRulesTimer.start(); - } - - setThrottleLimits(dsResource.streamItems.length - 1); - CONFIG::LOGGING - { - logger.debug("prepareForSwitching() - Starting with stream index " + actualIndex + " at " + Math.round(dsResource.streamItems[actualIndex].bitrate) + " kbps"); - } - metrics.currentIndex = actualIndex; - } - - private function initDSIFailedCounts():void - { - if (dsiFailedCounts != null) - { - dsiFailedCounts.length = 0; - dsiFailedCounts = null; - } - - dsiFailedCounts = new Vector.(); - for (var i:int = 0; i < dsResource.streamItems.length; i++) - { - dsiFailedCounts.push(0); - } - } - - private function incrementDSIFailedCount(index:int):void { - dsiFailedCounts[index]++; - - // Start the timer that clears the failed counts if one of them - // just went over the max failed count - if (dsiFailedCounts[index] > _maxUpSwitchesPerStream) { - if (clearFailedCountsTimer == null) { - clearFailedCountsTimer = new Timer(_clearFailedCountInterval, 1); - clearFailedCountsTimer.addEventListener(TimerEvent.TIMER, clearFailedCounts); - } - - clearFailedCountsTimer.start(); - } - } - - private function clearFailedCounts(event:TimerEvent):void { - clearFailedCountsTimer.removeEventListener(TimerEvent.TIMER, clearFailedCounts); - clearFailedCountsTimer = null; - initDSIFailedCounts(); - } - - private function setThrottleLimits(index:int):void { - connection.call("setBandwidthLimit", null, _bandwidthLimit, _bandwidthLimit); - } - - private var netStream:NetStream; - private var dsResource:DynamicStreamingResource; - private var switchingRules:Vector.; - private var metrics:NetStreamMetricsBase; - private var checkRulesTimer:Timer; - private var clearFailedCountsTimer:Timer; - private var actualIndex:int = -1; - private var _targetIndex:int = -1; - private var oldStreamName:String; - private var switching:Boolean; - private var _currentIndex:int; - private var lastTransitionIndex:int = -1; - private var connection:NetConnection; - private var dsiFailedCounts:Vector.; // This vector keeps track of the number of failures - // for each DynamicStreamingItem in the DynamicStreamingResource - private var failedDSI:Dictionary; - private var _bandwidthLimit:Number = 0; - private var prepared:Boolean; + if (!_autoSwitch) + { + if (index < 0 || index > maxAllowedIndex) + { + throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX)); + } + else + { + CONFIG::LOGGING + { + logger.debug("switchTo() - manually switching to index: " + index); + } + + if (actualIndex == -1) + { + prepareForSwitching(); + } + executeSwitch(index); + } + } + else + { + throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_STREAM_NOT_IN_MANUAL_MODE)); + } + } + + // Protected + // + + /** + * Override this method to provide additional decisioning around + * allowing automatic switches to occur. This method will be invoked + * just prior to a switch request. If false is returned, that switch + * request will not take place. + * + *

      By default, the implementation does the following:

      + *

      1) When a switch down occurs, the stream being switched from has its + * failed count incremented. If, when the switching rules are evaluated + * again, a rule suggests switching up, since the stream previously + * failed, it won't be tried again until a duration (30s) elapses. This + * provides a better user experience by preventing a situation where + * the switch up is attempted but then fails almost immediately.

      + *

      2) Once a stream item has 3 failures, there will be no more + * attempts to switch to it until an interval (5m) has expired. At the + * end of this interval, all failed counts are reset to zero.

      + * + * @param newIndex The new index to switch to. + **/ + protected function canAutoSwitchNow(newIndex:int):Boolean + { + // If this stream has failed, we don't want to try it again until + // the wait period has elapsed + if (dsiFailedCounts[newIndex] >= 1) + { + var current:int = getTimer(); + if (current - failedDSI[newIndex] < _waitDurationAfterDownSwitch) + { + CONFIG::LOGGING + { + logger.debug("canAutoSwitchNow() - ignoring switch request because index has " + dsiFailedCounts[newIndex]+" failure(s) and only "+ (current - failedDSI[newIndex])/1000 + " seconds have passed since the last failure."); + } + return false; + } + } + // If the requested index is currently locked out, then we don't + // allow the switch. + else if (dsiFailedCounts[newIndex] > _maxUpSwitchesPerStream) + { + return false; + } + + return true; + } + + /** + * The multiplier to apply to the maximum bandwidth for the client. The + * default is 140% of the highest bitrate stream. + **/ + protected final function get bandwidthLimit():Number + { + return _bandwidthLimit; + } + protected final function set bandwidthLimit(value:Number):void + { + _bandwidthLimit = value; + } + + /** + * Forces the evaluation of all the rules. + * + * @private + **/ + protected function doCheckRules():void + { + checkRules(null); + } + + // Internals + // + + /** + * Executes the switch to the specified index. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + private function executeSwitch(targetIndex:int):void + { + var nso:NetStreamPlayOptions = new NetStreamPlayOptions(); + + var playArgs:Object = NetStreamUtils.getPlayArgsForResource(dsResource); + + nso.start = playArgs.start; + nso.len = playArgs.len; + + nso.streamName = dsResource.streamItems[targetIndex].streamName; + // + // FM-925, it seems that the oldStreamName cannot contain parameters, + // therefore we must remove them + // + var sn:String = oldStreamName; + if (sn != null && sn.indexOf("?") >= 0) + { + nso.oldStreamName = sn.substr(0, sn.indexOf("?")); + } + else + { + nso.oldStreamName = oldStreamName; + } + + nso.transition = NetStreamPlayTransitions.SWITCH; + + CONFIG::LOGGING + { + logger.debug("executeSwitch() - Switching to index " + (targetIndex) + " at " + Math.round(dsResource.streamItems[targetIndex].bitrate) + " kbps"); + } + + switching = true; + + netStream.play2(nso); + + oldStreamName = dsResource.streamItems[targetIndex].streamName; + + if (targetIndex < actualIndex && _autoSwitch) + { + // This is a failure for the current stream, so let's tag it as such. + incrementDSIFailedCount(actualIndex); + + // Keep track of when it failed so we don't try it again for + // another failedItemWaitPeriod milliseconds to improve the + // user experience. + failedDSI[actualIndex] = getTimer(); + } + } + + /** + * Checks all the switching rules. If a switching rule returns -1, it is + * recommending no change. If a switching rule returns a number greater than + * -1 it is recommending a switch to that index. This method uses the lesser of + * all the recommended indices that are greater than -1. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + private function checkRules(event:TimerEvent):void + { + if (switchingRules == null || switching || dsResource == null) + { + return; + } + + var newIndex:int = int.MAX_VALUE; + + for (var i:int = 0; i < switchingRules.length; i++) + { + var n:int = switchingRules[i].getNewIndex(); + + if (n != -1 && n < newIndex) + { + newIndex = n; + } + } + + // if the rules recommended a new bitrate index + // then make sure we respect the maximum allowed index + if ( newIndex != -1 + && newIndex != int.MAX_VALUE + && newIndex != actualIndex + ) + { + newIndex = Math.min(newIndex, maxAllowedIndex); + } + + // if no change was recommended then make sure that + // the current index is still respecting the maximum + // allowed index + if ( + (newIndex == -1 || newIndex == int.MAX_VALUE) + && actualIndex > maxAllowedIndex + ) + { + newIndex = maxAllowedIndex; + } + + if ( newIndex != -1 + && newIndex != int.MAX_VALUE + && newIndex != actualIndex + && !switching + && newIndex <= maxAllowedIndex + ) + { + if (actualIndex == -1) + { + prepareForSwitching(); + } + if (canAutoSwitchNow(newIndex)) + { + CONFIG::LOGGING + { + logger.debug("checkRules() - Calling for switch to " + newIndex + " at " + dsResource.streamItems[newIndex].bitrate + " kbps"); + } + executeSwitch(newIndex); + } + } + } + + private function onNetStatus(event:NetStatusEvent):void + { + CONFIG::LOGGING + { + logger.debug("onNetStatus() - event.info.code=" + event.info.code); + } + + switch (event.info.code) + { + case NetStreamCodes.NETSTREAM_PLAY_START: + if (actualIndex == -1) + { + prepareForSwitching(); + } + else if (_autoSwitch && checkRulesTimer.running == false) + { + checkRulesTimer.start(); + } + break; + case NetStreamCodes.NETSTREAM_PLAY_TRANSITION: + actualIndex = dsResource.indexFromName(event.info.details); + if (actualIndex > -1) + { + switching = false; + metrics.currentIndex = actualIndex; + lastTransitionIndex = actualIndex; + } + break; + case NetStreamCodes.NETSTREAM_PLAY_FAILED: + switching = false; + break; + case NetStreamCodes.NETSTREAM_SEEK_NOTIFY: + switching = false; + if (lastTransitionIndex >= 0) + { + _currentIndex = lastTransitionIndex; + } + break; + case NetStreamCodes.NETSTREAM_PLAY_STOP: + checkRulesTimer.stop(); + CONFIG::LOGGING + { + logger.debug("onNetStatus() - Stopping rules since server has stopped sending data"); + } + break; + } + } + + private function onPlayStatus(info:Object):void + { + CONFIG::LOGGING + { + logger.debug("onPlayStatus() - info.code=" + info.code); + } + + switch (info.code) + { + case NetStreamCodes.NETSTREAM_PLAY_TRANSITION_COMPLETE: + if (lastTransitionIndex >= 0) + { + _currentIndex = lastTransitionIndex; + lastTransitionIndex = -1; + } + + CONFIG::LOGGING + { + logger.debug("onPlayStatus() - Transition complete to index: " + currentIndex + " at " + Math.round(dsResource.streamItems[currentIndex].bitrate) + " kbps"); + } + + break; + } + } + + /** + * Prepare the manager for switching. Note that this doesn't necessarily + * mean a switch is imminent. + **/ + private function prepareForSwitching():void + { + initDSIFailedCounts(); + + metrics.resource = dsResource; + + actualIndex = 0; + lastTransitionIndex = -1; + + if ((dsResource.initialIndex >= 0) && (dsResource.initialIndex < dsResource.streamItems.length)) + { + actualIndex = dsResource.initialIndex; + } + + if (_autoSwitch) + { + checkRulesTimer.start(); + } + + setThrottleLimits(dsResource.streamItems.length - 1); + CONFIG::LOGGING + { + logger.debug("prepareForSwitching() - Starting with stream index " + actualIndex + " at " + Math.round(dsResource.streamItems[actualIndex].bitrate) + " kbps"); + } + metrics.currentIndex = actualIndex; + } + + private function initDSIFailedCounts():void + { + if (dsiFailedCounts != null) + { + dsiFailedCounts.length = 0; + dsiFailedCounts = null; + } + + dsiFailedCounts = new Vector.(); + for (var i:int = 0; i < dsResource.streamItems.length; i++) + { + dsiFailedCounts.push(0); + } + } + + private function incrementDSIFailedCount(index:int):void + { + dsiFailedCounts[index]++; + + // Start the timer that clears the failed counts if one of them + // just went over the max failed count + if (dsiFailedCounts[index] > _maxUpSwitchesPerStream) + { + if (clearFailedCountsTimer == null) + { + clearFailedCountsTimer = new Timer(_clearFailedCountInterval, 1); + clearFailedCountsTimer.addEventListener(TimerEvent.TIMER, clearFailedCounts); + } + + clearFailedCountsTimer.start(); + } + } + + private function clearFailedCounts(event:TimerEvent):void + { + clearFailedCountsTimer.removeEventListener(TimerEvent.TIMER, clearFailedCounts); + clearFailedCountsTimer = null; + initDSIFailedCounts(); + } + + private function setThrottleLimits(index:int):void + { + connection.call("setBandwidthLimit", null, _bandwidthLimit, _bandwidthLimit); + } + + private var netStream:NetStream; + private var dsResource:DynamicStreamingResource; + private var switchingRules:Vector.; + private var metrics:NetStreamMetricsBase; + private var checkRulesTimer:Timer; + private var clearFailedCountsTimer:Timer; + private var actualIndex:int = -1; + private var oldStreamName:String; + private var switching:Boolean; + private var _currentIndex:int; + private var lastTransitionIndex:int = -1; + private var connection:NetConnection; + private var dsiFailedCounts:Vector.; // This vector keeps track of the number of failures + // for each DynamicStreamingItem in the DynamicStreamingResource + private var failedDSI:Dictionary; + private var _bandwidthLimit:Number = 0;; - //private static const RULE_CHECK_INTERVAL:Number = 500; // Switching rule check interval in milliseconds private var _ruleCheckInterval:Number = 500; //private static const DEFAULT_MAX_UP_SWITCHES_PER_STREAM_ITEM:int = 3; private var _maxUpSwitchesPerStream:int = 3; //private static const DEFAULT_WAIT_DURATION_AFTER_DOWN_SWITCH:int = 30000; - private var _waitDurationAfterDownSwitch:int = 30000; + private var _waitDurationAfterDownSwitch:int = 30000; //private static const DEFAULT_CLEAR_FAILED_COUNTS_INTERVAL:Number = 300000; // default of 5 minutes for clearing failed counts on stream items private var _clearFailedCountInterval:Number = 300000; - CONFIG::LOGGING - { - private static const logger:Logger = Log.getLogger("NetStreamSwitchManager"); - } - } + CONFIG::LOGGING + { + private static const logger:Logger = Log.getLogger("org.osmf.net.NetStreamSwitchManager"); + } + } } \ No newline at end of file diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitchManagerBase.as b/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitchManagerBase.as new file mode 100644 index 0000000..b742b0c --- /dev/null +++ b/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitchManagerBase.as @@ -0,0 +1,153 @@ +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.net +{ + import flash.events.EventDispatcher; + +/** + * NetStreamSwitchManagerBase is a base class for classes that need to + * manage transitions between multi-bitrate (MBR) streams. + * + *

      A NetStreamSwitchManagerBase can work in manual or auto mode. For + * the former, it will execute upon request the NetStream call that + * performs the switch. For the latter, it will execute the switch based + * on its own internal logic.

      + * + *

      A NetStreamSwitchManagerBase doesn't dispatch any events indicating + * state changes. The assumption is that a client will already be listening + * to events on the NetStream, so there's no need for duplicative events + * here.

      + * + *

      This is an abstract base class, clients must subclass it to implement + * their own switching logic.

      + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public class NetStreamSwitchManagerBase extends EventDispatcher + { + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function NetStreamSwitchManagerBase() + { + super(); + + _autoSwitch = true; + _maxAllowedIndex = int.MAX_VALUE; + } + + /** + * Indicates whether the switching manager should automatically + * switch between streams. The default is true. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get autoSwitch():Boolean + { + return _autoSwitch; + } + + public function set autoSwitch(value:Boolean):void + { + _autoSwitch = value; + } + + /** + * Returns the current stream index that is rendering on the client. + * Note this may differ from the last index requested if this property + * is queried after a switch has begun but before it has completed. + * + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get currentIndex():uint + { + // Subclasses must override. + return 0; + } + + //flowplayer addition - manually set the current index + public function set currentIndex(index:uint):void {} + + /** + * The highest stream index that the switching manager is + * allowed to switch to. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function get maxAllowedIndex():int + { + return _maxAllowedIndex; + } + + /** + * The highest stream index that the switching manager is + * allowed to switch to. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function set maxAllowedIndex(value:int):void + { + _maxAllowedIndex = value; + } + + /** + * Initiate a switch to the stream with the given index. + * Note: If the media is paused, switching will not take place until after play resumes. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function switchTo(index:int):void + { + // Subclasses must override. + } + + // Internals + // + + protected var _autoSwitch:Boolean; + protected var _maxAllowedIndex:int; + } +} \ No newline at end of file diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitcher.as b/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitcher.as new file mode 100644 index 0000000..ff1c96b --- /dev/null +++ b/plugins/bwcheck/src/actionscript/org/osmf/net/NetStreamSwitcher.as @@ -0,0 +1,330 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ +package org.osmf.net +{ + import flash.events.EventDispatcher; + import flash.events.NetStatusEvent; + import flash.net.NetStream; + import flash.net.NetStreamPlayOptions; + import flash.net.NetStreamPlayTransitions; + + import org.osmf.utils.OSMFStrings; + + CONFIG::LOGGING + { + import org.osmf.logging.Log; + import org.osmf.logging.Logger; + } + + [Event(name="runAlgorithm", type="org.osmf.net.abr.ABREvent")] + + /** + * Controller of the NetStream regarding switching. Intended to be used by an adaptive bitrate switch manager + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public class NetStreamSwitcher extends EventDispatcher + { + /** + * Constructor. + * + * @param The NetStream object to be controlled + * @param dsResource The dynamic streaming resource + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function NetStreamSwitcher(netStream:NetStream, dsResource:DynamicStreamingResource) + { + if (netStream == null) + { + throw new ArgumentError("Invalid netStream"); + } + + if (dsResource == null) + { + throw new ArgumentError("Invalid dynamic streaming resource"); + } + + this.netStream = netStream; + this.dsResource = dsResource; + + _currentIndex = Math.max(0, dsResource.initialIndex); + + netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); + + // Make sure we get onPlayStatus first (by setting a higher priority) + // so that we can expose a consistent state to clients. + var client:NetClient = netStream.client as NetClient; + if (client != null) + { + NetClient(netStream.client).addHandler(NetStreamCodes.ON_PLAY_STATUS, onPlayStatus, int.MAX_VALUE); + } + else + { + throw new Error("The netStream does not have a NetClient associated."); + } + } + + /** + * Index of the quality level currently being played + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function get currentIndex():uint + { + return _currentIndex; + } + + /** + * The index of the quality level currently being downloaded + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function get actualIndex():int + { + return _actualIndex == -1 ? _currentIndex : _actualIndex; + } + + /** + * Flag indicating whether the NetStreamSwitcher is currently in a switching process.
      + * This is set to true when a switch is initiated and is set back to false when the NetStream + * reports having initiated the transition (NetStatusEvent.TRANSITION). + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function get switching():Boolean + { + return _switching; + } + + /** + * Initiates a switch to the specified index + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function switchTo(index:int):void + { + if (index < 0) + { + throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX)); + } + + if (_actualIndex == -1) + { + prepareForSwitching(); + } + executeSwitch(index); + } + + //flowplayer addition - make index publically settable. + public function set currentIndex(value:uint):void + { + setCurrentIndex(value); + } + + private function setCurrentIndex(value:uint):void + { + var oldValue:uint = _currentIndex; + _currentIndex = value; + } + + private function setActualIndex(value:int):void + { + var oldValue:int = _actualIndex; + _actualIndex = value; + } + + /** + * Executes the switch to the specified index. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + private function executeSwitch(targetIndex:int):void + { + var nso:NetStreamPlayOptions = new NetStreamPlayOptions(); + + var playArgs:Object = NetStreamUtils.getPlayArgsForResource(dsResource); + + nso.start = playArgs.start; + nso.len = playArgs.len; + + nso.streamName = dsResource.streamItems[targetIndex].streamName; + + // FM-925, it seems that the oldStreamName cannot contain parameters, + // therefore we must remove them + var sn:String = oldStreamName; + if (sn != null && sn.indexOf("?") >= 0) + { + nso.oldStreamName = sn.substr(0, sn.indexOf("?")); + } + else + { + nso.oldStreamName = oldStreamName; + } + + nso.transition = NetStreamPlayTransitions.SWITCH; + + CONFIG::LOGGING + { + logger.debug("executeSwitch() - Switching to index " + (targetIndex) + " at " + Math.round(dsResource.streamItems[targetIndex].bitrate) + " kbps"); + } + + _switching = true; + + netStream.play2(nso); + + oldStreamName = dsResource.streamItems[targetIndex].streamName; + } + + /** + * Prepare the manager for switching. Note that this doesn't necessarily + * mean a switch is imminent. + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + private function prepareForSwitching():void + { + _actualIndex = 0; + // lastTransitionIndex = -1; + + if ((dsResource.initialIndex >= 0) && (dsResource.initialIndex < dsResource.streamItems.length)) + { + _actualIndex = dsResource.initialIndex; + } + + CONFIG::LOGGING + { + logger.debug("prepareForSwitching() - Starting with stream index " + _actualIndex + " at " + Math.round(dsResource.streamItems[_actualIndex].bitrate) + " kbps"); + } + } + + private function onNetStatus(event:NetStatusEvent):void + { + CONFIG::LOGGING + { + logger.debug("onNetStatus() - event.info.code = " + event.info.code); + } + + switch (event.info.code) + { + case NetStreamCodes.NETSTREAM_PLAY_START: + if (_actualIndex == -1) + { + prepareForSwitching(); + } + break; + case NetStreamCodes.NETSTREAM_PLAY_TRANSITION: + // Issue: http://bugs.adobe.com/jira/browse/FM-1474 + // We need to check whether this was a video transition, + // because the same event is dispatched in case of an audio transition. + // We do this by checking whether the url the transition + // was initated to is indeed a video stream + var index:int = dsResource.indexFromName(event.info.details); + if (index >= 0) + { + setActualIndex(index); + + CONFIG::LOGGING + { + logger.debug("event.info.details (index) = " + index); + } + + if (_actualIndex > -1) + { + _switching = false; + } + } + break; + case NetStreamCodes.NETSTREAM_PLAY_FAILED: + _switching = false; + break; + case NetStreamCodes.NETSTREAM_SEEK_NOTIFY: + _switching = false; + setCurrentIndex(actualIndex); + break; + case NetStreamCodes.NETSTREAM_PLAY_STOP: + break; + } + } + + private function onPlayStatus(info:Object):void + { + switch (info.code) + { + case NetStreamCodes.NETSTREAM_PLAY_TRANSITION_COMPLETE: + // Issue: http://bugs.adobe.com/jira/browse/FM-1474 + // We need to check whether this was a video transition, + // because the same event is dispatched in case of an audio transition. + // We do this by checking whether the url the transition + // completed to is indeed a video stream + var index:int = dsResource.indexFromName(info.details); + + if (index >= 0) + { + setCurrentIndex(index); + + CONFIG::LOGGING + { + logger.debug("onPlayStatus() - Transition complete to index: " + index + " at " + Math.round(dsResource.streamItems[index].bitrate) + " kbps"); + } + } + + break; + } + } + + private var oldStreamName:String; + private var netStream:NetStream = null; + private var dsResource:DynamicStreamingResource = null; + private var _currentIndex:uint = 0; + private var _actualIndex:int = -1; + private var _switching:Boolean; + + CONFIG::LOGGING + { + private static const logger:Logger = Log.getLogger("org.osmf.net.NetStreamSwitcher"); + } + } +} \ No newline at end of file diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/RuleSwitchManagerBase.as b/plugins/bwcheck/src/actionscript/org/osmf/net/RuleSwitchManagerBase.as new file mode 100644 index 0000000..15741a4 --- /dev/null +++ b/plugins/bwcheck/src/actionscript/org/osmf/net/RuleSwitchManagerBase.as @@ -0,0 +1,293 @@ +/***************************************************** + * + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + ***************************************************** + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * + * The Initial Developer of the Original Code is Adobe Systems Incorporated. + * Portions created by Adobe Systems Incorporated are Copyright (C) 2011 Adobe Systems + * Incorporated. All Rights Reserved. + * + *****************************************************/ + +/* +AdobePatentID="2278US01" +*/ + +package org.osmf.net +{ + import flash.errors.IllegalOperationError; + import flash.events.EventDispatcher; + + import org.osmf.events.HTTPStreamingEvent; + import org.osmf.net.metrics.MetricRepository; + import org.osmf.net.rules.Recommendation; + import org.osmf.net.rules.RuleBase; + import org.osmf.utils.OSMFStrings; + + CONFIG::LOGGING + { + import org.osmf.logging.Log; + import org.osmf.logging.Logger; + } + + /** + *

      SwitchManger manages the Adaptive Bitrate experience.
      + * It is responsible with putting all the required components together.

      + * + * @see org.osmf.net.abr.MetricBase + * @see org.osmf.net.abr.RuleBase + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public class RuleSwitchManagerBase extends NetStreamSwitchManagerBase + { + /** + * Constructor. + * + * @param notifier An object that dispatches the HTTPStreamingEvent.RUN_ALGORITHM event + * @param switcher The NetStreamSwitcher to use for switching + * @param metricRepository The repository responsible with providing metrics + * @param emergencyRules Array of rules to be used in the algorithm. + * An emergency rule can only recommend lower bitrates than the current one. + * @param autoSwitch Flag deciding whether autoSwitch should be enabled + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function RuleSwitchManagerBase + ( notifier:EventDispatcher + , switcher:NetStreamSwitcher + , metricRepository:MetricRepository + , emergencyRules:Vector. = null + , autoSwitch:Boolean = true + ) + { + super(); + + if (notifier == null) + { + throw new ArgumentError("Invalid netStream"); + } + + if (switcher == null) + { + throw new ArgumentError("Invalid switcher"); + } + + if (metricRepository == null) + { + throw new ArgumentError("Invalid metric repository"); + } + + this.notifier = notifier; + this.switcher = switcher; + _metricRepository = metricRepository; + + if (emergencyRules != null) + { + _emergencyRules = emergencyRules.slice(); + } + + this.autoSwitch = autoSwitch; + } + + override public function set autoSwitch(value:Boolean):void + { + super.autoSwitch = value; + + if (value) + { + notifier.addEventListener(HTTPStreamingEvent.RUN_ALGORITHM, onRunAlgorithm); + } + else + { + notifier.removeEventListener(HTTPStreamingEvent.RUN_ALGORITHM, onRunAlgorithm); + } + } + + /** + * The index of the currently downloading quality level + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function get actualIndex():int + { + return switcher.actualIndex; + } + + /** + * The metric repository responsible with providing the metrics + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function get metricRepository():MetricRepository + { + return _metricRepository; + } + + /** + * Array of normal rules to be used in the algorithm. + * An emergency rule can only recommend lower bitrates than the current one. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function get emergencyRules():Vector. + { + return _emergencyRules; + } + + /** + * Computes the necessary rules and metrics and determines the index to switch to. + * The index must be a valid one (it can be higher than maxAllowedIndex, but it should be + * a real index that is available) + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function getNewIndex():uint + { + throw new IllegalOperationError("The getNewIndex() function must be overriden by the subclass."); + } + + /** + * Returns an index that satisfies the maxBitrate constraint + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 2.0 + */ + public function getNewEmergencyIndex(maxBitrate:Number):uint + { + throw new IllegalOperationError("The getNewEmergencyIndex() function must be overriden by the subclass."); + } + + override public function get currentIndex():uint + { + return switcher.currentIndex; + } + + //flowplayer addition - set the current index + override public function set currentIndex(index:uint):void { + switcher.currentIndex = index; + } + + override public function switchTo(index:int):void + { + if (!_autoSwitch) + { + if (index < 0 || index > maxAllowedIndex) + { + throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX)); + } + else + { + CONFIG::LOGGING + { + logger.debug("switchTo() - manually switching to index: " + index); + } + + switcher.switchTo(index); + } + } + else + { + throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_STREAM_NOT_IN_MANUAL_MODE)); + } + } + + private function onRunAlgorithm(event:HTTPStreamingEvent):void + { + var minEmergencyBitrate:Number = Number.POSITIVE_INFINITY; + + for each (var rule:RuleBase in _emergencyRules) + { + var rec:Recommendation = rule.getRecommendation(); + + // Only consider rules that are sure + if (rec.confidence == 1) + { + minEmergencyBitrate = rec.bitrate; + } + } + + var newIndex:uint = 0; + + if (minEmergencyBitrate < Number.POSITIVE_INFINITY) + { + newIndex = getNewEmergencyIndex(minEmergencyBitrate); + } + else + { + newIndex = getNewIndex(); + } + + // if the rules recommended a new bitrate index + // then make sure we respect the maximum allowed index + if (newIndex != switcher.actualIndex) + { + newIndex = Math.min(newIndex, maxAllowedIndex); + } + // if no change was recommended then make sure that + // the current index is still respecting the maximum + // allowed index + else + { + if (switcher.actualIndex > maxAllowedIndex) + { + newIndex = maxAllowedIndex; + } + } + + // The newIndex may have been changed due to the previous conditions + // Check that it's still different than the actual index and that + // the switcher isn't switching at the moment + if (newIndex != switcher.actualIndex && !switcher.switching) + { + CONFIG::LOGGING + { + logger.info("Automatically switching to new index: " + newIndex); + } + + switcher.switchTo(newIndex); + } + } + + private var _metricRepository:MetricRepository; + private var _emergencyRules:Vector. = null; + private var switcher:NetStreamSwitcher; + private var notifier:EventDispatcher; + + CONFIG::LOGGING + { + private static const logger:Logger = Log.getLogger("org.osmf.net.RuleSwitchManagerBase"); + } + } +} \ No newline at end of file diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/InsufficientBandwidthRule.as b/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/InsufficientBandwidthRule.as deleted file mode 100644 index 3e0ffbe..0000000 --- a/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/InsufficientBandwidthRule.as +++ /dev/null @@ -1,132 +0,0 @@ -/***************************************************** -* -* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. -* -***************************************************** -* The contents of this file are subject to the Mozilla Public License -* Version 1.1 (the "License"); you may not use this file except in -* compliance with the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" -* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -* License for the specific language governing rights and limitations -* under the License. -* -* -* The Initial Developer of the Original Code is Akamai Technologies, Inc. -* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai -* Technologies, Inc. All Rights Reserved. -* -*****************************************************/ -package org.osmf.net.rtmpstreaming -{ - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } - - import org.osmf.net.SwitchingRuleBase; - import org.osmf.utils.OSMFStrings; - - /** - * InsufficientBandwidthRule is a switching rule that switches down when - * the bandwidth is insufficient for the current stream. - * - *

      When comparing stream bitrates to available bandwidth, the class uses - * a "bitrate multiplier" against which the stream bitrate is multiplied.

      - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public class InsufficientBandwidthRule extends SwitchingRuleBase - { - /** - * Constructor. - * - * @param metrics The metrics provider used by this rule to determine - * whether to switch. - * @param bitrateMultiplier A multiplier that is used when the stream - * bitrate is compared against available bandwidth. The stream bitrate - * is multiplied by this amount. The default is 1.15. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function InsufficientBandwidthRule(metrics:RTMPNetStreamMetrics, bitrateMultiplier:Number=1.15) - { - super(metrics); - - this.bitrateMultiplier = bitrateMultiplier; - } - - /** - * @private - */ - override public function getNewIndex():int - { - var newIndex:int = -1; - var moreDetail:String; - - // Wait until the metrics class can calculate a stable average bandwidth - if (rtmpMetrics.averageMaxBytesPerSecond != 0) - { - // See if we need to switch down based on average max bytes per second - for (var i:int = rtmpMetrics.currentIndex; i >= 0; i--) - { - //debug("bw: " + (rtmpMetrics.averageMaxBytesPerSecond * 8 / 1024) + " multiplied: " + (rtmpMetrics.resource.streamItems[i].bitrate * bitrateMultiplier)); - if (rtmpMetrics.averageMaxBytesPerSecond * 8 / 1024 > (rtmpMetrics.resource.streamItems[i].bitrate * bitrateMultiplier)) - { - newIndex = i; - break; - } - } - - newIndex = (newIndex == rtmpMetrics.currentIndex) ? -1 : newIndex; - - CONFIG::LOGGING - { - if ((newIndex != -1) && (newIndex < rtmpMetrics.currentIndex)) - { - debug("Average bandwidth of " + Math.round(rtmpMetrics.averageMaxBytesPerSecond * 8 / 1024) + " < " + bitrateMultiplier + " * rendition bitrate"); - } - } - } - - CONFIG::LOGGING - { - if (newIndex != -1) - { - debug("getNewIndex() - about to return: " + newIndex + ", detail=" + moreDetail); - } - } - - return newIndex; - } - - private function get rtmpMetrics():RTMPNetStreamMetrics - { - return metrics as RTMPNetStreamMetrics; - } - - CONFIG::LOGGING - { - private function debug(s:String):void - { - logger.debug(s); - } - } - - private var bitrateMultiplier:Number; - - CONFIG::LOGGING - { - private static const logger:Logger = Log.getLogger("org.osmf.net.rtmpstreaming.InsufficientBandwidthRule"); - } - } -} diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/InsufficientBufferRule.as b/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/InsufficientBufferRule.as new file mode 100644 index 0000000..e856a60 --- /dev/null +++ b/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/InsufficientBufferRule.as @@ -0,0 +1,145 @@ +/***************************************************** +* +* Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Akamai Technologies, Inc. +* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai +* Technologies, Inc. All Rights Reserved. +* +*****************************************************/ +package org.osmf.net.rtmpstreaming +{ + import flash.events.NetStatusEvent; + + import org.osmf.net.NetStreamCodes; + import org.osmf.net.SwitchingRuleBase; + + CONFIG::LOGGING + { + import org.osmf.logging.Log; + import org.osmf.logging.Logger; + } + +/** + * InsufficientBufferRule is a switching rule that switches down when + * the buffer has insufficient data. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public class InsufficientBufferRule extends SwitchingRuleBase + { + /** + * Constructor. + * + * @param metrics The metrics provider used by this rule to determine + * whether to switch. + * @param minBufferLength The minimum buffer length that must be + * maintained before the rule suggests a switch down. The default + * value is 2 seconds. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public function InsufficientBufferRule(metrics:RTMPNetStreamMetrics, minBufferLength:Number=2) + { + super(metrics); + + _panic = false; + this.minBufferLength = minBufferLength; + metrics.netStream.addEventListener(NetStatusEvent.NET_STATUS, monitorNetStatus, false, 0, true); + } + + /** + * @private + */ + override public function getNewIndex():int + { + var newIndex:int = -1; + + if (_panic || (rtmpMetrics.netStream.bufferLength < minBufferLength && rtmpMetrics.netStream.bufferLength > rtmpMetrics.netStream.bufferTime)) + { + CONFIG::LOGGING + { + if (!_panic) + { + debug("Buffer of " + Math.round(rtmpMetrics.netStream.bufferLength) + " < " + minBufferLength + " seconds"); + } + } + + //#127 possible fix for rtmp buffer rule. Make it reduce back an index rather than drop to the lowest index. + newIndex = rtmpMetrics.currentIndex > 0 ? rtmpMetrics.currentIndex-- : 0; + //newIndex = 0; + } + + CONFIG::LOGGING + { + if (newIndex != -1) + { + debug("getNewIndex() - about to return: " + newIndex + ", detail=" + _moreDetail); + } + } + + return newIndex; + } + + private function monitorNetStatus(e:NetStatusEvent):void + { + switch (e.info.code) + { + case NetStreamCodes.NETSTREAM_BUFFER_FULL: + _panic = false; + break; + case NetStreamCodes.NETSTREAM_BUFFER_EMPTY: + if (Math.round(rtmpMetrics.netStream.time) != 0) + { + _panic = true; + _moreDetail = "Buffer was empty"; + } + break; + case NetStreamCodes.NETSTREAM_PLAY_INSUFFICIENTBW: + _panic = true; + _moreDetail = "Stream had insufficient bandwidth"; + break; + } + } + + private function get rtmpMetrics():RTMPNetStreamMetrics + { + return metrics as RTMPNetStreamMetrics; + } + + CONFIG::LOGGING + { + private function debug(s:String):void + { + logger.debug(s); + } + } + + private var _panic:Boolean; + private var _moreDetail:String; + private var minBufferLength:Number; + + CONFIG::LOGGING + { + private static const logger:Logger = Log.getLogger("org.osmf.net.rtmpstreaming.InsufficientBufferRule"); + } + } +} diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/RTMPNetStreamMetrics.as b/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/RTMPNetStreamMetrics.as deleted file mode 100644 index 8b49003..0000000 --- a/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/RTMPNetStreamMetrics.as +++ /dev/null @@ -1,124 +0,0 @@ -/***************************************************** - * - * Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. - * - ***************************************************** - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * - * The Initial Developer of the Original Code is Adobe Systems Incorporated. - * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems - * Incorporated. All Rights Reserved. - * - *****************************************************/ -package org.osmf.net.rtmpstreaming { - import flash.events.TimerEvent; - import flash.net.NetStream; - - import org.osmf.net.NetStreamMetricsBase; - import org.osmf.net.StreamType; - - CONFIG::LOGGING - { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } - - /** - * RTMPNetStreamMetrics is a metrics provider for RTMP-based NetStreams. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public class RTMPNetStreamMetrics extends NetStreamMetricsBase { - /** - * Constructor. - * - * @param netStream The NetStream to provide metrics for. - **/ - public function RTMPNetStreamMetrics(netStream:NetStream) { - super(netStream); - - _averageMaxBytesPerSecondArray = new Array(); - } - - /** - * The average max bytes per second value, calculated based on a - * recent set of samples. - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion OSMF 1.0 - */ - public function get averageMaxBytesPerSecond():Number { - return _averageMaxBytesPerSecond; - } - - /** - * @private - **/ - override protected function calculateMetrics():void { - super.calculateMetrics(); - - try { - // Average maxBytesPerSecond - var maxBytesPerSecond:Number = netStream.info.maxBytesPerSecond; - _averageMaxBytesPerSecondArray.unshift(maxBytesPerSecond); - if (_averageMaxBytesPerSecondArray.length > DEFAULT_AVG_MAX_BYTES_SAMPLE_SIZE) { - _averageMaxBytesPerSecondArray.pop(); - } - var totalMaxBytesPerSecond:Number = 0; - var peakMaxBytesPerSecond:Number = 0; - - for (var b:uint = 0; b < _averageMaxBytesPerSecondArray.length; b++) { - totalMaxBytesPerSecond += _averageMaxBytesPerSecondArray[b]; - peakMaxBytesPerSecond = _averageMaxBytesPerSecondArray[b] > peakMaxBytesPerSecond ? _averageMaxBytesPerSecondArray[b] : peakMaxBytesPerSecond; - } - - // Flash player can have problems attempting to accurately estimate - // max bytes available with live streams. The server will buffer the - // content and then dump it quickly to the client. The client sees - // this as an oscillating series of maxBytesPerSecond measurements, - // where the peak roughly corresponds to the true estimate of max - // bandwidth available. When isLive is true, we optimize the estimated - // averageMaxBytesPerSecond. - _averageMaxBytesPerSecond = _averageMaxBytesPerSecondArray.length < DEFAULT_AVG_MAX_BYTES_SAMPLE_SIZE ? 0 : isLive ? peakMaxBytesPerSecond : totalMaxBytesPerSecond / _averageMaxBytesPerSecondArray.length; - } - catch (error:Error) { - CONFIG::LOGGING - { - logger.debug(".calculateMetrics() - " + error); - } - throw(error); - } - } - - // Internals - // - - private function get isLive():Boolean { - return resource && resource.streamType == StreamType.LIVE; - } - - private var _averageMaxBytesPerSecondArray:Array; - private var _averageMaxBytesPerSecond:Number; - - private static const DEFAULT_AVG_MAX_BYTES_SAMPLE_SIZE:Number = 50; - - CONFIG::LOGGING - { - private static const logger:Logger = Log.getLogger("org.osmf.net.rtmpstreaming.RTMPNetStreamMetrics"); - } - } -} \ No newline at end of file diff --git a/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/SufficientBandwidthRule.as b/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/SufficientBandwidthRule.as index 3e8d33e..5f67721 100644 --- a/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/SufficientBandwidthRule.as +++ b/plugins/bwcheck/src/actionscript/org/osmf/net/rtmpstreaming/SufficientBandwidthRule.as @@ -21,13 +21,13 @@ *****************************************************/ package org.osmf.net.rtmpstreaming { - import org.osmf.net.SwitchingRuleBase; +import org.osmf.net.SwitchingRuleBase; - CONFIG::LOGGING +CONFIG::LOGGING { - import org.osmf.logging.Logger; - import org.osmf.logging.Log; - } + import org.osmf.logging.Log; + import org.osmf.logging.Logger; +} /** * SufficientBandwidthRule is a switching rule that switches up when the @@ -48,11 +48,11 @@ package org.osmf.net.rtmpstreaming **/ public function SufficientBandwidthRule(metrics:RTMPNetStreamMetrics, bandwidthSafetyMultiplier:Number = 1.15, minDroppedFrames:Number = 2) { - super(metrics); - - _bandwidthSafetyMultiplier = bandwidthSafetyMultiplier; - _minDroppedFrames = minDroppedFrames; + //flowplayer addition - make bandwidth rule settings configurable + this.bandwidthSafetyMultiplier = bandwidthSafetyMultiplier; + this.minDroppedFrames = minDroppedFrames; + super(metrics); } /** @@ -69,17 +69,11 @@ package org.osmf.net.rtmpstreaming // First find the preferred bitrate level we should be at by finding // the highest profile that can play, given the current average max // bytes per second. - for (var i:int = rtmpMetrics.resource.streamItems.length - 1; i >= 0; i--) + for (var i:int = rtmpMetrics.resource.streamItems.length - 1; i >= 0; i--) { - - //debug("bandwidth: " + rtmpMetrics.averageMaxBytesPerSecond * 8 / 1024 + " multiplied: " + (rtmpMetrics.resource.streamItems[i].bitrate * _bandwidthSafetyMultiplier) + " bitrate: " + rtmpMetrics.resource.streamItems[i].bitrate); - - if (rtmpMetrics.averageMaxBytesPerSecond * 8 / 1024 > (rtmpMetrics.resource.streamItems[i].bitrate * _bandwidthSafetyMultiplier)) + if (rtmpMetrics.averageMaxBytesPerSecond * 8 / 1024 > (rtmpMetrics.resource.streamItems[i].bitrate * this.bandwidthSafetyMultiplier)) { - - newIndex = i; - //debug("bandwidth is greater than bitrate index " + newIndex); - + newIndex = i; break; } } @@ -90,13 +84,13 @@ package org.osmf.net.rtmpstreaming { // We switch up only if conditions are perfect - no framedrops and // a stable buffer. - newIndex = (rtmpMetrics.droppedFPS < _minDroppedFrames && rtmpMetrics.netStream.bufferLength > rtmpMetrics.netStream.bufferTime) ? newIndex : -1; + newIndex = (rtmpMetrics.droppedFPS < this.minDroppedFrames && rtmpMetrics.netStream.bufferLength > rtmpMetrics.netStream.bufferTime) ? newIndex : -1; CONFIG::LOGGING { if (newIndex != -1) { - debug("Move up since avg dropped FPS " + Math.round(rtmpMetrics.droppedFPS) + " < " + _minDroppedFrames + " and bufferLength > " + rtmpMetrics.netStream.bufferTime); + debug("Move up since avg dropped FPS " + Math.round(rtmpMetrics.droppedFPS) + " < " + this.minDroppedFrames + " and bufferLength > " + rtmpMetrics.netStream.bufferTime); } } } @@ -129,11 +123,9 @@ package org.osmf.net.rtmpstreaming logger.debug(s); } } - - //private static const BANDWIDTH_SAFETY_MULTIPLE:Number = 1.15; - //private static const MIN_DROPPED_FPS:int = 2; - private var _bandwidthSafetyMultiplier:Number = 1.15; - private var _minDroppedFrames:Number = 2; + + private var bandwidthSafetyMultiplier:Number = 1.15; + private var minDroppedFrames:Number = 2; CONFIG::LOGGING { diff --git a/plugins/bwcheck/src/flash/hd_buttons.fla b/plugins/bwcheck/src/flash/hd_buttons.fla deleted file mode 100644 index bd69b45..0000000 Binary files a/plugins/bwcheck/src/flash/hd_buttons.fla and /dev/null differ diff --git a/plugins/bwcheck/src/flash/hd_buttons.swc b/plugins/bwcheck/src/flash/hd_buttons.swc deleted file mode 100644 index 682fb77..0000000 Binary files a/plugins/bwcheck/src/flash/hd_buttons.swc and /dev/null differ diff --git a/plugins/bwcheck/src/flash/hd_buttons.swf b/plugins/bwcheck/src/flash/hd_buttons.swf deleted file mode 100644 index ef019a9..0000000 Binary files a/plugins/bwcheck/src/flash/hd_buttons.swf and /dev/null differ diff --git a/plugins/captions/README.txt b/plugins/captions/README.txt index e856589..0893eab 100644 --- a/plugins/captions/README.txt +++ b/plugins/captions/README.txt @@ -1,5 +1,12 @@ Version history: +3.2.10 +------ +- Added external methods showButton() and hideButton() that can be used for the CC button. +- Changed default Timed Text XML namespace to be http://www.w3.org/ns/ttml This can be overridden using a clip + specific property 'ttNamespace'. The namespace of the old spec was http://www.w3.org/2006/10/ttaf1 Issue #35 + + 3.2.9 ----- - #19, loadCaptions() had disappeared somewhere, now works again diff --git a/plugins/captions/build.properties b/plugins/captions/build.properties index 8961a4f..a0c5d7b 100644 --- a/plugins/captions/build.properties +++ b/plugins/captions/build.properties @@ -1,2 +1,2 @@ devkit-dir=../../lib/devkit -version=3.2.9 \ No newline at end of file +version=3.2.10 \ No newline at end of file diff --git a/plugins/captions/build.xml b/plugins/captions/build.xml index aaec264..e3234c1 100644 --- a/plugins/captions/build.xml +++ b/plugins/captions/build.xml @@ -3,12 +3,15 @@ - - + + + + + diff --git a/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionLoader.as b/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionLoader.as index a911efe..da4a3bf 100644 --- a/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionLoader.as +++ b/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionLoader.as @@ -167,8 +167,7 @@ package org.flowplayer.captions { parser = new JSONParser(_config.template); } else if (parserType == "tt") { - parser = new TTXTParser(_config.template); - TTXTParser(parser).simpleFormatting = _config.simpleFormatting; + parser = new TTXTParser(_config.template, clip.getCustomProperty("ttNamespace") as String || "http://www.w3.org/ns/ttml", _config.simpleFormatting); } else { throw new Error("Unrecognized captions file extension"); diff --git a/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionPlugin.as b/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionPlugin.as index de788bf..b439726 100644 --- a/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionPlugin.as +++ b/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionPlugin.as @@ -279,5 +279,15 @@ package org.flowplayer.captions { internal function set config(value:Config):void { _config = value; } + + [External] + public function showButton():void { + _captionView.showButton(); + } + + [External] + public function hideButton():void { + _captionView.hideButton(); + } } } diff --git a/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionViewDelegate.as b/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionViewDelegate.as index f3652ee..14fcb6b 100644 --- a/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionViewDelegate.as +++ b/plugins/captions/src/actionscript/org/flowplayer/captions/CaptionViewDelegate.as @@ -152,5 +152,13 @@ package org.flowplayer.captions { internal function css(styleObj:Object):void { _view.css(styleObj); } + + internal function hideButton():void { + _player.panel.removeChild(_button); + } + + internal function showButton():void { + _player.addToPanel(_button, _config.button); + } } } diff --git a/plugins/captions/src/actionscript/org/flowplayer/captions/Config.as b/plugins/captions/src/actionscript/org/flowplayer/captions/Config.as index 91de2c2..bfc047b 100644 --- a/plugins/captions/src/actionscript/org/flowplayer/captions/Config.as +++ b/plugins/captions/src/actionscript/org/flowplayer/captions/Config.as @@ -83,8 +83,7 @@ package org.flowplayer.captions delete defaults[prop1]; } } - - } + } } diff --git a/plugins/captions/src/actionscript/org/flowplayer/captions/parsers/TTXTParser.as b/plugins/captions/src/actionscript/org/flowplayer/captions/parsers/TTXTParser.as index a8cb562..922b15c 100644 --- a/plugins/captions/src/actionscript/org/flowplayer/captions/parsers/TTXTParser.as +++ b/plugins/captions/src/actionscript/org/flowplayer/captions/parsers/TTXTParser.as @@ -14,25 +14,21 @@ package org.flowplayer.captions.parsers { import org.flowplayer.view.FlowStyleSheet; public class TTXTParser extends AbstractCaptionParser { - private var _tt:Namespace = new Namespace("http://www.w3.org/2006/10/ttaf1"); - private var _bodyStyle:String; private var _simpleFormatting:Boolean = false; private var _cueRow:int = 0; internal static const SIMPLE_FORMATTING_PROPS:Array = ["fontStyle", "fontWeight", "textAlign"]; protected var log:Log = new Log(this); + private var _namespace:Namespace; - public function TTXTParser(textTemplate:String) { + public function TTXTParser(textTemplate:String, xmlNamespace:String, simpleFormatting:Boolean) { super(textTemplate); - default xml namespace = _tt; - } - public function get simpleFormatting():Boolean { - return _simpleFormatting; - } + _namespace = new Namespace(xmlNamespace); + default xml namespace = _namespace; - public function set simpleFormatting(simpleFormatting:Boolean):void { + log.debug("using namespace " + xmlNamespace); _simpleFormatting = simpleFormatting; } diff --git a/plugins/cloudfrontsignedurl/build.xml b/plugins/cloudfrontsignedurl/build.xml new file mode 100644 index 0000000..a566d75 --- /dev/null +++ b/plugins/cloudfrontsignedurl/build.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/CloudFrontSignedUrl.as b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/CloudFrontSignedUrl.as new file mode 100644 index 0000000..9123169 --- /dev/null +++ b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/CloudFrontSignedUrl.as @@ -0,0 +1,165 @@ +/* + * This file is part of Flowplayer, http://flowplayer.org + * + * By: Thomas Dubois, thomas _at_ flowplayer.org + * Copyright (c) 2010 Flowplayer Oy + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + */ + +package org.flowplayer.cloudfrontsignedurl { + import flash.events.NetStatusEvent; + + import org.flowplayer.controller.ClipURLResolver; + import org.flowplayer.controller.StreamProvider; + + import org.flowplayer.model.Clip; + import org.flowplayer.model.Plugin; + import org.flowplayer.model.PluginModel; + import org.flowplayer.model.PluginError; + + import org.flowplayer.util.Log; + import org.flowplayer.util.URLUtil; + import com.adobe.utils.StringUtil; + + import org.flowplayer.util.PropertyBinder; + import org.flowplayer.view.Flowplayer; + + public class CloudFrontSignedUrl implements ClipURLResolver, Plugin { + private const log:Log = new Log(this); + private var _model:PluginModel; + private var _config:Config; + private var _player:Flowplayer; + private var _signedUrlGenerator:SignedUrlGenerator; + + /* + * URL resolving is used for HTTP + */ + public function resolve(provider:StreamProvider, clip:Clip, successListener:Function):void { + var signedUrl:String = _getUrl(clip); + clip.setResolvedUrl(this, signedUrl); + successListener(clip); + } + + private function _getUrl(clip:Clip):String { + + var url:String = clip.getPreviousResolvedUrl(this); + + var isRTMPStream:Boolean = url.toLowerCase().indexOf('mp4:') == 0; + if ( isRTMPStream ) + url = url.substr(4); + + var expires:Number = Math.round((new Date()).getTime() / 1000 + _config.timeToLive); + + var signedUrl:String = _signedUrlGenerator.signUrl(url, expires); + if ( isRTMPStream ) + signedUrl = 'mp4:'+ signedUrl; + + return signedUrl; + } + + private function _checkDomains():Boolean { + if ( _config.domains.length == 0 ) + return true; + + var url:String = URLUtil.pageUrl; + + if ( url == null ) + return false; + + if ( URLUtil.localDomain(url) ) + return true; + + + var domain:String = _getDomain(); + domain = domain.toLowerCase(); + var strippedDomain:String = _stripSubdomain(domain); + + log.debug("Found domain "+ domain + " "+ strippedDomain); + + return _config.domains.indexOf(domain) != -1 || _config.domains.indexOf(strippedDomain) != -1; + } + + private function _getDomain():String { + var url:String = URLUtil.pageUrl; + var domain:String = url.substr(url.indexOf('://')+3); + if ( domain.indexOf('/') != -1 ) + domain = domain.substr(0, domain.indexOf('/')); + + if ( domain.indexOf(':') != -1 ) + domain = domain.substr(0, domain.indexOf(':')); + + return domain; + } + + private function _stripSubdomain(domain:String):String { + var els:Array = domain.split("."); + var len:int = els.length; + + // 2 parts --> cannot strip + if (len == 2) return domain; + + if ("co,com,net,org,web,gov,edu,".indexOf(els[len-2] + ",") != -1 || StringUtil.endsWith(domain, "ac.uk")) { + // special ending (amazon.co.uk) + return els[len-3] + "." + els[len-2] + "." + els[len-1];; + } else { + return els[len-2] + "." + els[len-1]; + } + } + + public function set onFailure(listener:Function):void { + + } + public function handeNetStatusEvent(event:NetStatusEvent):Boolean { + log.error("handeNetStatusEvent", event); + return true; + } + + public function onConfig(model:PluginModel):void { + _model = model; + _config = new Config(); + + if ( ! model.config ) + return; + + // only allow to overide default config. + if ( ! _config.privateKey ) + _config.privateKey = model.config['privateKey']; + + if ( _config.domains.length == 0 ) + _config.domains = model.config['domains']; + + if ( ! _config.keyPairId ) + _config.keyPairId = model.config['keyPairId']; + + if ( ! _config.timeToLive ) + _config.timeToLive = model.config['timeToLive']; + } + + public function onLoad(player:Flowplayer):void { + _player = player; + try { + if ( ! _checkDomains() ) { + _model.dispatchError(PluginError.ERROR, "Incorrect domain : " + _getDomain() +", allowed : "+ _config.domains.join(", ") +")"); + return; + } + } catch(e:Error) { + log.error("error", e); + } + + _signedUrlGenerator = new SignedUrlGenerator(_config); + + + _model.dispatchOnLoad(); + } + + + public function getDefaultConfig():Object { + return null; + } + + + + } +} \ No newline at end of file diff --git a/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/CloudFrontSignedUrlPlugin.as b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/CloudFrontSignedUrlPlugin.as new file mode 100644 index 0000000..d409c72 --- /dev/null +++ b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/CloudFrontSignedUrlPlugin.as @@ -0,0 +1,21 @@ +/* + * This file is part of Flowplayer, http://flowplayer.org + * + * By: Thomas Dubois, thomas _at_ flowplayer.org + * Copyright (c) 2010 Flowplayer Oy + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + */ + +package org.flowplayer.cloudfrontsignedurl { + import flash.display.Sprite; + import org.flowplayer.model.PluginFactory; + + public class CloudFrontSignedUrlPlugin extends Sprite implements PluginFactory{ + + public function newPlugin():Object { + return new CloudFrontSignedUrl(); + } + } +} \ No newline at end of file diff --git a/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/Config.as b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/Config.as new file mode 100644 index 0000000..1f406ef --- /dev/null +++ b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/Config.as @@ -0,0 +1,57 @@ +/* + * This file is part of Flowplayer, http://flowplayer.org + * + * By: Thomas Dubois, thomas _at_ flowplayer.org + * Copyright (c) 2010 Flowplayer Oy + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + */ + +package org.flowplayer.cloudfrontsignedurl { + + public class Config { + private var _privateKey:String = ""; + private var _keyPairId:String = ""; + + private var _timeToLive:Number = 5*60; + private var _domains:Array = []; + + + public function get privateKey():String { + return _privateKey; + } + + public function set privateKey(val:String):void { + _privateKey = val; + } + + public function get keyPairId():String { + return _keyPairId; + } + + public function set keyPairId(val:String):void { + _keyPairId = val; + } + + public function toString():String { + return "[Config] keyPairId = '" + _keyPairId + "'"; + } + + public function get timeToLive():Number { + return _timeToLive; + } + + public function set timeToLive(val:Number):void { + _timeToLive = val; + } + + public function get domains():Array { + return _domains; + } + + public function set domains(value:Array):void { + _domains = value; + } + } +} \ No newline at end of file diff --git a/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/SecuredCloudfrontRTMPConnectionProvider.as b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/SecuredCloudfrontRTMPConnectionProvider.as new file mode 100644 index 0000000..0b728b7 --- /dev/null +++ b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/SecuredCloudfrontRTMPConnectionProvider.as @@ -0,0 +1,36 @@ +/* + * Copyright 2008 Anssi Piirainen + * + * This file is part of FlowPlayer. + * + * FlowPlayer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FlowPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FlowPlayer. If not, see . + */ + +package org.flowplayer.cloudfrontsignedurl { + + import org.flowplayer.controller.*; + + /** + * @author api + */ + public class SecuredCloudfrontRTMPConnectionProvider extends ParallelRTMPConnectionProvider { + protected var _config:Object; + + public function SecuredCloudfrontRTMPConnectionProvider(config:Object) { + super(config.netConnectionUrl, config.proxyType, config.failOverDelay); + _config = config; + } + + } +} diff --git a/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/SignedUrlGenerator.as b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/SignedUrlGenerator.as new file mode 100644 index 0000000..1f4f53b --- /dev/null +++ b/plugins/cloudfrontsignedurl/src/actionscript/org/flowplayer/cloudfrontsignedurl/SignedUrlGenerator.as @@ -0,0 +1,91 @@ +/* + * This file is part of Flowplayer, http://flowplayer.org + * + * By: Thomas Dubois, thomas _at_ flowplayer.org + * Copyright (c) 2010 Flowplayer Oy + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + */ + +package org.flowplayer.cloudfrontsignedurl { + + import org.flowplayer.model.Clip; + import com.hurlant.crypto.rsa.RSAKey; + import com.hurlant.crypto.hash.SHA1; + import flash.utils.ByteArray; + import com.hurlant.util.Hex; + import com.hurlant.util.der.PEM; + import com.hurlant.util.Base64; + + import org.flowplayer.util.Log; + + public class SignedUrlGenerator { + + private var log:Log = new Log(this); + private var _config:Config = null; + private var _rsa:RSAKey = null; + + + public function SignedUrlGenerator(config:Config) { + _config = config; + _rsa = PEM.readRSAPrivateKey(_config.privateKey); + } + + public function signUrl(url:String, expires:Number):String { + var resource:String = url; + + var rawPolicy:String = '{"Statement":[{"Resource":"'+ url +'","Condition":{"DateLessThan":{"AWS:EpochTime":'+ expires +'}}}]}'; + log.debug("Using policy "+ rawPolicy); + + var safePolicy:String = getSafeString(rawPolicy); + + var signature:String = getSignature(rawPolicy); + var safeSignature:String= getSafeString(signature); + + var queryString:String = 'Expires='+ expires +'&Signature='+ safeSignature +'&Key-Pair-Id='+ _config.keyPairId; + var separator:String = resource.indexOf('?') == -1 ? '?' : '&'; + + var signedUrl:String = url + separator + queryString; + log.debug("Generated url "+ signedUrl); + return signedUrl; + } + + private function getSignature(rawPolicy:String):String { + var hexRawPolicy:ByteArray = Hex.toArray(Hex.fromString(rawPolicy)); + + var dst:ByteArray = new ByteArray(); + _rsa.sign(hexRawPolicy, dst, hexRawPolicy.length, SHA1DigestPadding); + + var signature:String = com.hurlant.util.Base64.encodeByteArray(dst); + + return signature; + } + + // thousand thanks to Kenji Urushima, derived from http://www9.atwiki.jp/kurushima/pub/jsrsa/ + private function SHA1DigestPadding(src:ByteArray, end:int, n:uint, type:uint = 0x02):ByteArray { + var pmStrLen:Number = _rsa.n.bitLength() / 4; + + var _RSASIGN_SHA1_DIHEAD:String = "3021300906052b0e03021a05000414"; + + var sha1:SHA1 = new SHA1(); + var sHashHex:ByteArray = sha1.hash(src); + + var sHead:String = "0001"; + var sTail:String = "00" + _RSASIGN_SHA1_DIHEAD + Hex.fromArray(sHashHex); + var sMid:String = ""; + var fLen:Number = pmStrLen - sHead.length - sTail.length; + for (var i:int = 0; i < fLen; i += 2) { + sMid += "ff"; + } + + var sPaddedMessageHex:String = sHead + sMid + sTail; + + return Hex.toArray(sPaddedMessageHex); + } + + private function getSafeString(str:String):String { + return str.replace(/\+/g, '-').replace(/=/g, '_').replace(/\//g, '~'); + } + } +} \ No newline at end of file diff --git a/plugins/cluster/README.txt b/plugins/cluster/README.txt index ef873ea..8c6bdbc 100644 --- a/plugins/cluster/README.txt +++ b/plugins/cluster/README.txt @@ -1,5 +1,10 @@ Version history: +3.2.10 +------ +- #99 cleanup domain parsing, use native function instead of mx classes. +- #101 fixes for handling origin server redirections. + 3.2.4 ----- - #601 dispatch resolver failure correctly. diff --git a/plugins/cluster/build.properties b/plugins/cluster/build.properties index 93ede59..ddb7666 100644 --- a/plugins/cluster/build.properties +++ b/plugins/cluster/build.properties @@ -1,2 +1,2 @@ devkit-dir=../../lib/devkit -version=3.2.9 +version=3.2.10 diff --git a/plugins/cluster/build.xml b/plugins/cluster/build.xml index bdf07e8..9a3c582 100644 --- a/plugins/cluster/build.xml +++ b/plugins/cluster/build.xml @@ -6,11 +6,14 @@ - - + + + + + diff --git a/plugins/cluster/src/actionscript/org/flowplayer/cluster/ClusterConnectionProvider.as b/plugins/cluster/src/actionscript/org/flowplayer/cluster/ClusterConnectionProvider.as index 00e23c0..ab673f9 100644 --- a/plugins/cluster/src/actionscript/org/flowplayer/cluster/ClusterConnectionProvider.as +++ b/plugins/cluster/src/actionscript/org/flowplayer/cluster/ClusterConnectionProvider.as @@ -1 +1 @@ -/* * This file is part of Flowplayer, http://flowplayer.org * * By: Daniel Rossi, , Anssi Piirainen Flowplayer Oy * Copyright (c) 2008-2011 Flowplayer Oy * * Released under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.cluster { import flash.events.IOErrorEvent; import flash.events.NetStatusEvent; import flash.net.NetConnection; import flash.net.NetStream; import flash.net.Responder; import flash.utils.*; import org.flowplayer.controller.ClipURLResolver; import org.flowplayer.controller.ConnectionProvider; import org.flowplayer.controller.NetConnectionClient; import org.flowplayer.controller.NetStreamClient; import org.flowplayer.controller.NetStreamControllingStreamProvider; import org.flowplayer.controller.StreamProvider; import org.flowplayer.model.Clip; import org.flowplayer.model.ClipError; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginEventType; import org.flowplayer.model.PluginModel; import org.flowplayer.util.Log; import org.flowplayer.util.PropertyBinder; import org.flowplayer.util.URLUtil; import org.flowplayer.view.Flowplayer; /** * A RTMP stream provider with fallback and clustering support. Supports following: *
        *
      • Starting in the middle of the clip's timeline using the clip.start property.
      • *
      • Stopping before the clip file ends using the clip.duration property.
      • *
      • Ability to combine a group of clips into one gapless stream.
      • *
      • Ability to fallback to a list of servers in a cluster server farm.
      • *
      • Ability to recognise, store and leave out any failed servers for a given time.
      • *
      • Ability to randomly connect to a server in the servers list mimicking a round robin connection.
      • *
      • Works with a traditional load balancing appliance by feeding its host at the top of the list, and direct connections to the servers happen on fallback.
      • *
      *

      * Stream group is configured in a clip like this: * * { streams: [ { url: 'metacafe', duration: 20 }, { url: 'honda_accord', start: 10, duration: 20 } ] } * * The group is played back seamlessly as one gapless stream. The individual streams in a group can * be cut out from a larger file using the 'start' and 'duration' properties as shown in the example above. * *

      * To enable server fallback a hosts config property is required in the plugins config like this: * * hosts: [ * 'rtmp://server1.host.com/myapp', * 'rtmp://server2.host.com/myapp', * 'rtmp://server3.host.com/myapp', * ] * *

      * To enable the fallback feature to store (client side) failed servers to prevent reattempting those connections the failureExpiry config property is required like so: * failureExpiry: 3000, * *

      This tells the feature to wait for 3000 milliseconds before allowing connection attempts again. * *

      * To enable round robin connections the loadBalanceServers config property requires to be enabled like so: * * loadBalanceServers: true * *

      * Advanced configurations for the fallback feature can be enabled like so: * * connectTimeout: 5000, * connectCount: 3 * encoding: 0 * *

      connectTimeout is the time in milliseconds before each reconnection attempt. * connectCount is the ammount of times connection reattmps will occur before giving up. * encoding is the AMF encoding version either 0 or 3 for AMF3. * *

      Two custom events a fired during connection attempts and fallback, these are: * *

        *
      • RTMPEventType.RECONNECTED - onReconnect
      • *
      • RTMPEventType.FAILED - onFailed
      • *
      * * @author danielr */ public class ClusterConnectionProvider implements ConnectionProvider, ClipURLResolver, Plugin { private var _config:ClusterConfig; private var log:Log = new Log(this); protected var _rtmpCluster:RTMPCluster; private var _connection:NetConnection; private var _netStream:NetStream; private var _provider:StreamProvider; private var _successListener:Function; private var _failureListener:Function; private var _connectionClient:Object; private var _objectEncoding:uint; private var _clip:Clip; private var _connectionArgs:Array; private var _isComplete:Boolean = false; private var _model:PluginModel; private var _resolving:Boolean; private var _player:Flowplayer; private var _onConnectionStatusCallback:Function; public function onConfig(model:PluginModel):void { log.debug("onConfig"); _model = model; _config = new PropertyBinder(new ClusterConfig(), null).copyProperties(model.config) as ClusterConfig; _rtmpCluster = new RTMPCluster(_config); _rtmpCluster.onFailed(onFailed); } public function getDefaultConfig():Object { return null; } public function connect(provider:StreamProvider, clip:Clip, successListener:Function, objectEncoding:uint, connectionArgs:Array):void { log.debug("connect()"); _resolving = false; _objectEncoding = objectEncoding; _clip = clip; _connectionArgs = connectionArgs; _successListener = successListener; _provider = provider as NetStreamControllingStreamProvider; _connection = new NetConnection(); _connection.proxyType = "best"; _connection.objectEncoding = objectEncoding; _connection.client = _connectionClient || new NetConnectionClient(); log.debug("connect() using connection client " + _connection.client); _connection.addEventListener(NetStatusEvent.NET_STATUS, connectionProviderConnectionStatus); _connection.addEventListener(IOErrorEvent.IO_ERROR, _netIOError); var host:String = getNextNetConnectionUrl(clip); log.debug("connecting to " + host); if (connectionArgs.length > 0) { _connection.connect(host, connectionArgs); } else if (_config.connectionArgs) { _connection.connect(host, _config.connectionArgs); } else { _connection.connect(host); } _model.dispatch(PluginEventType.PLUGIN_EVENT, "onConnect", _rtmpCluster.currentHost, _rtmpCluster.currentHostIndex); if (isRtmpUrl(host)) { _rtmpCluster.onReconnected(onRTMPReconnect); _rtmpCluster.start(); } } private function _netIOError(event:IOErrorEvent):void { log.error(event.text); } protected function getNextNetConnectionUrl(clip:Clip):String { var host:String = _rtmpCluster.nextHost; if (isRtmpUrl(host)) return host; return null; } private function connectionProviderConnectionStatus(event:NetStatusEvent):void { if (_onConnectionStatusCallback != null) { _onConnectionStatusCallback(event, _connection); } if (event.info.code == "NetConnection.Connect.Success" && _successListener != null) { log.debug("_onConnectionStatus, NetConnection.Connect.Success, calling clusterComplete()"); clusterComplete(); } else if (["NetConnection.Connect.Failed", "NetConnection.Connect.Rejected", "NetConnection.Connect.AppShutdown", "NetConnection.Connect.InvalidApp"].indexOf(event.info.code) >= 0) { log.info("Couldnt connect to " + _connection.uri); } } public function set connectionClient(client:Object):void { if (_connection) { _connection.client = client; } _connectionClient = client; } public function set onFailure(listener:Function):void { _failureListener = listener; } protected function get connection():NetConnection { return _connection; } public function handeNetStatusEvent(event:NetStatusEvent):Boolean { return true; } protected function get provider():StreamProvider { return _provider; } protected function get failureListener():Function { return _failureListener; } protected function get successListener():Function { return _successListener; } /** * Fallback feature method called by the reconnection attempt timer */ protected function onRTMPReconnect():void { _model.dispatch(PluginEventType.PLUGIN_EVENT, "onConnectFailed", _rtmpCluster.currentHost, _rtmpCluster.currentHostIndex); _rtmpCluster.setFailedServer(_rtmpCluster.currentHost); _connection.close(); _rtmpCluster.stop(); //#427 run host checks here to check for null hosts on rtmp. if (!_rtmpCluster.hasMoreHosts()) { _rtmpCluster.stop(); onFailed(); return; } connect(_provider, _clip, _successListener, _objectEncoding, _connectionArgs); log.info("RTMP Connection Failed Attempting Reconnection"); } protected function onHTTPReconnect():void { _model.dispatch(PluginEventType.PLUGIN_EVENT, "onConnectFailed", _rtmpCluster.currentHost, _rtmpCluster.currentHostIndex); _rtmpCluster.setFailedServer(_clip.getResolvedUrl(this)); _rtmpCluster.stop(); log.info("HTTP Connection Attempting Reconnection"); resolveURL(true); } protected function onFailed():void { log.info("Connections failed"); //#601 dispatch resolver failure correctly. _failureListener(_clip.completeUrl); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onFailed"); } protected function resolveURL(useNextHost:Boolean):void { //fix for #377, run host checks and increment indexes here to trigger reconnections of the next host or else recurssion occurs or last host is null. if (!_rtmpCluster.hasMoreHosts()) { _rtmpCluster.stop(); onFailed(); return; } log.debug("resolveURL, useNextHost " + useNextHost); // store the resolvedUrl already now, to make sure the resolved URL is there when onStart() // is dispatched by the provider var currentUrl:String = _clip.getPreviousResolvedUrl(this); var nextHost:String = useNextHost ? _rtmpCluster.nextHost : _rtmpCluster.currentHost; var url:String = URLUtil.completeURL(nextHost, URLUtil.baseUrlAndRest(currentUrl)[1]); _clip.setResolvedUrl(this, url); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onConnect", _rtmpCluster.currentHost, _rtmpCluster.currentHostIndex); //#15 add cache busting to the file being checked for availability to play back correctly once resolving has completed. _netStream.play(_clip.getResolvedUrl(this) + "?" + Math.random()); _rtmpCluster.start(); } private function _onNetStatus(event:NetStatusEvent):void { if (event.info.code == "NetStream.Play.Start") { log.debug("_onNetStatus: NetStream.Play.Start, calling clusterComplete()"); clusterComplete(); } else if (event.info.code == "NetStream.Play.StreamNotFound" || event.info.code == "NetConnection.Connect.Rejected" || event.info.code == "NetConnection.Connect.Failed") { onHTTPReconnect(); } } protected function clusterComplete():void { _isComplete = true; if (_netStream) { _netStream.close(); } _rtmpCluster.stop(); if (_resolving) { log.debug("clusterComplete(), resolving? " + _resolving); var currentUrl:String = _clip.getPreviousResolvedUrl(this); _clip.setResolvedUrl(this, URLUtil.completeURL(_rtmpCluster.currentHost, URLUtil.baseUrlAndRest(currentUrl)[1])); _successListener(_clip); } else { getServerDuration(); log.debug("calling success listener"); _successListener(_connection); } } private function lookupRtmpPlugin(providers:Dictionary):PluginModel { for each (var obj:Object in providers) { var model:PluginModel = obj as PluginModel; log.debug(model.name); if (model.name == "rtmp") { return model; } if (["http", "httpInstream"].indexOf(model.name) < 0 && model.pluginObject is StreamProvider) { return model; } } return null; } private function getServerDuration():void { log.debug("getServerDuration()"); var model:PluginModel = lookupRtmpPlugin(_player.pluginRegistry.providers); if (! model) return; log.debug("found RTMP plugin " + model + ", looking up durationFunc"); if (model.config && model.config.durationFunc) { log.debug("getServerDuration(), calling durationFunc '" + model.config.durationFunc + "'"); _connection.call(model.config.durationFunc, new Responder(onDurationResult), _clip.url); } } private function onDurationResult(info:Object):void { log.debug("onDurationResult()"); _clip.duration = info as Number; } public function resolve(provider:StreamProvider, clip:Clip, successListener:Function):void { log.debug("resolve()"); _resolving = true; _clip = clip; _successListener = successListener; _provider = provider; if (_provider.netStream) { _provider.netStream.close(); } _connection = new NetConnection(); _connection.addEventListener(NetStatusEvent.NET_STATUS, _onConnectionStatus); _connection.connect(getNextNetConnectionUrl(_clip)); } private function _onConnectionStatus(event:NetStatusEvent):void { log.debug("onConnectionStatus: " + event.info.code); if (event.info.code == "NetConnection.Connect.Success") { doResolve(false); } else if (["NetConnection.Connect.Failed", "NetConnection.Connect.Rejected", "NetConnection.Connect.AppShutdown", "NetConnection.Connect.InvalidApp"].indexOf(event.info.code) >= 0) { _failureListener("Failed to connect " + event.info.code); } } private function doResolve(useNextHost:Boolean):void { _netStream = new NetStream(_connection); _netStream.client = new NetStreamClient(_clip, _player.config, _provider.streamCallbacks); _netStream.addEventListener(NetStatusEvent.NET_STATUS, _onNetStatus); _rtmpCluster.onReconnected(onHTTPReconnect); _rtmpCluster.start(); resolveURL(useNextHost); } public static function isRtmpUrl(url:String):Boolean { if (! url) return false; return url.toLowerCase().indexOf("rtmp") == 0; } [External] public function set loadBalancing(enabled:Boolean):void { log.debug("setting loadBalanceServers to " + enabled); _config.loadBalance = enabled; } public function onLoad(player:Flowplayer):void { _player = player; _model.dispatchOnLoad(); } public function set onConnectionStatus(value:Function):void { _onConnectionStatusCallback = value; } } } \ No newline at end of file +/* * This file is part of Flowplayer, http://flowplayer.org * * By: Daniel Rossi, , Anssi Piirainen Flowplayer Oy * Copyright (c) 2008-2011 Flowplayer Oy * * Released under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.cluster { import flash.events.IOErrorEvent; import flash.events.NetStatusEvent; import flash.net.NetConnection; import flash.net.NetStream; import flash.net.Responder; import flash.utils.*; import org.flowplayer.controller.ClipURLResolver; import org.flowplayer.controller.ConnectionProvider; import org.flowplayer.controller.NetConnectionClient; import org.flowplayer.controller.NetStreamClient; import org.flowplayer.controller.NetStreamControllingStreamProvider; import org.flowplayer.controller.StreamProvider; import org.flowplayer.model.Clip; import org.flowplayer.model.ClipError; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginEventType; import org.flowplayer.model.PluginModel; import org.flowplayer.util.Log; import org.flowplayer.util.PropertyBinder; import org.flowplayer.util.URLUtil; import org.flowplayer.view.Flowplayer; /** * A RTMP stream provider with fallback and clustering support. Supports following: *
        *
      • Starting in the middle of the clip's timeline using the clip.start property.
      • *
      • Stopping before the clip file ends using the clip.duration property.
      • *
      • Ability to combine a group of clips into one gapless stream.
      • *
      • Ability to fallback to a list of servers in a cluster server farm.
      • *
      • Ability to recognise, store and leave out any failed servers for a given time.
      • *
      • Ability to randomly connect to a server in the servers list mimicking a round robin connection.
      • *
      • Works with a traditional load balancing appliance by feeding its host at the top of the list, and direct connections to the servers happen on fallback.
      • *
      *

      * Stream group is configured in a clip like this: * * { streams: [ { url: 'metacafe', duration: 20 }, { url: 'honda_accord', start: 10, duration: 20 } ] } * * The group is played back seamlessly as one gapless stream. The individual streams in a group can * be cut out from a larger file using the 'start' and 'duration' properties as shown in the example above. * *

      * To enable server fallback a hosts config property is required in the plugins config like this: * * hosts: [ * 'rtmp://server1.host.com/myapp', * 'rtmp://server2.host.com/myapp', * 'rtmp://server3.host.com/myapp', * ] * *

      * To enable the fallback feature to store (client side) failed servers to prevent reattempting those connections the failureExpiry config property is required like so: * failureExpiry: 3000, * *

      This tells the feature to wait for 3000 milliseconds before allowing connection attempts again. * *

      * To enable round robin connections the loadBalanceServers config property requires to be enabled like so: * * loadBalanceServers: true * *

      * Advanced configurations for the fallback feature can be enabled like so: * * connectTimeout: 5000, * connectCount: 3 * encoding: 0 * *

      connectTimeout is the time in milliseconds before each reconnection attempt. * connectCount is the ammount of times connection reattmps will occur before giving up. * encoding is the AMF encoding version either 0 or 3 for AMF3. * *

      Two custom events a fired during connection attempts and fallback, these are: * *

        *
      • RTMPEventType.RECONNECTED - onReconnect
      • *
      • RTMPEventType.FAILED - onFailed
      • *
      * * @author danielr */ public class ClusterConnectionProvider implements ConnectionProvider, ClipURLResolver, Plugin { private var _config:ClusterConfig; private var log:Log = new Log(this); protected var _rtmpCluster:RTMPCluster; private var _connection:NetConnection; private var _netStream:NetStream; private var _provider:StreamProvider; private var _successListener:Function; private var _failureListener:Function; private var _connectionClient:Object; private var _objectEncoding:uint; private var _clip:Clip; private var _connectionArgs:Array; private var _isComplete:Boolean = false; private var _model:PluginModel; private var _resolving:Boolean; private var _player:Flowplayer; private var _onConnectionStatusCallback:Function; public function onConfig(model:PluginModel):void { log.debug("onConfig"); _model = model; _config = new PropertyBinder(new ClusterConfig(), null).copyProperties(model.config) as ClusterConfig; _rtmpCluster = new RTMPCluster(_config); _rtmpCluster.onFailed(onFailed); } public function getDefaultConfig():Object { return null; } public function connect(provider:StreamProvider, clip:Clip, successListener:Function, objectEncoding:uint, connectionArgs:Array):void { log.debug("connect()"); _resolving = false; _objectEncoding = objectEncoding; _clip = clip; _connectionArgs = connectionArgs; _successListener = successListener; _provider = provider as NetStreamControllingStreamProvider; _connection = new NetConnection(); _connection.proxyType = "best"; _connection.objectEncoding = objectEncoding; _connection.client = _connectionClient || new NetConnectionClient(); log.debug("connect() using connection client " + _connection.client); _connection.addEventListener(NetStatusEvent.NET_STATUS, connectionProviderConnectionStatus); _connection.addEventListener(IOErrorEvent.IO_ERROR, _netIOError); var host:String = getNextNetConnectionUrl(clip); log.debug("connecting to " + host); if (connectionArgs.length > 0) { _connection.connect(host, connectionArgs); } else if (_config.connectionArgs) { _connection.connect(host, _config.connectionArgs); } else { _connection.connect(host); } _model.dispatch(PluginEventType.PLUGIN_EVENT, "onConnect", _rtmpCluster.currentHost, _rtmpCluster.currentHostIndex); if (isRtmpUrl(host)) { _rtmpCluster.onReconnected(onRTMPReconnect); _rtmpCluster.start(); } } private function _netIOError(event:IOErrorEvent):void { log.error(event.text); } protected function getNextNetConnectionUrl(clip:Clip):String { var host:String = _rtmpCluster.nextHost; if (isRtmpUrl(host)) return host; return null; } private function connectionProviderConnectionStatus(event:NetStatusEvent):void { if (_onConnectionStatusCallback != null) { _onConnectionStatusCallback(event, _connection); } if (event.info.code == "NetConnection.Connect.Success" && _successListener != null) { log.debug("_onConnectionStatus, NetConnection.Connect.Success, calling clusterComplete()"); clusterComplete(); //#101 handle redirects for clustering origin servers } else if (event.info.code == "NetConnection.Connect.Rejected" && event.info.ex && event.info.ex.code == 302) { _rtmpCluster.stop(); _rtmpCluster.updateCurrentHost(event.info.ex.redirect); setTimeout(function():void{ log.debug("connecting to a redirected URL " + event.info.ex.redirect); connect(_provider, _clip, _successListener, _objectEncoding, _connectionArgs); }, 100); } else if (["NetConnection.Connect.Failed", "NetConnection.Connect.AppShutdown", "NetConnection.Connect.InvalidApp"].indexOf(event.info.code) >= 0) { log.info("Couldnt connect to " + _connection.uri); } } public function set connectionClient(client:Object):void { if (_connection) { _connection.client = client; } _connectionClient = client; } public function set onFailure(listener:Function):void { _failureListener = listener; } protected function get connection():NetConnection { return _connection; } public function handeNetStatusEvent(event:NetStatusEvent):Boolean { return true; } protected function get provider():StreamProvider { return _provider; } protected function get failureListener():Function { return _failureListener; } protected function get successListener():Function { return _successListener; } /** * Fallback feature method called by the reconnection attempt timer */ protected function onRTMPReconnect():void { _model.dispatch(PluginEventType.PLUGIN_EVENT, "onConnectFailed", _rtmpCluster.currentHost, _rtmpCluster.currentHostIndex); _rtmpCluster.setFailedServer(_rtmpCluster.currentHost); _connection.close(); _rtmpCluster.stop(); //#427 run host checks here to check for null hosts on rtmp. if (!_rtmpCluster.hasMoreHosts()) { _rtmpCluster.stop(); onFailed(); return; } connect(_provider, _clip, _successListener, _objectEncoding, _connectionArgs); log.info("RTMP Connection Failed Attempting Reconnection"); } protected function onHTTPReconnect():void { _model.dispatch(PluginEventType.PLUGIN_EVENT, "onConnectFailed", _rtmpCluster.currentHost, _rtmpCluster.currentHostIndex); _rtmpCluster.setFailedServer(_clip.getResolvedUrl(this)); _rtmpCluster.stop(); log.info("HTTP Connection Attempting Reconnection"); resolveURL(true); } protected function onFailed():void { log.info("Connections failed"); //#601 dispatch resolver failure correctly. _failureListener(_clip.completeUrl); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onFailed"); } protected function resolveURL(useNextHost:Boolean):void { //fix for #377, run host checks and increment indexes here to trigger reconnections of the next host or else recurssion occurs or last host is null. if (!_rtmpCluster.hasMoreHosts()) { _rtmpCluster.stop(); onFailed(); return; } log.debug("resolveURL, useNextHost " + useNextHost); // store the resolvedUrl already now, to make sure the resolved URL is there when onStart() // is dispatched by the provider var currentUrl:String = _clip.getPreviousResolvedUrl(this); var nextHost:String = useNextHost ? _rtmpCluster.nextHost : _rtmpCluster.currentHost; var url:String = URLUtil.completeURL(nextHost, URLUtil.baseUrlAndRest(currentUrl)[1]); _clip.setResolvedUrl(this, url); _model.dispatch(PluginEventType.PLUGIN_EVENT, "onConnect", _rtmpCluster.currentHost, _rtmpCluster.currentHostIndex); //#15 add cache busting to the file being checked for availability to play back correctly once resolving has completed. _netStream.play(_clip.getResolvedUrl(this) + "?" + Math.random()); _rtmpCluster.start(); } private function _onNetStatus(event:NetStatusEvent):void { if (event.info.code == "NetStream.Play.Start") { log.debug("_onNetStatus: NetStream.Play.Start, calling clusterComplete()"); clusterComplete(); } else if (event.info.code == "NetStream.Play.StreamNotFound" || event.info.code == "NetConnection.Connect.Rejected" || event.info.code == "NetConnection.Connect.Failed") { onHTTPReconnect(); } } protected function clusterComplete():void { _isComplete = true; if (_netStream) { _netStream.close(); } _rtmpCluster.stop(); if (_resolving) { log.debug("clusterComplete(), resolving? " + _resolving); var currentUrl:String = _clip.getPreviousResolvedUrl(this); _clip.setResolvedUrl(this, URLUtil.completeURL(_rtmpCluster.currentHost, URLUtil.baseUrlAndRest(currentUrl)[1])); _successListener(_clip); } else { getServerDuration(); log.debug("calling success listener"); _successListener(_connection); } } private function lookupRtmpPlugin(providers:Dictionary):PluginModel { for each (var obj:Object in providers) { var model:PluginModel = obj as PluginModel; log.debug(model.name); if (model.name == "rtmp") { return model; } if (["http", "httpInstream"].indexOf(model.name) < 0 && model.pluginObject is StreamProvider) { return model; } } return null; } private function getServerDuration():void { log.debug("getServerDuration()"); var model:PluginModel = lookupRtmpPlugin(_player.pluginRegistry.providers); if (! model) return; log.debug("found RTMP plugin " + model + ", looking up durationFunc"); if (model.config && model.config.durationFunc) { log.debug("getServerDuration(), calling durationFunc '" + model.config.durationFunc + "'"); _connection.call(model.config.durationFunc, new Responder(onDurationResult), _clip.url); } } private function onDurationResult(info:Object):void { log.debug("onDurationResult()"); _clip.duration = info as Number; } public function resolve(provider:StreamProvider, clip:Clip, successListener:Function):void { log.debug("resolve()"); _resolving = true; _clip = clip; _successListener = successListener; _provider = provider; if (_provider.netStream) { _provider.netStream.close(); } _connection = new NetConnection(); _connection.addEventListener(NetStatusEvent.NET_STATUS, _onConnectionStatus); _connection.connect(getNextNetConnectionUrl(_clip)); } private function _onConnectionStatus(event:NetStatusEvent):void { log.debug("onConnectionStatus: " + event.info.code); if (event.info.code == "NetConnection.Connect.Success") { doResolve(false); } else if (["NetConnection.Connect.Failed", "NetConnection.Connect.Rejected", "NetConnection.Connect.AppShutdown", "NetConnection.Connect.InvalidApp"].indexOf(event.info.code) >= 0) { _failureListener("Failed to connect " + event.info.code); } } private function doResolve(useNextHost:Boolean):void { _netStream = new NetStream(_connection); _netStream.client = new NetStreamClient(_clip, _player.config, _provider.streamCallbacks); _netStream.addEventListener(NetStatusEvent.NET_STATUS, _onNetStatus); _rtmpCluster.onReconnected(onHTTPReconnect); _rtmpCluster.start(); resolveURL(useNextHost); } public static function isRtmpUrl(url:String):Boolean { if (! url) return false; return url.toLowerCase().indexOf("rtmp") == 0; } [External] public function set loadBalancing(enabled:Boolean):void { log.debug("setting loadBalanceServers to " + enabled); _config.loadBalance = enabled; } public function onLoad(player:Flowplayer):void { _player = player; _model.dispatchOnLoad(); } public function set onConnectionStatus(value:Function):void { _onConnectionStatusCallback = value; } } } \ No newline at end of file diff --git a/plugins/cluster/src/actionscript/org/flowplayer/cluster/RTMPCluster.as b/plugins/cluster/src/actionscript/org/flowplayer/cluster/RTMPCluster.as index 042486e..95000a5 100644 --- a/plugins/cluster/src/actionscript/org/flowplayer/cluster/RTMPCluster.as +++ b/plugins/cluster/src/actionscript/org/flowplayer/cluster/RTMPCluster.as @@ -10,260 +10,273 @@ package org.flowplayer.cluster { -import flash.events.TimerEvent; -import flash.net.SharedObject; -import flash.utils.Timer; - -import mx.utils.URLUtil; - -import org.flowplayer.flow_internal; -import org.flowplayer.model.ClipEvent; -import org.flowplayer.model.PluginEventDispatcher; -import org.flowplayer.model.PluginEventType; -import org.flowplayer.model.PluginModel; -import org.flowplayer.model.PluginModelImpl; -import org.flowplayer.util.Log; - -use namespace flow_internal; - -public class RTMPCluster { - protected var _hosts:Array; - protected var _timer:Timer; - protected var _hostIndex:int = 0; - protected var _hostCount:int = 0; - protected var _connectCount:int = 0; - protected var _reConnectCount:int = 0; - protected var _connectTimeout:int = 2000; - protected var _loadBalanceServers:Boolean = false; - protected var _liveHosts:Array; - protected var _liveRandomServers:Array = []; - private var _startAfterConnect:Boolean; - protected var _failureExpiry:int = 0; + import flash.events.TimerEvent; + import flash.net.SharedObject; + import flash.utils.Timer; + + //import mx.utils.URLUtil; + + import org.flowplayer.flow_internal; + //import org.flowplayer.model.PluginModelImpl; + import org.flowplayer.util.Log; + + import org.flowplayer.util.URLUtil; + + use namespace flow_internal; + + public class RTMPCluster { + protected var _hosts:Array; + protected var _timer:Timer; + protected var _hostIndex:int = 0; + //protected var _hostCount:int = 0; + protected var _connectCount:int = 0; + protected var _reConnectCount:int = 0; + protected var _connectTimeout:int = 2000; + //protected var _loadBalanceServers:Boolean = false; + protected var _liveHosts:Array; + //protected var _liveRandomServers:Array = []; + //private var _startAfterConnect:Boolean; + protected var _failureExpiry:int = 0; protected var _reconnectFailureExpiry:int = 0; - private var _config:*; - private var _dispatcher:PluginModelImpl; - private var log:Log = new Log(this); - private var _reconnectListener:Function; - private var _failureListener:Function; - private var _currentHost:Object; - - - public function RTMPCluster(config:*) - { - _config = config; - - // there can be several hosts, or we are just using one single netConnectionUrl - initHosts(_config.hosts, config.netConnectionUrl); - - _connectCount = config.connectCount; - _connectTimeout = config.connectTimeout; - _failureExpiry = config.failureExpiry; - _currentHost = _hosts ? _hosts[0] : null; - } - - private function initHosts(hosts:Array, fallback:String):void { - log.debug("initHosts()"); - var myHosts:Array = []; - if (! hosts || hosts.length == 0) { - if (! fallback) { - throw new Error("A hosts array or a netConnectionUrl must be configured"); - } - myHosts.push({ 'host': fallback}); - } else { - for (var i:int = 0; i < hosts.length; i++) { - myHosts.push(hosts[i] is String ? { 'host': hosts[i] } : hosts[i]); + private var _config:*; + //private var _dispatcher:PluginModelImpl; + private var log:Log = new Log(this); + private var _reconnectListener:Function; + private var _failureListener:Function; + private var _currentHost:Object; + + + public function RTMPCluster(config:*) + { + _config = config; + // there can be several hosts, or we are just using one single netConnectionUrl + initHosts(_config.hosts, config.netConnectionUrl); + + _connectCount = config.connectCount; + _connectTimeout = config.connectTimeout; + _failureExpiry = config.failureExpiry; + _currentHost = _hosts ? _hosts[0] : null; + } + + private function initHosts(hosts:Array, fallback:String):void { + log.debug("initHosts()"); + var myHosts:Array = []; + if (! hosts || hosts.length == 0) { + if (! fallback) { + throw new Error("A hosts array or a netConnectionUrl must be configured"); + } + myHosts.push({ 'host': fallback}); + } else { + for (var i:int = 0; i < hosts.length; i++) { + myHosts.push(hosts[i] is String ? { 'host': hosts[i] } : hosts[i]); + } } + + _hosts = myHosts; + _liveHosts = _hosts; + log.debug("initHosts(), we have " + _liveHosts.length + " live hosts initially"); } - _hosts = myHosts; - _liveHosts = _hosts; - log.debug("initHosts(), we have " + _liveHosts.length + " live hosts initially"); - } + public function onReconnected(listener:Function):void { + _reconnectListener = listener; + } - public function onReconnected(listener:Function):void { - _reconnectListener = listener; - } + public function onFailed(listener:Function):void { + _failureListener = listener; + } - public function onFailed(listener:Function):void { - _failureListener = listener; - } + public function get currentHosts():Array + { + return _hosts.filter(_checkLiveHost); + } - public function get currentHosts():Array - { - return _hosts.filter(_checkLiveHost); - } + public function get hosts():Array + { + return _hosts; + } - public function get hosts():Array - { - return _hosts; - } + public function get hostIndex():int + { + return _hostIndex; + } - public function get nextHost():String - { - if (hasMultipleHosts()) + public function updateCurrentHost(host:String):void { - _liveHosts = currentHosts; - if (_liveHosts.length == 0) { - log.error("no live hosts available"); - if (_failureListener != null) { - _failureListener(); - return null; + _hosts[_hostIndex] = {host: host}; + } + + public function get nextHost():String + { + if (hasMultipleHosts()) + { + _liveHosts = currentHosts; + if (_liveHosts.length == 0) { + log.error("no live hosts available"); + if (_failureListener != null) { + _failureListener(); + return null; + } + } + if (_config.loadBalance) + { + _hostIndex = getRandomIndex(); + log.debug("Load balanced index " + _hostIndex); + } + if (_liveHosts.length > _hostIndex) { + log.debug("cluster has multiple hosts"); + _currentHost = _liveHosts[_hostIndex]; + return _currentHost["host"]; } } - if (_config.loadBalance) - { - _hostIndex = getRandomIndex(); - log.debug("Load balanced index " + _hostIndex); + log.error("no hosts available"); + return null; + } + + public function start():void + { + if (_timer && _timer.running) { + _timer.stop(); } - if (_liveHosts.length > _hostIndex) { - log.debug("cluster has multiple hosts"); - _currentHost = _liveHosts[_hostIndex]; - return _currentHost["host"]; + _timer = new Timer(_connectTimeout, _liveHosts.length); + _timer.addEventListener(TimerEvent.TIMER , tryFallBack); + if (hasMultipleHosts()) { + log.debug("starting connection timeout timer, with a delay of " + _connectTimeout); + _timer.start(); } } - log.error("no hosts available"); - return null; - } - - public function start():void - { - if (_timer && _timer.running) { - _timer.stop(); + + public function stop():void + { + if (_timer != null && _timer.running) _timer.stop(); } - _timer = new Timer(_connectTimeout, _liveHosts.length); - _timer.addEventListener(TimerEvent.TIMER , tryFallBack); - if (hasMultipleHosts()) { - log.debug("starting connection timeout timer, with a delay of " + _connectTimeout); - _timer.start(); + + public function hasMultipleHosts():Boolean + { + return _liveHosts.length > 0; + } + + public function getRandomIndex():uint { + return Math.round(Math.random() * (_liveHosts.length - 1)); } - } - - public function stop():void - { - if (_timer != null && _timer.running) _timer.stop(); - } - - public function hasMultipleHosts():Boolean - { - return _liveHosts.length > 0; - } - - public function getRandomIndex():uint { - return Math.round(Math.random() * (_liveHosts.length - 1)); - } - - public function get liveServers():Array - { - return _liveHosts; - } - - private function _checkLiveHost(element:*, index:int, arr:Array):Boolean - { - return _isLiveServer(element); - } - - private function _getFailedServerSO(host:String):SharedObject - { - var domain:String = URLUtil.getServerName(host); - return SharedObject.getLocal(domain,"/"); - } - - public function setFailedServer(host:String):void - { - log.debug("Setting Failed Server: " + host); - var server:SharedObject = _getFailedServerSO(host); - server.data.failureTimestamp = new Date(); - } - - public function set connectCount(count:Number):void - { - _connectCount = count; - } - - internal function hasMoreHosts():Boolean - { - if (_failureExpiry == 0) - _hostIndex++ - else - _hostIndex = 0; - - _liveHosts = currentHosts; - - if (_hostIndex >= _liveHosts.length) + + public function get liveServers():Array { - // - _reConnectCount++; - if (_reConnectCount < _connectCount) - { - log.debug("Restarting Connection Attempts"); - _hostIndex = 0; - //#427 when reconnecting to the max reconnect count, clear the failure expiry and reset the live hosts to enable to try again ? - _reconnectFailureExpiry = 0; - _liveHosts = currentHosts; + return _liveHosts; + } - } - } else { - //#427 set the normal failure expiry during retries. - _reconnectFailureExpiry = _failureExpiry; + private function _checkLiveHost(element:*, index:int, arr:Array):Boolean + { + return _isLiveServer(element); } - log.debug("Host Index: " + _hostIndex + " LiveServers: " + _liveHosts.length); - return (_hostIndex <= _liveHosts.length && _liveHosts[_hostIndex]); - } - - private function _isLiveServer(element:*):Boolean - { - var host:String = element.host; - var server:SharedObject = _getFailedServerSO(host); - // Server is failed, determine if the failure expiry interval has been reached and clear it - if (server.data.failureTimestamp) + + private function _getFailedServerSO(host:String):SharedObject { - var date:Date = new Date(); + return SharedObject.getLocal(getDomain(host),"/"); + } - // Determine the failure offset - var offset:int = date.getTime() - server.data.failureTimestamp.getTime(); + private function getDomain(url:String):String { + var schemeEnd:int = url.indexOf("//") + 2; + var domain:String = url.substr(schemeEnd); + var endPos:int = domain.indexOf("/"); + return domain.substr(0, endPos); + } - log.debug("Failed Server Remaining Expiry: " + offset + " Start Time: " + server.data.failureTimestamp.getTime() + " Current Time: " + date.getTime()); + public function setFailedServer(host:String):void + { + log.debug("Setting Failed Server: " + host); + var server:SharedObject = _getFailedServerSO(host); + server.data.failureTimestamp = new Date(); + } + + public function set connectCount(count:Number):void + { + _connectCount = count; + } + + internal function hasMoreHosts():Boolean + { + if (_failureExpiry == 0) + _hostIndex++ + else + _hostIndex = 0; + + _liveHosts = currentHosts; - // Failure offset has reached the failureExpiry setting, clear it from the list to allow a connection - //#427 failure expiry was not being reset to honour connect retry. - if (offset >= _reconnectFailureExpiry && _reConnectCount < _connectCount) + if (_hostIndex >= _liveHosts.length) { - log.debug("Clearing Failure Period " + _config.failureExpiry); - server.clear(); - return true; + // + _reConnectCount++; + if (_reConnectCount < _connectCount) + { + log.debug("Restarting Connection Attempts"); + _hostIndex = 0; + //#427 when reconnecting to the max reconnect count, clear the failure expiry and reset the live hosts to enable to try again ? + _reconnectFailureExpiry = 0; + _liveHosts = currentHosts; + + } + } else { + //#427 set the normal failure expiry during retries. + _reconnectFailureExpiry = _failureExpiry; } - return false; + log.debug("Host Index: " + _hostIndex + " LiveServers: " + _liveHosts.length); + return (_hostIndex <= _liveHosts.length && _liveHosts[_hostIndex]); } - return true; - } - protected function tryFallBack(e:TimerEvent):void - { - // Check if there is more hosts to attempt reconnection to - if (hasMoreHosts()) + private function _isLiveServer(element:*):Boolean { - log.debug("invoking reconnect listener"); - if (_reconnectListener != null) { - _reconnectListener(); + var host:String = element.host; + var server:SharedObject = _getFailedServerSO(host); + // Server is failed, determine if the failure expiry interval has been reached and clear it + if (server.data.failureTimestamp) + { + var date:Date = new Date(); + + // Determine the failure offset + var offset:int = date.getTime() - server.data.failureTimestamp.getTime(); + + log.debug("Failed Server Remaining Expiry: " + offset + " Start Time: " + server.data.failureTimestamp.getTime() + " Current Time: " + date.getTime()); + + // Failure offset has reached the failureExpiry setting, clear it from the list to allow a connection + //#427 failure expiry was not being reset to honour connect retry. + if (offset >= _reconnectFailureExpiry && _reConnectCount < _connectCount) + { + log.debug("Clearing Failure Period " + _config.failureExpiry); + server.clear(); + return true; + } + return false; } + return true; + } + + protected function tryFallBack(e:TimerEvent):void + { + // Check if there is more hosts to attempt reconnection to + if (hasMoreHosts()) + { + log.debug("invoking reconnect listener"); + if (_reconnectListener != null) { + _reconnectListener(); + } - } else { - // we have reached the end of the hosts list stop reconnection attempts and send a failed event - stop(); - if (_failureListener != null) { - _failureListener(); + } else { + // we have reached the end of the hosts list stop reconnection attempts and send a failed event + stop(); + if (_failureListener != null) { + _failureListener(); + } } } - } - public function get currentHost():String { - return _currentHost["host"]; - } + public function get currentHost():String { + return _currentHost["host"]; + } - public function get currentHostIndex():int { - return _hosts.indexOf(_currentHost); - } + public function get currentHostIndex():int { + return _hosts.indexOf(_currentHost); + } } diff --git a/plugins/content/build.properties b/plugins/content/build.properties index bf90eab..93ede59 100644 --- a/plugins/content/build.properties +++ b/plugins/content/build.properties @@ -1,2 +1,2 @@ devkit-dir=../../lib/devkit -version=3.2.8 +version=3.2.9 diff --git a/plugins/content/build.xml b/plugins/content/build.xml index c8e3a6b..b2a5be0 100644 --- a/plugins/content/build.xml +++ b/plugins/content/build.xml @@ -4,13 +4,16 @@ - - + + + + + diff --git a/plugins/controls/README.txt b/plugins/controls/README.txt index f39e61a..90837b3 100644 --- a/plugins/controls/README.txt +++ b/plugins/controls/README.txt @@ -1,5 +1,11 @@ Version history: +3.2.16 (Nov 2013) +----------------- +- #58 fix alignment issue with tooltips. first obtain the global coordinates of the parent to use for configuring the + alignment of the tooltip. outmost left and right tooltips are aligned right and left or else centre them. + + 3.2.15 ------ - #42 when returning and resuming from an instream clip, restart the time update timer. diff --git a/plugins/controls/build-air.xml b/plugins/controls/build-air.xml index be4b6a3..0594571 100644 --- a/plugins/controls/build-air.xml +++ b/plugins/controls/build-air.xml @@ -3,12 +3,15 @@ - - + + + + + @@ -17,4 +20,5 @@ + \ No newline at end of file diff --git a/plugins/controls/build-skinless.xml b/plugins/controls/build-skinless.xml index dcad201..f75be81 100644 --- a/plugins/controls/build-skinless.xml +++ b/plugins/controls/build-skinless.xml @@ -3,12 +3,15 @@ - - + + + + + diff --git a/plugins/controls/build-tube.xml b/plugins/controls/build-tube.xml index 62c35c6..46057be 100644 --- a/plugins/controls/build-tube.xml +++ b/plugins/controls/build-tube.xml @@ -7,6 +7,10 @@ + + + + @@ -14,8 +18,8 @@ - - + + diff --git a/plugins/controls/build.properties b/plugins/controls/build.properties index fc780cd..fa65725 100644 --- a/plugins/controls/build.properties +++ b/plugins/controls/build.properties @@ -1,2 +1,2 @@ -version=3.2.15 +version=3.2.16 devkit-dir=../../lib/devkit diff --git a/plugins/controls/build.xml b/plugins/controls/build.xml index fc89bf3..12e610d 100644 --- a/plugins/controls/build.xml +++ b/plugins/controls/build.xml @@ -7,6 +7,9 @@ + + + @@ -15,8 +18,8 @@ - - + + diff --git a/plugins/controls/src/actionscript/org/flowplayer/controls/scrubber/ScrubberSlider.as b/plugins/controls/src/actionscript/org/flowplayer/controls/scrubber/ScrubberSlider.as index fd345e3..056b6b0 100644 --- a/plugins/controls/src/actionscript/org/flowplayer/controls/scrubber/ScrubberSlider.as +++ b/plugins/controls/src/actionscript/org/flowplayer/controls/scrubber/ScrubberSlider.as @@ -56,6 +56,7 @@ package org.flowplayer.controls.scrubber { lookupPluginAndBindEvent(_player, "audio", onAudioEvent); createBars(); addPlaylistListeners(_player.playlist); + this.name = "scrubber"; } private function lookupPluginAndBindEvent(player:Flowplayer, pluginName:String, eventHandler:Function):void { @@ -135,14 +136,14 @@ package org.flowplayer.controls.scrubber { log.debug("stopTrickPlayTracking()"); if (_trickPlayTrackTimer) { _trickPlayTrackTimer.stop(); + _trickPlayTrackTimer.addEventListener(TimerEvent.TIMER, onTrickPlayProgress); + _trickPlayTrackTimer = null; } } private function startTrickPlayTracking():void { log.debug("startTrickPlayTracking()"); - if (_trickPlayTrackTimer) { - _trickPlayTrackTimer.stop(); - } + stopTrickPlayTracking(); _trickPlayTrackTimer = new Timer(200); _trickPlayTrackTimer.addEventListener(TimerEvent.TIMER, onTrickPlayProgress); _trickPlayTrackTimer.start(); @@ -232,15 +233,6 @@ package org.flowplayer.controls.scrubber { return; } - if (_seekInProgress) { - log.debug("doStart(), seek in progress, returning"); - return; - } - - if (! _player.isPlaying()) { - log.debug("doStart(), not playing, returning"); - return; - } if (_startDetectTimer && _startDetectTimer.running) { log.debug("doStart(), not playing, returning"); return; @@ -254,20 +246,22 @@ package org.flowplayer.controls.scrubber { var time:Number = startTime > 0 ? startTime : status.time; _startDetectTimer = new Timer(200); + //#163 set weak listener and clear the timer when done. _startDetectTimer.addEventListener(TimerEvent.TIMER, function(event:TimerEvent):void { var currentTime:Number = _player.status.time; - log.debug("on startDetectTimer() currentTime " + currentTime + ", time " + time); +// log.debug("on startDetectTimer() currentTime " + currentTime + ", time " + time); if (Math.abs(currentTime - time) > 0.2) { _startDetectTimer.stop(); + _startDetectTimer = null; var endPos:Number = width - _dragger.width; - log.debug("animation duration is " + clip.duration + " - "+ time + " * 1000"); +// log.debug("animation duration is " + clip.duration + " - "+ time + " * 1000"); // var duration:Number = (clip.duration - time) * 1000; var duration:Number = (clip.duration - currentTime) * 1000; updateDraggerPos(currentTime, clip); - log.debug("doStart(), starting an animation to x pos " + endPos + ", the duration is " + duration + ", current pos is " + _dragger.x + ", time is "+ currentTime); +// log.debug("doStart(), starting an animation to x pos " + endPos + ", the duration is " + duration + ", current pos is " + _dragger.x + ", time is "+ currentTime); animationEngine.animateProperty(_dragger, "x", endPos, duration, null, function():void { @@ -276,10 +270,8 @@ package org.flowplayer.controls.scrubber { function(t:Number, b:Number, c:Number, d:Number):Number { return c * t / d + b; }); - } else { - log.debug("not started yet, currentTime " + currentTime + ", time " + time); } - }); + }, false, 0, true); log.debug("doStart(), starting timer"); _startDetectTimer.start(); } @@ -301,6 +293,8 @@ package org.flowplayer.controls.scrubber { log.debug("stop()"); if (_startDetectTimer) { _startDetectTimer.stop(); + //#163 set weak listener and clear the timer when done. + _startDetectTimer = null; } animationEngine.cancel(_dragger); } @@ -361,10 +355,12 @@ package org.flowplayer.controls.scrubber { private function createBars():void { _progressBar = new Sprite(); + _progressBar.name = "progressBar"; addChild(_progressBar); _bufferBar = new Sprite(); addChild(_bufferBar); + _bufferBar.name = "bufferBar"; swapChildren(_dragger, _bufferBar); } @@ -424,13 +420,17 @@ package org.flowplayer.controls.scrubber { if (_isSeekPaused) { _player.resume(true); - seekToScrubberValue(false); + //seekToScrubberValue(false); _isSeekPaused = false; - return; - } - if (_player.isPaused()) { - _currentClip.dispatchEvent(new ClipEvent(ClipEventType.SEEK, value)); + //return; } + + //#104 when completing a seek click or drag, do a final non silent seek request when both paused and resuming playback from a paused seek. + seekToScrubberValue(false); + //else if (_player.isPaused()) { + //seekToScrubberValue(false); + //_currentClip.dispatchEvent(new ClipEvent(ClipEventType.SEEK, value)); + //} } //#321 set an maximum end seek limit or else playback completion may fail diff --git a/plugins/controls/src/actionscript/org/flowplayer/controls/time/TimeViewController.as b/plugins/controls/src/actionscript/org/flowplayer/controls/time/TimeViewController.as index b9a9519..db3d253 100644 --- a/plugins/controls/src/actionscript/org/flowplayer/controls/time/TimeViewController.as +++ b/plugins/controls/src/actionscript/org/flowplayer/controls/time/TimeViewController.as @@ -72,6 +72,8 @@ package org.flowplayer.controls.time { override protected function addPlayerListeners():void { super.addPlayerListeners(); _player.playlist.onSeek(function(event:ClipEvent):void { onTimeUpdate(null); }); + //#145 there is no seek complete event use the metadata change to update the time when seeking when paused with rtmp. + _player.playlist.onMetaDataChange(function(event:ClipEvent):void { onTimeUpdate(null); }); _player.playlist.onBeforeFinish(durationReached); } diff --git a/plugins/f4m/README.txt b/plugins/f4m/README.txt index 3e62e91..cdfdfc4 100644 --- a/plugins/f4m/README.txt +++ b/plugins/f4m/README.txt @@ -1,3 +1,9 @@ +3.2.10 +------ +- New code requires to be compiled against OSMF 2.0 +- fixes for osmf dateutil class +- #99 add isDefault bitrate config option + 3.2.9 ----- - http://code.google.com/p/flowplayer-core/issues/detail?id=486 diff --git a/plugins/f4m/build.properties b/plugins/f4m/build.properties index 2d8dec7..5d1e2d5 100644 --- a/plugins/f4m/build.properties +++ b/plugins/f4m/build.properties @@ -1,3 +1,3 @@ devkit-dir=../../lib/devkit osmf-dir=../../lib/osmf/framework/OSMF -version=3.2.9 +version=3.2.10 diff --git a/plugins/f4m/build.xml b/plugins/f4m/build.xml index 98445be..74f1dc0 100644 --- a/plugins/f4m/build.xml +++ b/plugins/f4m/build.xml @@ -7,11 +7,14 @@ - - + + + + + diff --git a/plugins/f4m/src/actionscript/org/flowplayer/f4m/F4mProvider.as b/plugins/f4m/src/actionscript/org/flowplayer/f4m/F4mProvider.as index f4139ac..03c55bc 100644 --- a/plugins/f4m/src/actionscript/org/flowplayer/f4m/F4mProvider.as +++ b/plugins/f4m/src/actionscript/org/flowplayer/f4m/F4mProvider.as @@ -11,8 +11,8 @@ package org.flowplayer.f4m { import flash.events.NetStatusEvent; -import flash.events.TimerEvent; -import flash.utils.Timer; + import flash.events.TimerEvent; + import flash.utils.Timer; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginModel; @@ -154,6 +154,7 @@ import flash.utils.Timer; if (itemConfig.hasOwnProperty("label")) bitrateItem.label = itemConfig.label; if (itemConfig.hasOwnProperty("sd")) bitrateItem.sd = itemConfig.sd; if (itemConfig.hasOwnProperty("hd")) bitrateItem.hd = itemConfig.hd; + if (itemConfig.hasOwnProperty("isDefault")) bitrateItem.isDefault = itemConfig.isDefault as Boolean; } bitrateItems.push(bitrateItem); @@ -197,13 +198,20 @@ import flash.utils.Timer; { log.debug("F4M Manifest Finished"); - try - { + //#493 add option to include application instance for rtmp base urls. if (!manifest.urlIncludesFMSApplicationInstance && manifest.baseURL) manifest.urlIncludesFMSApplicationInstance = _config.includeApplicationInstance; - netResource = parser.createResource(manifest, new URLResource(_clip.completeUrl)); + try + { + netResource = parser.createResource(manifest, new URLResource(_clip.completeUrl)); + } + catch (error:Error) + { + handleStreamNotFound(error.message); + return; + } if (netResource is DynamicStreamingResource) { dynResource = netResource as DynamicStreamingResource; @@ -236,11 +244,7 @@ import flash.utils.Timer; _successListener(_clip); } - } - catch (error:Error) - { - handleStreamNotFound(error.message); - } + } /** diff --git a/plugins/f4m/src/actionscript/org/osmf/utils/DateUtil.as b/plugins/f4m/src/actionscript/org/osmf/utils/DateUtil.as new file mode 100644 index 0000000..5ded526 --- /dev/null +++ b/plugins/f4m/src/actionscript/org/osmf/utils/DateUtil.as @@ -0,0 +1,174 @@ +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.utils +{ + [ExcludeClass] + + /** + * @private + * + * Class that contains static utility methods for manipulating and working + * with Dates. + * + * @langversion ActionScript 3.0 + * @playerversion Flash 9.0 + * @tiptext + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public class DateUtil + { + /** + * Parses dates that conform to the W3C Date-time Format into Date objects. + * + * This function is useful for parsing RSS 1.0 and Atom 1.0 dates. + * + * @param str + * + * @returns + * + * @langversion ActionScript 3.0 + * @playerversion Flash 9.0 + * @tiptext + * + * @see http://www.w3.org/TR/NOTE-datetime + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + public static function parseW3CDTF(str:String):Date + { + var parsedDate:Date = null; + try + { + parsedDate = parseW3CDTFInternal(str); + } + catch (e:Error) + { + throw new Error("Unable to parse the string [" + str + "] into a date. " + "The internal error was: " + e.toString()); + } + + return parsedDate; + } + + // Internals + // + + private static function parseW3CDTFInternal(dateStr:String):Date + { + var expression:RegExp = /^ (\d\d\d\d) (?: - (\d\d) (?: - (\d\d) (?: T (\d\d) (?: : (\d\d) (?: : (\d\d (?: \.\d* )? ) )? )? )? (?: Z | ([+-]) (\d\d) : (\d\d) )? )? )? $/x; + + if (!dateStr) + { + throw new Error(PARSING_ERROR_STR); + } + + var matches:Object = expression.exec(dateStr); + + if (!matches) + { + throw new Error(PARSING_ERROR_STR); + } + + function getMatch(matchNo:Number, minAllowedValue:Number, maxAllowedValue:Number):Number + { + var match:String = matches[matchNo]; + if (!match) + { + return minAllowedValue; + } + + var matchValue:Number = Number(match); + if (matchValue < minAllowedValue || matchValue > maxAllowedValue) + { + throw new Error(PARSING_ERROR_STR); + } + + return matchValue; + } + + // get date components + var year:Number = getMatch(GROUP_INDEX_YEAR, 0, 9999); + var month:Number = getMatch(GROUP_INDEX_MONTH, 1, 12); + var lastDayInCurrentMonth:Number = getLastDayInMonth(year, month); + var day:Number = getMatch(GROUP_INDEX_DAY, 1, lastDayInCurrentMonth); + var hour:Number = getMatch(GROUP_INDEX_HOUR, 0, 23); + var minutes:Number = getMatch(GROUP_INDEX_MINUTE, 0, 59); + var secondsAndMilliseconds:Number = getMatch(GROUP_INDEX_SECOND, 0, 59.99999999999); + var seconds:Number = Math.floor(secondsAndMilliseconds); + var milliseconds:Number = Math.floor(secondsAndMilliseconds * 1000 % 1000); + var tzSign:String = matches[GROUP_INDEX_TZ]; + var offsetMilliseconds:Number = 0; + + // get the timezone offset + if (tzSign) + { + var offsetHours:Number = getMatch(GROUP_INDEX_OFFSET_HOURS, 0, 23); + var offsetMinutes:Number = getMatch(GROUP_INDEX_OFFSET_MINUTES, 0, 59); + + offsetMilliseconds = (offsetHours * 60 + offsetMinutes) * 60 * 1000; + if (tzSign == '-') + { + offsetMilliseconds = offsetMilliseconds * -1; + } + } + + // convert the date to milliseconds and adjust it using the timezone offset + var utc:Number = Date.UTC(year, month - 1, day, hour, minutes, seconds, milliseconds); + var parsedDate:Date = new Date(utc - offsetMilliseconds); + + // check the parsed date validity + if (parsedDate.toString() == "Invalid Date") + { + throw new Error(PARSING_ERROR_STR); + } + + return parsedDate; + } + + private static function getLastDayInMonth(year:Number, month:Number):Number + { + var dt:Date = new Date(year, month, 0); + + return dt.date; + } + + private static const PARSING_ERROR_STR:String = "This date does not conform to W3CDTF."; + + private static const GROUP_INDEX_YEAR:Number = 1; + private static const GROUP_INDEX_MONTH:Number = 2; + private static const GROUP_INDEX_DAY:Number = 3; + private static const GROUP_INDEX_HOUR:Number = 4; + private static const GROUP_INDEX_MINUTE:Number = 5; + private static const GROUP_INDEX_SECOND:Number = 6; + private static const GROUP_INDEX_TZ:Number = 7; + + //flowplayer additions - fixes to type bug + private static const GROUP_INDEX_OFFSET_HOURS:Number = 8; + private static const GROUP_INDEX_OFFSET_MINUTES:Number = 9; + } +} diff --git a/plugins/httpstreaming-hls/LICENSE.txt b/plugins/httpstreaming-hls/LICENSE.txt deleted file mode 100644 index 7f04a62..0000000 --- a/plugins/httpstreaming-hls/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) 2009 Flowplayer Ltd - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/plugins/httpstreaming-hls/README-swc.txt b/plugins/httpstreaming-hls/README-swc.txt deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/httpstreaming-hls/README.txt b/plugins/httpstreaming-hls/README.txt deleted file mode 100644 index d478195..0000000 --- a/plugins/httpstreaming-hls/README.txt +++ /dev/null @@ -1,10 +0,0 @@ -Installation Instructions: - -The Apple Http Live Streaming features come from http://code.google.com/p/apple-http-osmf/ with some refactored modifications for multi bitrate support available in the swc library for now. - -1) Checkout OSMF 2.0 Source http://www.osmf.org/source.html or download here http://sourceforge.net/projects/osmf.adobe/files/OSMF%202.0%20Release%20%28final%20source%2C%20ASDocs%2C%20pdf%20guides%20and%20release%20notes%29/ -2) Change the location of the build property osmf-dir to the location of the osmf 2.0 checkout or download. -3) Run ant example -4) Load example in build/example/index.html - -Examples available at http://flowplayer.electroteque.org/httpstreaminghls \ No newline at end of file diff --git a/plugins/httpstreaming-hls/build.properties b/plugins/httpstreaming-hls/build.properties deleted file mode 100644 index 6adb059..0000000 --- a/plugins/httpstreaming-hls/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -devkit-dir=../../lib/devkit -osmf-dir=/www/Flash/osmf/framework/OSMF -apple-osmf-dir=/www/Flash/flowplayer/apple-osmf/src -version=3.2.10 diff --git a/plugins/httpstreaming-hls/build.xml b/plugins/httpstreaming-hls/build.xml deleted file mode 100644 index 8b0d0e8..0000000 --- a/plugins/httpstreaming-hls/build.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/httpstreaming-hls/example/flowplayer-3.2.11.min.js b/plugins/httpstreaming-hls/example/flowplayer-3.2.11.min.js deleted file mode 100644 index 4cb5d93..0000000 --- a/plugins/httpstreaming-hls/example/flowplayer-3.2.11.min.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * flowplayer.js 3.2.11. The Flowplayer API - * - * Copyright 2009-2011 Flowplayer Oy - * - * This file is part of Flowplayer. - * - * Flowplayer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Flowplayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Flowplayer. If not, see . - * - * Date: 2012-06-16 10:34:45 -0400 (Sat, 16 Jun 2012) - * Revision: 808 - */ -(function(){function g(o){console.log("$f.fireEvent",[].slice.call(o))}function k(q){if(!q||typeof q!="object"){return q}var o=new q.constructor();for(var p in q){if(q.hasOwnProperty(p)){o[p]=k(q[p])}}return o}function m(t,q){if(!t){return}var o,p=0,r=t.length;if(r===undefined){for(o in t){if(q.call(t[o],o,t[o])===false){break}}}else{for(var s=t[0];p1){var t=arguments[1],q=(arguments.length==3)?arguments[2]:{};if(typeof t=="string"){t={src:t}}t=i({bgcolor:"#000000",version:[10,1],expressInstall:"http://releases.flowplayer.org/swf/expressinstall.swf",cachebusting:false},t);if(typeof o=="string"){if(o.indexOf(".")!=-1){var s=[];m(n(o),function(){s.push(new b(this,k(t),k(q)))});return new d(s)}else{var r=c(o);return new b(r!==null?r:k(o),k(t),k(q))}}else{if(o){return new b(o,k(t),k(q))}}}return null};i(window.$f,{fireEvent:function(){var o=[].slice.call(arguments);var q=$f(o[0]);return q?q._fireEvent(o.slice(1)):null},addPlugin:function(o,p){b.prototype[o]=p;return $f},each:m,extend:i});if(typeof jQuery=="function"){jQuery.fn.flowplayer=function(q,p){if(!arguments.length||typeof arguments[0]=="number"){var o=[];this.each(function(){var r=$f(this);if(r){o.push(r)}});return arguments.length?o[arguments[0]]:new d(o)}return this.each(function(){$f(this,k(q),p?k(p):{})})}}})();(function(){var h=document.all,j="http://get.adobe.com/flashplayer",c=typeof jQuery=="function",e=/(\d+)[^\d]+(\d+)[^\d]*(\d*)/,b={width:"100%",height:"100%",id:"_"+(""+Math.random()).slice(9),allowfullscreen:true,allowscriptaccess:"always",quality:"high",version:[3,0],onFail:null,expressInstall:null,w3c:false,cachebusting:false};if(window.attachEvent){window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}})}function i(m,l){if(l){for(var f in l){if(l.hasOwnProperty(f)){m[f]=l[f]}}}return m}function a(f,n){var m=[];for(var l in f){if(f.hasOwnProperty(l)){m[l]=n(f[l])}}return m}window.flashembed=function(f,m,l){if(typeof f=="string"){f=document.getElementById(f.replace("#",""))}if(!f){return}if(typeof m=="string"){m={src:m}}return new d(f,i(i({},b),m),l)};var g=i(window.flashembed,{conf:b,getVersion:function(){var m,f;try{f=navigator.plugins["Shockwave Flash"].description.slice(16)}catch(o){try{m=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");f=m&&m.GetVariable("$version")}catch(n){try{m=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");f=m&&m.GetVariable("$version")}catch(l){}}}f=e.exec(f);return f?[1*f[1],1*f[(f[1]*1>9?2:3)]*1]:[0,0]},asString:function(l){if(l===null||l===undefined){return null}var f=typeof l;if(f=="object"&&l.push){f="array"}switch(f){case"string":l=l.replace(new RegExp('(["\\\\])',"g"),"\\$1");l=l.replace(/^\s?(\d+\.?\d*)%/,"$1pct");return'"'+l+'"';case"array":return"["+a(l,function(o){return g.asString(o)}).join(",")+"]";case"function":return'"function()"';case"object":var m=[];for(var n in l){if(l.hasOwnProperty(n)){m.push('"'+n+'":'+g.asString(l[n]))}}return"{"+m.join(",")+"}"}return String(l).replace(/\s/g," ").replace(/\'/g,'"')},getHTML:function(o,l){o=i({},o);var n=''}o.width=o.height=o.id=o.w3c=o.src=null;o.onFail=o.version=o.expressInstall=null;for(var m in o){if(o[m]){n+=''}}var p="";if(l){for(var f in l){if(l[f]){var q=l[f];p+=f+"="+(/function|object/.test(typeof q)?g.asString(q):q)+"&"}}p=p.slice(0,-1);n+='"}n+="";return n},isSupported:function(f){return k[0]>f[0]||k[0]==f[0]&&k[1]>=f[1]}});var k=g.getVersion();function d(f,n,m){if(g.isSupported(n.version)){f.innerHTML=g.getHTML(n,m)}else{if(n.expressInstall&&g.isSupported([6,65])){f.innerHTML=g.getHTML(i(n,{src:n.expressInstall}),{MMredirectURL:encodeURIComponent(location.href),MMplayerType:"PlugIn",MMdoctitle:document.title})}else{if(!f.innerHTML.replace(/\s/g,"")){f.innerHTML="

      Flash version "+n.version+" or greater is required

      "+(k[0]>0?"Your version is "+k:"You have no flash plugin installed")+"

      "+(f.tagName=="A"?"

      Click here to download latest version

      ":"

      Download latest version from here

      ");if(f.tagName=="A"||f.tagName=="DIV"){f.onclick=function(){location.href=j}}}if(n.onFail){var l=n.onFail.call(this);if(typeof l=="string"){f.innerHTML=l}}}}if(h){window[n.id]=document.getElementById(n.id)}i(this,{getRoot:function(){return f},getOptions:function(){return n},getConf:function(){return m},getApi:function(){return f.firstChild}})}if(c){jQuery.tools=jQuery.tools||{version:"3.2.11"};jQuery.tools.flashembed={conf:b};jQuery.fn.flashembed=function(l,f){return this.each(function(){$(this).data("flashembed",flashembed(this,l,f))})}}})(); \ No newline at end of file diff --git a/plugins/httpstreaming-hls/example/flowplayer.ipad-3.2.12.min.js b/plugins/httpstreaming-hls/example/flowplayer.ipad-3.2.12.min.js deleted file mode 100644 index 80dee70..0000000 --- a/plugins/httpstreaming-hls/example/flowplayer.ipad-3.2.12.min.js +++ /dev/null @@ -1 +0,0 @@ -$f.addPlugin("ipad",function(y){var S=-1;var z=0;var A=1;var P=2;var E=3;var L=4;var j=5;var i=this;var U=1;var T=false;var I=false;var v=false;var s=0;var R=[];var l;var t=null;var d=0;var f={accelerated:false,autoBuffering:false,autoPlay:true,baseUrl:null,bufferLength:3,connectionProvider:null,cuepointMultiplier:1000,cuepoints:[],controls:{},duration:0,extension:"",fadeInSpeed:1000,fadeOutSpeed:1000,image:false,linkUrl:null,linkWindow:"_self",live:false,metaData:{},originalUrl:null,position:0,playlist:[],provider:"http",scaling:"scale",seekableOnBegin:false,start:0,url:null,urlResolvers:[]};var x=S;var r=S;var u=/iPad|iPhone|iPod/i.test(navigator.userAgent);var c=null;function n(Y,X,V){if(X){for(key in X){if(key){if(X[key]&&typeof X[key]=="function"&&!V){continue}if(X[key]&&typeof X[key]=="object"&&X[key].length===undefined){var W={};n(W,X[key]);Y[key]=W}else{Y[key]=X[key]}}}}return Y}var B={simulateiDevice:false,controlsSizeRatio:1.5,controls:true,debug:false,validExtensions:"mov|m4v|mp4|avi|mp3|m4a|aac|m3u8|m3u|pls",posterExtensions:"png|jpg"};n(B,y);var b=B.validExtensions?new RegExp("^.("+B.validExtensions+")$","i"):null;var e=new RegExp("^.("+B.posterExtensions+")$","i");function h(){if(B.debug){if(u){var V=[].splice.call(arguments,0).join(", ");console.log.apply(console,[V])}else{console.log.apply(console,arguments)}}}function m(V){switch(V){case -1:return"UNLOADED";case 0:return"LOADED";case 1:return"UNSTARTED";case 2:return"BUFFERING";case 3:return"PLAYING";case 4:return"PAUSED";case 5:return"ENDED"}return"UNKOWN"}function J(V){var W=$f.fireEvent(i.id(),"onBefore"+V,s);return W!==false}function O(V){V.stopPropagation();V.preventDefault();return false}function M(W,V){if(x==S&&!V){return}r=x;x=W;D();if(W==E){p()}h(m(W))}function C(){c.fp_stop();T=false;I=false;v=false;M(A);M(A)}var g=null;function p(){if(g){return}console.log("starting tracker");g=setInterval(G,100);G()}function D(){clearInterval(g);g=null}function G(){var W=Math.floor(c.fp_getTime()*10)*100;var X=Math.floor(c.duration*10)*100;var Y=(new Date()).time;function V(ab,Z){ab=ab>=0?ab:X-Math.abs(ab);for(var aa=0;aaY){Z[aa].lastTimeFired=-1}else{if(Z[aa].lastTimeFired+500>Y){continue}else{if(ab==W||(W-500ab)){Z[aa].lastTimeFired=Y;$f.fireEvent(i.id(),"onCuepoint",s,Z[aa].fnId,Z[aa].parameters)}}}}}$f.each(i.getCommonClip().cuepoints,V);$f.each(R[s].cuepoints,V)}function H(){C();v=true;c.fp_seek(0)}function N(V){}function q(){console.log(c);function V(X){var W={};n(W,f);n(W,i.getCommonClip());n(W,X);if(W.ipadUrl){url=decodeURIComponent(W.ipadUrl)}else{if(W.url){url=W.url}}if(url&&url.indexOf("://")==-1&&W.ipadBaseUrl){url=W.ipadBaseUrl+"/"+url}else{if(url&&url.indexOf("://")==-1&&W.baseUrl){url=W.baseUrl+"/"+url}}W.originalUrl=W.url;W.completeUrl=url;W.extension=W.completeUrl.substr(W.completeUrl.lastIndexOf("."));var Y=W.extension.indexOf("?");if(Y>-1){W.extension=W.extension.substr(0,Y)}W.type="video";delete W.index;h("fixed clip",W);return W}c.fp_play=function(Z,X,ab,ac){var W=null;var aa=true;var Y=true;h("Calling play() "+Z,Z);if(X){h("ERROR: inStream clips not yet supported");return}if(Z!==undefined){if(typeof Z=="number"){if(s>=R.length){return}s=Z;Z=R[s]}else{if(typeof Z=="string"){Z={url:Z}}c.fp_setPlaylist(Z.length!==undefined?Z:[Z])}if(s==0&&R.length>1&&e.test(R[s].extension)){var ac=R[s].url;console.log("Poster image available with url "+ac);++s;console.log("Not last clip in the playlist, moving to next one");c.fp_play(s,false,true,ac);return}if(b&&!b.test(R[s].extension)){return}Z=R[s];W=Z.completeUrl;if(Z.autoBuffering!==undefined&&Z.autoBuffering===false){aa=false}if(Z.autoPlay===undefined||Z.autoPlay===true||ab===true){aa=true;Y=true}else{Y=false}}else{h("clip was not given, simply calling video.play, if not already buffering");if(x!=P){c.play()}return}h("about to play "+W,aa,Y);C();if(W){h("Changing SRC attribute"+W);c.setAttribute("src",W)}if(aa){if(!J("Begin")){return false}if(ac){Y=Z.autoPlay;c.setAttribute("poster",ac);c.setAttribute("preload","none")}$f.fireEvent(i.id(),"onBegin",s);h("calling video.load()");c.load()}if(Y){h("calling video.play()");c.play()}};c.fp_pause=function(){h("pause called");if(!J("Pause")){return false}c.pause()};c.fp_resume=function(){h("resume called");if(!J("Resume")){return false}c.play()};c.fp_stop=function(){h("stop called");if(!J("Stop")){return false}I=true;c.pause();try{c.currentTime=0}catch(W){}};c.fp_seek=function(W){h("seek called "+W);if(!J("Seek")){return false}var aa=0;var W=W+"";if(W.charAt(W.length-1)=="%"){var X=parseInt(W.substr(0,W.length-1))/100;var Z=c.duration;aa=Z*X}else{aa=W}try{c.currentTime=aa}catch(Y){h("Wrong seek time")}};c.fp_getTime=function(){return c.currentTime};c.fp_mute=function(){h("mute called");if(!J("Mute")){return false}U=c.volume;c.volume=0};c.fp_unmute=function(){if(!J("Unmute")){return false}c.volume=U};c.fp_getVolume=function(){return c.volume*100};c.fp_setVolume=function(W){if(!J("Volume")){return false}c.volume=W/100};c.fp_toggle=function(){h("toggle called");if(i.getState()==j){H();return}if(c.paused){c.fp_play()}else{c.fp_pause()}};c.fp_isPaused=function(){return c.paused};c.fp_isPlaying=function(){return !c.paused};c.fp_getPlugin=function(X){if(X=="canvas"||X=="controls"){var W=i.getConfig();return W.plugins&&W.plugins[X]?W.plugins[X]:null}h("ERROR: no support for "+X+" plugin on iDevices");return null};c.fp_close=function(){M(S);c.parentNode.removeChild(c);c=null};c.fp_getStatus=function(){var X=0;var Y=0;try{X=c.buffered.start();Y=c.buffered.end()}catch(W){}return{bufferStart:X,bufferEnd:Y,state:x,time:c.fp_getTime(),muted:c.muted,volume:c.fp_getVolume()}};c.fp_getState=function(){return x};c.fp_startBuffering=function(){if(x==A){c.load()}};c.fp_setPlaylist=function(X){h("Setting playlist");s=0;for(var W=0;W0){ak=R[s].duration;t=ak+d}else{ak=c.duration;t=null}c.fp_updateClip({duration:ak,metaData:{duration:c.duration}},s);R[s].duration=c.duration;R[s].metaData={duration:c.duration};$f.fireEvent(i.id(),"onMetaData",s,R[s])};c.addEventListener("loadedmetadata",Y,false);c.addEventListener("durationchange",Y,false);var W=function(ak){if(t&&c.currentTime>t){c.fp_seek(d);C();return O(ak)}};c.addEventListener("timeupdate",W,false);var ah=function(ak){if(x==L){if(!J("Resume")){h("Resume disallowed, pausing");c.fp_pause();return O(ak)}$f.fireEvent(i.id(),"onResume",s)}M(E);if(!T){T=true;$f.fireEvent(i.id(),"onStart",s)}};c.addEventListener("playing",ah,false);var V=function(ak){F()};c.addEventListener("play",V,false);var ae=function(ak){if(!J("Finish")){if(R.length==1){h("Active playlist only has one clip, onBeforeFinish returned false. Replaying");H()}else{if(s!=(R.length-1)){h("Not the last clip in the playlist, but onBeforeFinish returned false. Returning to the beginning of current clip");c.fp_seek(0)}else{h("Last clip in playlist, but onBeforeFinish returned false, start again from the beginning");c.fp_play(0)}}return O(ak)}M(j);$f.fireEvent(i.id(),"onFinish",s);if(R.length>1&&s<(R.length-1)){h("Not last clip in the playlist, moving to next one");c.fp_play(++s,false,true)}};c.addEventListener("ended",ae,false);var ad=function(ak){M(z,true);$f.fireEvent(i.id(),"onError",s,201);if(B.onFail&&B.onFail instanceof Function){B.onFail.apply(i,[])}};c.addEventListener("error",ad,false);var ag=function(ak){h("got pause event from player"+i.id());if(I){return}if(x==P&&r==A){h("forcing play");setTimeout(function(){c.play()},0);return}if(!J("Pause")){c.fp_resume();return O(ak)}Q();M(L);$f.fireEvent(i.id(),"onPause",s)};c.addEventListener("pause",ag,false);var aj=function(ak){$f.fireEvent(i.id(),"onBeforeSeek",s)};c.addEventListener("seeking",aj,false);var ab=function(ak){if(I){I=false;$f.fireEvent(i.id(),"onStop",s)}else{$f.fireEvent(i.id(),"onSeek",s)}h("seek done, currentState",m(x));if(v){v=false;c.fp_play()}else{if(x!=E){c.fp_pause()}}};c.addEventListener("seeked",ab,false);var af=function(ak){$f.fireEvent(i.id(),"onVolume",c.fp_getVolume())};c.addEventListener("volumechange",af,false)}function F(){l=setInterval(function(){if(c.fp_getTime()>=c.duration-1){$f.fireEvent(i.id(),"onLastSecond",s);Q()}},100)}function Q(){clearInterval(l)}function o(){c.fp_play(0)}function w(){}if(u||B.simulateiDevice){if(!window.flashembed.__replaced){var k=window.flashembed;window.flashembed=function(X,ac,Y){if(typeof X=="string"){X=document.getElementById(X.replace("#",""))}if(!X){return}var ab=window.getComputedStyle(X,null);var aa=parseInt(ab.width);var V=parseInt(ab.height);while(X.firstChild){X.removeChild(X.firstChild)}var W=document.createElement("div");var Z=document.createElement("video");W.appendChild(Z);X.appendChild(W);W.style.height=V+"px";W.style.width=aa+"px";W.style.display="block";W.style.position="relative";W.style.background="-webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.7)))";W.style.cursor="default";W.style.webkitUserDrag="none";Z.style.height="100%";Z.style.width="100%";Z.style.display="block";Z.id=ac.id;Z.name=ac.id;Z.style.cursor="pointer";Z.style.webkitUserDrag="none";Z.type="video/mp4";Z.playerConfig=Y.config;$f.fireEvent(Y.config.playerId,"onLoad","player")};flashembed.getVersion=k.getVersion;flashembed.asString=k.asString;flashembed.isSupported=function(){return true};flashembed.__replaced=true}var a=i._fireEvent;i._fireEvent=function(V){if(V[0]=="onLoad"&&V[1]=="player"){c=i.getParent().querySelector("video");if(B.controls){c.controls="controls"}q();K();M(z,true);c.fp_setPlaylist(c.playerConfig.playlist);o();a.apply(i,[V])}var W=x!=S;if(x==S&&typeof V=="string"){W=true}if(W){return a.apply(i,[V])}};i._swfHeight=function(){return parseInt(c.style.height)};i.hasiPadSupport=function(){return true}}return i}); \ No newline at end of file diff --git a/plugins/httpstreaming-hls/example/index.html.tmpl b/plugins/httpstreaming-hls/example/index.html.tmpl deleted file mode 100644 index 70c6391..0000000 --- a/plugins/httpstreaming-hls/example/index.html.tmpl +++ /dev/null @@ -1,311 +0,0 @@ - - - - - - - - Flowplayer - Flash Video Player for the Web - - - - - - - - - - - - - - - -
      - - - - -
      - - - - - - - - -

      - Apple HTTP Live Streaming - Play Apple HTTP Live Streaming within Flowplayer -

      - - - - - -

      Introduction

      - - -

      Examples

      - - - -

      Basic example with a single bitrate

      - -

      - -

      - - -
      - - - - - - - - - - - - - - - -
      - -
      -
      
      -flowplayer("player", "@PLAYER_SWF@", {
      -    // configure the required plugins
      -    plugins:  {
      -
      -        httpstreaming: {
      -            url: '@MAIN_PLAYER_SWF@'
      -        }
      -    },
      -
      -
      -    clip: {
      -        url: "http://184.72.239.149/vod/smil:bigbuckbunnyiphone.smil/chunklist-b400000.m3u8",
      -        ipadUrl: "http://184.72.239.149/vod/smil:bigbuckbunnyiphone.smil/chunklist-b400000.m3u8",
      -        urlResolvers: ["httpstreaming","brselect"],
      -        provider: "httpstreaming",
      -        autoPlay: false
      -    },
      -    log: {
      -        level: 'debug',
      -        filter: 'org.osmf.*, org.electroteque.m3u8.*, org.flowplayer.bitrateselect.*'
      -    }
      -
      -}).ipad();
      -
      -
      -
      - - -

      Multi bitrate example with menu selection.

      - -

      - -

      - - -
      - - - - - - - - - - -
      - -
      -
      
      -flowplayer("player", "@PLAYER_SWF@", {
      -    // configure the required plugins
      -    plugins:  {
      -
      -        httpstreaming: {
      -            url: '@MAIN_PLAYER_SWF@',
      -
      -
      -        },
      -        menu: {
      -            url: "flowplayer.menu.swf",
      -            items: [
      -                                        // you can have an optional label as the first item
      -                                        // the bitrate specific items are filled here based on the clip's bitrates
      -                                        { label: "select bitrate:", enabled: false }
      -                                    ]
      -        },
      -        brselect: {
      -            url: "flowplayer.bitrateselect.swf",
      -            menu: true,
      -            onStreamSwitchBegin: function (newItem, currentItem) {
      -                $f("bitrate").getPlugin('content').setHtml("Will switch to: " + newItem.streamName +
      -                    " from " + currentItem.streamName);
      -            },
      -            onStreamSwitch: function (newItem) {
      -                $f("bitrate").getPlugin('content').setHtml("Switched to: " + newItem.streamName + " with bitrate: " + newItem.bitrate);
      -            }
      -        },
      -        content: {
      -                            url: 'flowplayer.content.swf',
      -                            bottom: 30, left: 0, width: 250, height: 150,
      -                            backgroundColor: 'transparent', backgroundGradient: 'none', border: 0,
      -                            textDecoration: 'outline',
      -                            style: {
      -                                body: {
      -                                    fontSize: 14,
      -                                    fontFamily: 'Arial',
      -                                    textAlign: 'center',
      -                                    color: '#ffffff'
      -                                }
      -                            }
      -        }
      -
      -    },
      -
      -
      -    clip: {
      -        url: "http://184.72.239.149/vod/smil:bigbuckbunnyiphone.smil/playlist.m3u8",
      -        ipadUrl: "http://184.72.239.149/vod/smil:bigbuckbunnyiphone.smil/playlist.m3u8",
      -        urlResolvers: ["httpstreaming","brselect"],
      -        provider: "httpstreaming",
      -        autoPlay: false,
      -        bitrates: {
      -            labels: { "300": "Low", "400": "Medium", "600": "High"  },
      -            default: 400
      -        },
      -    },
      -    log: {
      -        level: 'debug',
      -        filter: 'org.osmf.*, org.electroteque.m3u8.*, org.flowplayer.bitrateselect.*'
      -    }
      -
      -}).ipad();
      -
      -
      -
      - - -
      - -
      - - - - diff --git a/plugins/httpstreaming-hls/lib/apple-osmf.swc b/plugins/httpstreaming-hls/lib/apple-osmf.swc deleted file mode 100644 index c29b3f7..0000000 Binary files a/plugins/httpstreaming-hls/lib/apple-osmf.swc and /dev/null differ diff --git a/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/Config.as b/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/Config.as deleted file mode 100644 index 04ee9f6..0000000 --- a/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/Config.as +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * By: Daniel Rossi, - * Copyright (c) 2012 Electroteque Media - * - * Released under the MIT License: - * http://www.opensource.org/licenses/mit-license.php - */ -package org.electroteque.m3u8 { - - public class Config { - private var _retryInterval:int = 10; - private var _maxRetries:int = 100; - - public function set retryInterval(value:int):void - { - _retryInterval = value; - } - - public function get retryInterval():int - { - return _retryInterval * 1000; - } - - public function set maxRetries(value:int):void - { - _maxRetries = value; - } - - public function get maxRetries():int - { - return _maxRetries; - } - } -} diff --git a/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/HttpStreamingHlsPlugin.as b/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/HttpStreamingHlsPlugin.as deleted file mode 100644 index fc34d01..0000000 --- a/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/HttpStreamingHlsPlugin.as +++ /dev/null @@ -1,23 +0,0 @@ -/* - * - * By: Daniel Rossi, - * Copyright (c) 2012 Electroteque Media - * - * Released under the MIT License: - * http://www.opensource.org/licenses/mit-license.php - */ -package org.electroteque.m3u8 { - import org.flowplayer.model.PluginFactory; - import flash.display.Sprite; - - public class HttpStreamingHlsPlugin extends Sprite implements PluginFactory { - - public function HttpStreamingHlsPlugin() { - - } - - public function newPlugin():Object { - return new HttpStreamingHlsProvider(); - } - } -} \ No newline at end of file diff --git a/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/HttpStreamingHlsProvider.as b/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/HttpStreamingHlsProvider.as deleted file mode 100644 index 347c70d..0000000 --- a/plugins/httpstreaming-hls/src/actionscript/org/electroteque/m3u8/HttpStreamingHlsProvider.as +++ /dev/null @@ -1,534 +0,0 @@ -/* - * - * By: Daniel Rossi, - * Copyright (c) 2012 Electroteque Media - * - * The Initial Developer of the Apple-OSMF feature is Matthew Kaufman http://code.google.com/p/apple-http-osmf/ - * - * Released under the MIT License: - * http://www.opensource.org/licenses/mit-license.php - */ -package org.electroteque.m3u8 { - - import org.flowplayer.model.Clip; - import org.flowplayer.model.ClipError; - import org.flowplayer.model.ErrorCode; - import org.flowplayer.model.ClipType; - import org.flowplayer.model.ClipEventType; - import org.flowplayer.model.ClipEvent; - import org.flowplayer.controller.NetStreamControllingStreamProvider; - import org.flowplayer.model.Plugin; - import org.flowplayer.model.PluginModel; - import org.flowplayer.util.PropertyBinder; - import org.flowplayer.view.ErrorHandler; - import org.flowplayer.view.Flowplayer; - import org.flowplayer.controller.StreamProvider; - import org.flowplayer.controller.ClipURLResolver; - import org.flowplayer.controller.ResourceLoader; - import org.flowplayer.net.BitrateItem; - - import flash.events.NetStatusEvent; - import flash.net.NetStream; - import flash.net.NetConnection; - import flash.events.TimerEvent; - import flash.utils.Timer; - - import at.matthew.httpstreaming.parser.HttpStreamingM3U8ManifestParser; - import at.matthew.httpstreaming.model.HttpStreamingM3U8Manifest; - import at.matthew.httpstreaming.HTTPStreamingM3U8Factory; - - import org.osmf.media.MediaResourceBase; - import org.osmf.media.URLResource; - - import org.osmf.events.ParseEvent; - - import org.osmf.net.DynamicStreamingResource; - import org.osmf.net.DynamicStreamingItem; - import org.osmf.net.StreamingURLResource; - - import org.osmf.net.httpstreaming.HTTPNetStream; - - public class HttpStreamingHlsProvider extends NetStreamControllingStreamProvider implements ClipURLResolver, ErrorHandler, Plugin { - protected var _bufferStart:Number; - protected var _config:Config; - protected var _startSeekDone:Boolean; - protected var _model:PluginModel; - protected var _player:Flowplayer; - protected var _clip:Clip; - protected var _currentClip:Clip; - protected var _previousClip:Clip; - protected var manifest:HttpStreamingM3U8Manifest; - protected var parser:HttpStreamingM3U8ManifestParser; - protected var resource:MediaResourceBase; - protected var netResource:URLResource; - protected var dynResource:DynamicStreamingResource; - protected var streamResource:StreamingURLResource; - protected var _isDynamicStreamResource:Boolean = false; - protected var _successListener:Function; - protected var _retryTimer:Timer; - protected var _retryCount:int; - - /** - * @inherit - * @param model - */ - override public function onConfig(model:PluginModel):void { - _model = model; - _config = new PropertyBinder(new Config(), null).copyProperties(model.config) as Config; - } - - /** - * load event - * @param player - */ - override public function onLoad(player:Flowplayer):void { - log.info("onLoad()"); - _player = player; - _model.dispatchOnLoad(); - } - - /** - * configure clip url - * @param clip - * @return - */ - override protected function getClipUrl(clip:Clip):String { - return clip.completeUrl; - } - - /** - * load new stream - * @param event - * @param netStream - * @param clip - */ - override protected function doLoad(event:ClipEvent, netStream:NetStream, clip:Clip):void { - if (!netResource) return; - clip.onPlayStatus(onPlayStatus); - - _bufferStart = clip.currentTime; - _startSeekDone = false; - netStream.play(clip.url, clip.start); - } - - /** - * url resolver - * @param provider - * @param clip - * @param successListener - */ - - public function resolve(provider:StreamProvider, clip:Clip, successListener:Function):void { - _clip = clip; - _successListener = successListener; - loadM3U8(_clip.completeUrl, onM3U8Loaded); - } - - - /** - * Loads the M3u8 playlist - * @param m3u8Url - * @param loadedCallback - */ - protected function loadM3U8(m3u8Url:String, loadedCallback:Function):void { - if (!_player) return; - log.debug("connect(), loading M3U8 file from " + m3u8Url); - - var loader:ResourceLoader = _player.createLoader(); - loader.errorHandler = this; - loader.load(m3u8Url, function(loader:ResourceLoader):void { - log.debug("M3U8 file received"); - loadedCallback(String(loader.getContent())); - }, true); - } - - /** - * M3u8 playlist loaded and parsing the manifest - * @param m3u8Content - */ - protected function onM3U8Loaded(m3u8Content:String):void { - stopM3U8Reload(); - parseM3U8Manifest(m3u8Content); - } - - /** - * formats the streaming items - * @param streamItems - * @return - */ - protected function formatStreamItems(streamItems:Vector.):Vector. { - var bitrateItems:Vector. = new Vector.(); - var bitrateOptions:Object = {}; - if (_clip.getCustomProperty("bitrates")) { - bitrateOptions = _clip.getCustomProperty("bitrates"); - } else { - bitrateOptions.default = dynResource.streamItems[0].bitrate; - - if (dynResource.streamItems.length == 2) { - bitrateOptions.sd = dynResource.streamItems[0].bitrate; - bitrateOptions.hd = dynResource.streamItems[dynResource.streamItems.length - 1].bitrate; - } - } - - for (var index:int = 0; index < dynResource.streamItems.length; index++) { - var item:DynamicStreamingItem = streamItems[index]; - - var bitrateItem:BitrateItem = new BitrateItem(); - bitrateItem.url = item.streamName; - bitrateItem.bitrate = item.bitrate / 1000; - bitrateItem.index = index; - bitrateItem.width = item.width; - bitrateItem.height = item.height; - if (bitrateOptions.default == bitrateItem.bitrate) bitrateItem.isDefault = true; - if (bitrateOptions.sd == bitrateItem.bitrate) bitrateItem.sd = true; - if (bitrateOptions.hd == bitrateItem.bitrate) bitrateItem.hd = true; - if (bitrateOptions.labels) bitrateItem.label = bitrateOptions.labels[bitrateItem.bitrate]; - bitrateItems.push(bitrateItem); - } - return bitrateItems; - } - - /** - * M3u8 manifest parsing has finished - */ - protected function onM3U8Finished():void - { - log.debug("M3U8 Manifest Finished"); - - try - { - resource = parser.createResource(manifest, new URLResource(_clip.completeUrl)); - - //dynamic streaming resource - if (resource is DynamicStreamingResource) { - dynResource = resource as DynamicStreamingResource; - //formats the stream items to be ready for the bwcheck plugin - dynResource.streamItems = formatStreamItems(dynResource.streamItems); - _isDynamicStreamResource = true; - _clip.setCustomProperty("bitrateItems", dynResource.streamItems); - _clip.setCustomProperty("urlResource", dynResource); - - } else { - //single bitrate resource - streamResource = resource as StreamingURLResource; - - log.debug("Manifest parsed with a single stream " + manifest.media[0].url); - _clip.setResolvedUrl(this, streamResource.url); - _clip.setCustomProperty("urlResource", streamResource); - } - - _clip.setCustomProperty("manifestInfo",manifest); - - - if (_successListener != null) { - _successListener(_clip); - } - - } - catch (error:Error) - { - handleStreamNotFound(error.message); - } - } - - /** - * Handle stream not found errors, for live streams use connection reattempts until it becomes available. - * @param message - */ - private function handleStreamNotFound(message:String):void - { - log.error(message); - - if (_clip.live) { - retryM3U8Load(); - return; - } - - _clip.dispatchError(ClipError.STREAM_NOT_FOUND, message); - } - - /** - * Stop the playlist loading timer - */ - protected function stopM3U8Reload():void - { - if (_retryTimer) { - _retryTimer.stop(); - _retryTimer.removeEventListener(TimerEvent.TIMER, onM3U8LoadRetry); - _retryTimer.reset(); - _retryTimer = null; - _retryCount = 0; - } - } - - /** - * Attempt to reconnect or stop if the retry count has reached it's limit. - */ - private function retryM3U8Load():void - { - if (!_retryTimer) { - _retryTimer = new Timer(_config.retryInterval); - _retryTimer.addEventListener(TimerEvent.TIMER, onM3U8LoadRetry); - _retryTimer.start(); - log.error("Reattempting to load media from M3U8 manifest " + _clip.completeUrl); - } - - _retryCount++; - - if (_retryCount > _config.maxRetries) { - stopM3U8Reload(); - } - } - - /** - * Reload the M3U8 feed after a set interval. - * @param event - */ - private function onM3U8LoadRetry(event:TimerEvent):void - { - log.error("Reattempting to load media from M3U8 manifest " + _clip.completeUrl); - loadM3U8(_clip.completeUrl, onM3U8Loaded); - } - - /** - * Formats the baseUrl - * @param url - * @return - */ - protected function getRootUrl(url:String):String - { - var path:String = url.substr(0, url.lastIndexOf("/")); - - return path; - } - - private function parseM3U8Manifest(M3U8Content:String):void { - // log.debug("M3U8 Content: " + M3U8Content); - log.debug("Parsing M3U8 Manifest"); - parser = new HttpStreamingM3U8ManifestParser(); - - parser.addEventListener(ParseEvent.PARSE_COMPLETE, onParserLoadComplete); - parser.addEventListener(ParseEvent.PARSE_ERROR, onParserLoadError); - - - try - { - parser.parse(M3U8Content, getRootUrl(_clip.completeUrl), _clip.completeUrl); - } - catch (parseError:Error) - { - - log.error(parseError.errorID + " " + parseError.getStackTrace()); - } - } - - /** - * M3u8 parser completed - * @param event - */ - protected function onParserLoadComplete(event:ParseEvent):void - { - parser.removeEventListener(ParseEvent.PARSE_COMPLETE, onParserLoadComplete); - parser.removeEventListener(ParseEvent.PARSE_ERROR, onParserLoadError); - - manifest = event.data as HttpStreamingM3U8Manifest; - onM3U8Finished(); - } - - /** - * M3u8 parser error - * @param event - */ - protected function onParserLoadError(event:ParseEvent):void - { - parser.removeEventListener(ParseEvent.PARSE_COMPLETE, onParserLoadComplete); - parser.removeEventListener(ParseEvent.PARSE_ERROR, onParserLoadError); - log.error("Error parsing manifest"); - } - - /** - * resolver failure listener - * @param listener - */ - public function set onFailure(listener:Function):void { - - } - - public function showError(message:String):void - { - - } - - /** - * Handle stream not found errors for missing M3U8 feeds - * @param error - * @param info - * @param throwError - */ - public function handleError(error:ErrorCode, info:Object = null, throwError:Boolean = true):void - { - handleStreamNotFound(error.message); - } - - /** - * handles netstatus events - * @param event - * @return - */ - public function handeNetStatusEvent(event:NetStatusEvent):Boolean { - return true; - } - - protected function onPlayStatus(event:ClipEvent) : void { - log.debug("onPlayStatus() -- " + event.info.code); - if (event.info.code == "NetStream.Play.TransitionComplete"){ - dispatchEvent(new ClipEvent(ClipEventType.SWITCH_COMPLETE)); - } - return; - } - - /** - * Setup switch events on the netstream - * @param event - */ - override protected function onNetStatus(event:NetStatusEvent) : void { - log.debug("onNetStatus(), code: " + event.info.code + ", paused? " + paused + ", seeking? " + seeking); - switch(event.info.code){ - case "NetStream.Play.Transition": - log.debug("Stream Transition -- " + event.info.details); - dispatchEvent(new ClipEvent(ClipEventType.SWITCH, event.info.details)); - break; - } - return; - } - - /** - * @inherit - * @param event - * @param netStream - * @param closeStreamAndConnection - */ - override protected function doStop(event:ClipEvent, netStream:NetStream, closeStreamAndConnection:Boolean = false):void { - _currentClip = null; - log.debug("Clearing clip and stopping "); - super.doStop(event, netStream, closeStreamAndConnection); - } - - /** - * @inherit - * @param event - * @param netStream - * @param seconds - */ - override protected function doSeek(event : ClipEvent, netStream : NetStream, seconds : Number) : void { - var seekTime:int = int(seconds); - _bufferStart = seekTime; - log.debug("calling netStream.seek(" + seekTime + ")"); - seeking = true; - netStream.seek(seekTime); - } - - /** - * @inherit - * @param event - * @param netStream - * @param clip - * @param netStreamPlayOptions - */ - override protected function doSwitchStream(event:ClipEvent, netStream:NetStream, clip:Clip, netStreamPlayOptions:Object = null):void { - log.debug("doSwitchStream()"); - - _previousClip = clip; - - if (netStream.hasOwnProperty("play2") && netStreamPlayOptions) { - import flash.net.NetStreamPlayOptions; - if (netStreamPlayOptions is NetStreamPlayOptions) { - log.debug("doSwitchStream() calling play2()") - netStream.play2(netStreamPlayOptions as NetStreamPlayOptions); - } - } else { - //fix for #338, don't set the currentTime when dynamic stream switching - _bufferStart = clip.currentTime; - clip.currentTime = Math.floor(_previousClip.currentTime + netStream.time); - load(event, clip); - dispatchEvent(event); - } - } - - /** - * @inherit - * @param event - */ - override protected function onMetaData(event:ClipEvent):void { - log.debug("in NetStreamControllingStremProvider.onMetaData: " + event.target); - - if (! clip.startDispatched) { - clip.dispatch(ClipEventType.START, pauseAfterStart); - clip.startDispatched = true; - } - - if (pauseAfterStart) { - pauseToFrame(); - } - switching = false; - } - - /** - * @inherit - */ - override public function get bufferStart() : Number { - if (!clip) return 0; - if (!netStream) return 0; - return Math.max(0, getCurrentPlayheadTime(netStream)); - } - - /** - * @inherit - */ - override public function get bufferEnd() : Number { - if (!clip) return 0; - if (!netStream) return 0; - return getCurrentPlayheadTime(netStream) + netStream.bufferLength; - } - - /** - * @inherit - */ - override public function get allowRandomSeek():Boolean { - return true; - } - - /** - * @inherit - * @return - */ - override protected function canDispatchBegin():Boolean { - return true; - } - - - public function getDefaultConfig():Object { - return null; - } - - /** - * @inherit - */ - override public function get type():String { - return "httpstreaminghls"; - } - - /** - * @inherit - * @param connection - * @return - */ - override protected function createNetStream(connection:NetConnection):NetStream { - if (!clip.getCustomProperty("urlResource")) return super.createNetStream(connection); - clip.type = ClipType.VIDEO; - netResource = clip.getCustomProperty("urlResource") as URLResource; - var httpNetStream:HTTPNetStream = new HTTPNetStream(connection, new HTTPStreamingM3U8Factory(), netResource); - return httpNetStream; - } - } -} diff --git a/plugins/httpstreaming/README.txt b/plugins/httpstreaming/README.txt index dc2c521..e17a025 100644 --- a/plugins/httpstreaming/README.txt +++ b/plugins/httpstreaming/README.txt @@ -1,5 +1,12 @@ Version history: +3.2.11 (Nov 2013) +------ +- Now uses OSMF 2.0 +- #70 fixes for live streams +- #70 fixes for buffer start value. +- #136 when we are streaming live and not in dvr mode set the duration to zero in the index handler instead of the metadata callback. + 3.2.10 ------ - #27 regression caused by #550, only stop the player for live streams. caused issues when stopping between playlist items. @@ -8,6 +15,7 @@ Version history: ----- - #515 when seeking on startup set a delay or else the initial time is treated as the clip start time. - #550 for live streams once unpublished, stop the player to prevent streamnotfound errors reconnecting. +- #27 regression caused by #550, only stop the player for live streams. caused issues when stopping between playlist items. 3.2.8 ----- diff --git a/plugins/httpstreaming/build.properties b/plugins/httpstreaming/build.properties index 5d1e2d5..681bfd2 100644 --- a/plugins/httpstreaming/build.properties +++ b/plugins/httpstreaming/build.properties @@ -1,3 +1,3 @@ devkit-dir=../../lib/devkit osmf-dir=../../lib/osmf/framework/OSMF -version=3.2.10 +version=3.2.11 diff --git a/plugins/httpstreaming/build.xml b/plugins/httpstreaming/build.xml index 88afc6f..b365157 100644 --- a/plugins/httpstreaming/build.xml +++ b/plugins/httpstreaming/build.xml @@ -7,11 +7,14 @@ - - + + + + + diff --git a/plugins/httpstreaming/src/actionscript/org/flowplayer/httpstreaming/HttpStreamingProvider.as b/plugins/httpstreaming/src/actionscript/org/flowplayer/httpstreaming/HttpStreamingProvider.as index 165527a..512cc2a 100644 --- a/plugins/httpstreaming/src/actionscript/org/flowplayer/httpstreaming/HttpStreamingProvider.as +++ b/plugins/httpstreaming/src/actionscript/org/flowplayer/httpstreaming/HttpStreamingProvider.as @@ -32,6 +32,7 @@ package org.flowplayer.httpstreaming { import org.osmf.net.httpstreaming.HTTPNetStream; import org.osmf.net.httpstreaming.f4f.HTTPStreamingF4FFactory; import org.osmf.net.httpstreaming.dvr.DVRInfo; + import org.osmf.net.StreamingURLResource; import org.osmf.metadata.Metadata; import org.osmf.metadata.MetadataNamespaces; import org.osmf.media.URLResource; @@ -97,8 +98,8 @@ package org.flowplayer.httpstreaming { _dvrInfo = null; _dvrIsRecording = false; - //netStream.client = new NetStreamClient(clip, _player.config, streamCallbacks); - netStream.play(clip.url, clip.start); + //#70 fixes for live streams. + netStream.play(clip.url, clip.live && !isDvr ? -1 : clip.start); } private function onPlayStatus(event:ClipEvent) : void { @@ -122,6 +123,15 @@ package org.flowplayer.httpstreaming { //#27 regression caused by #550, only stop the player for live streams. caused issues when stopping between playlist items. if (clip.live && !_player.playlist.hasNext()) _player.stop(); break; + case "NetStream.Buffer.Empty": + //#70 implement playback optimisations from strobe media playback. + if (netStream.bufferTime >= 2.0) { + netStream.bufferTime += 1.0; + } + else { + netStream.bufferTime = 2.0; + } + break; } return; } @@ -162,11 +172,19 @@ package org.flowplayer.httpstreaming { } } - override protected function onMetaData(event:ClipEvent):void { + /*override protected function onMetaData(event:ClipEvent):void { log.debug("in NetStreamControllingStremProvider.onMetaData: " + event.target); - //if we are not dvr recording dispatch start - if (! clip.startDispatched && !_dvrIsRecording) { + //#70 remove clip duration for live streams and when not dvr recording + if (clip.live && !isDvr) { + clip.metaData.duration = 0; + clip.duration = 0; + clip.durationFromMetadata = 0; + } + + + + if (! clip.startDispatched) { clip.dispatch(ClipEventType.START, pauseAfterStart); clip.startDispatched = true; } @@ -175,7 +193,7 @@ package org.flowplayer.httpstreaming { pauseToFrame(); } switching = false; - } + } */ override public function get allowRandomSeek():Boolean { return true; @@ -218,10 +236,6 @@ package org.flowplayer.httpstreaming { //dispatch the dvr event dispatchDVREvent(_dvrInfo); - //dispatch clip start - clip.dispatch(ClipEventType.START, false); - clip.startDispatched = true; - //seek to the closest offset to the live position determined by the current dvr duration, buffertime and live snap offset. var livePosition:Number = Math.max(0, dvrSeekOffset); this.netStream.seek(livePosition); @@ -230,6 +244,11 @@ package org.flowplayer.httpstreaming { } + private function get isDvr():Boolean + { + return StreamingURLResource(netResource).streamType == "dvr"; + } + private function dispatchDVREvent(dvrInfo:DVRInfo):void { log.debug("Seeking to DVR position"); @@ -274,10 +293,11 @@ package org.flowplayer.httpstreaming { return httpNetStream; } - override public function get bufferStart() : Number { - if (!clip) return 0; - if (!netStream) return 0; - return Math.max(0, getCurrentPlayheadTime(netStream)); + //#70 fixes for buffer start value + override public function get bufferStart():Number + { + if (! clip) return 0; + return _bufferStart - clip.start; } override public function get bufferEnd() : Number { diff --git a/plugins/httpstreaming/src/actionscript/org/osmf/net/httpstreaming/f4f/HTTPStreamingF4FIndexHandler.as b/plugins/httpstreaming/src/actionscript/org/osmf/net/httpstreaming/f4f/HTTPStreamingF4FIndexHandler.as new file mode 100644 index 0000000..cfb4c13 --- /dev/null +++ b/plugins/httpstreaming/src/actionscript/org/osmf/net/httpstreaming/f4f/HTTPStreamingF4FIndexHandler.as @@ -0,0 +1,2372 @@ +/***************************************************** +* +* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. +* +***************************************************** +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" +* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +* License for the specific language governing rights and limitations +* under the License. +* +* +* The Initial Developer of the Original Code is Adobe Systems Incorporated. +* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems +* Incorporated. All Rights Reserved. +* +*****************************************************/ +package org.osmf.net.httpstreaming.f4f +{ + import flash.events.EventDispatcher; + import flash.events.IEventDispatcher; + import flash.events.TimerEvent; + import flash.net.URLRequest; + import flash.utils.ByteArray; + import flash.utils.IDataInput; + import flash.utils.Timer; + + import org.osmf.elements.f4mClasses.BootstrapInfo; + import org.osmf.events.DVRStreamInfoEvent; + import org.osmf.events.HTTPStreamingEvent; + import org.osmf.events.HTTPStreamingEventReason; + import org.osmf.events.HTTPStreamingFileHandlerEvent; + import org.osmf.events.HTTPStreamingIndexHandlerEvent; + import org.osmf.net.dvr.DVRUtils; + import org.osmf.net.httpstreaming.HTTPStreamDownloader; + import org.osmf.net.httpstreaming.HTTPStreamRequest; + import org.osmf.net.httpstreaming.HTTPStreamRequestKind; + import org.osmf.net.httpstreaming.HTTPStreamingFileHandlerBase; + import org.osmf.net.httpstreaming.HTTPStreamingIndexHandlerBase; + import org.osmf.net.httpstreaming.HTTPStreamingUtils; + import org.osmf.net.httpstreaming.dvr.DVRInfo; + import org.osmf.net.httpstreaming.flv.FLVTagScriptDataMode; + import org.osmf.net.httpstreaming.flv.FLVTagScriptDataObject; + import org.osmf.utils.OSMFSettings; + import org.osmf.utils.URL; + + CONFIG::LOGGING + { + import org.osmf.logging.Logger; + } + + [ExcludeClass] + + /** + * @private + * + * The actual implementation of HTTPStreamingFileIndexHandlerBase. It + * handles the indexing scheme of an F4V file. + */ + public class HTTPStreamingF4FIndexHandler extends HTTPStreamingIndexHandlerBase + { + /* + AdobePatentID="2390US01" + */ + + /** + * Default Constructor. + * + * @param fileHandler The associated file handler object which is responsable for processing the actual data. + * We need this object as it may process bootstrap information found into the stream. + * @param fragmentsThreshold The default threshold for fragments. + */ + public function HTTPStreamingF4FIndexHandler(fileHandler:HTTPStreamingFileHandlerBase, fragmentsThreshold:uint = DEFAULT_FRAGMENTS_THRESHOLD) + { + super(); + + // listen for any bootstrap box information dispatched by file handler + fileHandler.addEventListener(HTTPStreamingFileHandlerEvent.NOTIFY_BOOTSTRAP_BOX, onBootstrapBox); + + _bestEffortF4FHandler.addEventListener(HTTPStreamingFileHandlerEvent.NOTIFY_BOOTSTRAP_BOX, onBestEffortF4FHandlerNotifyBootstrapBox); + } + + /** + * @private + */ + override public function dvrGetStreamInfo(indexInfo:Object):void + { + _invokedFromDvrGetStreamInfo = true; + playInProgress = false; + initialize(indexInfo); + } + + /** + * Initializes the index handler. + * + * @param indexInfor The index information. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + override public function initialize(indexInfo:Object):void + { + // Make sure we have an info object of the expected type. + _f4fIndexInfo = indexInfo as HTTPStreamingF4FIndexInfo; + if (_f4fIndexInfo == null || _f4fIndexInfo.streamInfos == null || _f4fIndexInfo.streamInfos.length <= 0) + { + CONFIG::LOGGING + { + logger.error("indexInfo object wrong or contains insufficient information!"); + } + + dispatchEvent(new HTTPStreamingEvent(HTTPStreamingEvent.INDEX_ERROR)); + return; + } + + _indexUpdating = false; + _pendingIndexLoads = 0; + _pendingIndexUpdates = 0; + _pendingIndexUrls = new Object(); + + playInProgress = false; + _pureLiveOffset = NaN; + + _serverBaseURL = _f4fIndexInfo.serverBaseURL; + _streamInfos = _f4fIndexInfo.streamInfos; + + var bootstrapBox:AdobeBootstrapBox; + var streamCount:int = _streamInfos.length; + + _streamQualityRates = []; + _streamNames = []; + + _bootstrapBoxesURLs = new Vector.(streamCount); + _bootstrapBoxes = new Vector.(streamCount); + for (var quality:int = 0; quality < streamCount; quality++) + { + var streamInfo:HTTPStreamingF4FStreamInfo = _streamInfos[quality]; + if (streamInfo != null) + { + _streamQualityRates[quality] = streamInfo.bitrate; + _streamNames[quality] = streamInfo.streamName; + + var bootstrap:BootstrapInfo = streamInfo.bootstrapInfo; + + if (bootstrap == null || (bootstrap.url == null && bootstrap.data == null)) + { + CONFIG::LOGGING + { + logger.error("Bootstrap(" + quality + ") null or contains inadequate information!"); + } + + dispatchEvent(new HTTPStreamingEvent(HTTPStreamingEvent.INDEX_ERROR)); + return; + } + + if (bootstrap.data != null) + { + bootstrapBox = processBootstrapData(bootstrap.data, quality); + if (bootstrapBox == null) + { + CONFIG::LOGGING + { + logger.error("BootstrapBox(" + quality + ") is null, potentially from bad bootstrap data!"); + } + + dispatchEvent(new HTTPStreamingEvent(HTTPStreamingEvent.INDEX_ERROR)); + return; + } + _bootstrapBoxes[quality] = bootstrapBox; + } + else + { + _bootstrapBoxesURLs[quality] = HTTPStreamingUtils.normalizeURL(bootstrap.url); + + _pendingIndexLoads++; + dispatchIndexLoadRequest(quality); + } + } + } + + if (_pendingIndexLoads == 0) + { + notifyRatesReady(); + notifyIndexReady(0); + } + } + + /** + * @inheritDoc + */ + override public function dispose():void + { + destroyBootstrapUpdateTimer(); + + _pendingIndexLoads = 0; + _pendingIndexUpdates = 0; + _pendingIndexUrls = new Object(); + + _bestEffortNeedsToFireFragmentDuration = false; + _bestEffortEnabled = true; + if (_bestEffortNotifyBootstrapBoxInfo != null && _bestEffortNotifyBootstrapBoxInfo.hasOwnProperty("downloader")) + { + var downloader:HTTPStreamDownloader = _bestEffortNotifyBootstrapBoxInfo.downloader as HTTPStreamDownloader; + if (downloader != null) + { + downloader.close(true); + } + } + } + + /** + * Called when the index file has been loaded and is ready to be processed. + * + * @param data The data from the loaded index file. + * @param indexContext An arbitrary context object which describes the loaded + * index file. Useful for index handlers which load multiple index files + * (and thus need to know which one to process). + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + override public function processIndexData(data:*, indexContext:Object):void + { + var quality:int = indexContext as int; + var bootstrapBox:AdobeBootstrapBox = processBootstrapData(data, quality); + + if (bootstrapBox == null) + { + CONFIG::LOGGING + { + logger.error("BootstrapBox(" + quality + ") is null when attempting to process index data during a bootstrap update."); + } + + dispatchEvent(new HTTPStreamingEvent(HTTPStreamingEvent.INDEX_ERROR)); + return; + } + + if (!_indexUpdating) + { + // we are processing an index initialization + _pendingIndexLoads--; + + CONFIG::LOGGING + { + logger.debug("Pending index loads: " + _pendingIndexLoads); + } + } + else + { + // we are processing an index update + _pendingIndexUpdates--; + + CONFIG::LOGGING + { + logger.debug("Pending index updates: " + _pendingIndexUpdates); + } + + var requestedUrl:String = _bootstrapBoxesURLs[quality]; + if (requestedUrl != null && _pendingIndexUrls.hasOwnProperty(requestedUrl)) + { + _pendingIndexUrls[requestedUrl].active = false; + } + + if (_pendingIndexUpdates == 0) + { + _indexUpdating = false; + // FM-924, onMetadata is called twice on http streaming live/dvr content + // It is really unnecessary to call onMetadata multiple times. The change of + // media length is fixed for VOD, and is informed by the call dispatchDVRStreamInfo + // for DVR. For "pure live", it does not really matter. Whenever MBR switching + // happens, onMetadata will be called by invoking checkMetadata method. + // + //notifyTotalDuration(bootstrapBox.totalDuration / bootstrapBox.timeScale, indexContext as int); + } + } + + CONFIG::LOGGING + { + logger.debug("BootstrapBox(" + quality + ") loaded successfully." + + "[version:" + bootstrapBox.bootstrapVersion + + ", fragments from frt:" + bootstrapBox.totalFragments + + ", fragments from srt:" + bootstrapBox.segmentRunTables[0].totalFragments + "]" + ); + } + updateBootstrapBox(quality, bootstrapBox, true /* sourceIsIndex */); + + if (_pendingIndexLoads == 0 && !_indexUpdating) + { + notifyRatesReady(); + notifyIndexReady(quality); + } + } + + /** + * Returns the HTTPStreamRequest which encapsulates the file for the given + * playback time and quality. If no such file exists for the specified time + * or quality, then this method should return null. + * + * @param time The time for which to retrieve a request object. + * @param quality The quality of the requested stream. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + override public function getFileForTime(time:Number, quality:int):HTTPStreamRequest + { + if ( quality < 0 + || quality >= _streamInfos.length + || time < 0) + { + CONFIG::LOGGING + { + logger.warn("Invalid parameters for getFileForTime(time=" + time + ", quality=" + quality + ")."); + } + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + + // best effort fetch accounting. initially assume seeks are not best effort. + _bestEffortState = BEST_EFFORT_STATE_OFF; + + var bootstrapBox:AdobeBootstrapBox = _bootstrapBoxes[quality]; + if (bootstrapBox == null) + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + + if (!playInProgress && isStopped(bootstrapBox)) + { + destroyBootstrapUpdateTimer(); + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + + updateMetadata(quality); + + var streamRequest:HTTPStreamRequest; + var desiredTime:Number = time * bootstrapBox.timeScale; + + // we should know the segment and fragment containing the desired time + if(_bestEffortEnabled) + { + streamRequest = getFirstRequestForBestEffortSeek(desiredTime, quality, bootstrapBox); + } + else + { + streamRequest = getSeekRequestForNormalFetch(desiredTime, quality, bootstrapBox); + } + + CONFIG::LOGGING + { + logger.debug("The url for ( time=" + time + ", quality=" + quality + ") = " + streamRequest.toString()); + } + + return streamRequest; + } + + /** + * @private + * + * helper for getFileForTime, called when best effort fetch is disabled. + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function getSeekRequestForNormalFetch( + desiredTime:Number, + quality:int, + bootstrapBox:AdobeBootstrapBox):HTTPStreamRequest + { + var streamRequest:HTTPStreamRequest = null; + var refreshNeeded:Boolean = false; + var currentTime:Number = bootstrapBox.currentMediaTime; + var contentComplete:Boolean = bootstrapBox.contentComplete(); + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + CONFIG::LOGGING + { + if (contentComplete) + { + logger.debug("Bootstrap reports that content is complete. If this is a live stream, then the publisher stopped it."); + } + } + if (desiredTime <= currentTime) + { + if(frt != null) + { + _currentFAI = frt.findFragmentIdByTime(desiredTime, currentTime, contentComplete ? false : bootstrapBox.live); + } + if (_currentFAI == null || fragmentOverflow(bootstrapBox, _currentFAI.fragId)) + { + // we're beyond the end of the bootstrap + if (!bootstrapBox.live || contentComplete) + { + // we're either: + // - vod, in which case we should stop playback + // - live/DVR, and there's a null term, meaning the content is done + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + else + { + // we're in live and we reached the end of content, but we're not done + return initiateLivenessFailure(quality); + } + } + else + { + // normal case: we found the fragment we were looking for. initiate a download request + return initiateNormalDownload(bootstrapBox, quality); + } + } + else if(bootstrapBox.live) + { + // we are trying to seek beyond the "live" point in the live scenario + return initiateBootstrapRefresh(quality); + } + else + { + // we are trying to seek beyond the "live" point in the vod scenario + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + } + + /** + * @private + */ + override public function getNextFile(quality:int):HTTPStreamRequest + { + if (quality < 0 || quality >= _streamInfos.length) + { + CONFIG::LOGGING + { + logger.warn("Invalid parameters for getNextFile(quality=" + quality + ")."); + } + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + + var bootstrapBox:AdobeBootstrapBox = _bootstrapBoxes[quality]; + if (bootstrapBox == null) + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + + if (!playInProgress && isStopped(bootstrapBox)) + { + destroyBootstrapUpdateTimer(); + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + + updateMetadata(quality); + var streamRequest:HTTPStreamRequest = null; + + if(_bestEffortEnabled) + { + // best effort case + if(_bestEffortState == BEST_EFFORT_STATE_OFF || + _bestEffortState == BEST_EFFORT_STATE_PLAY) + { + streamRequest = getNextRequestForBestEffortPlay(quality, bootstrapBox); + } + else + { + streamRequest = getNextRequestForBestEffortSeek(quality, bootstrapBox); + } + } + else + { + streamRequest = getNextRequestForNormalPlay(quality, bootstrapBox); + } + + CONFIG::LOGGING + { + logger.debug("Next url for (quality=" + quality + ") = " + streamRequest.toString()); + } + + return streamRequest; + } + + /** + * @private + * + * helper for getNextFile, called when best effort fetch is disabled. + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function getNextRequestForNormalPlay( + quality:int, + bootstrapBox:AdobeBootstrapBox):HTTPStreamRequest + { + var streamRequest:HTTPStreamRequest; + var currentTime:Number = bootstrapBox.currentMediaTime; + + var contentComplete:Boolean = bootstrapBox.contentComplete(); + CONFIG::LOGGING + { + if (contentComplete) + { + logger.debug("Bootstrap reports that content is complete. If this is a live stream, then the publisher stopped it."); + } + } + + var oldCurrentFAI:FragmentAccessInformation = _currentFAI; + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + if (oldCurrentFAI == null) + { + _currentFAI = null; + } + if(frt != null) + { + _currentFAI = frt.validateFragment( + oldCurrentFAI.fragId + 1, // fragId + currentTime, // totalDuration + contentComplete ? false : bootstrapBox.live); + } + if (_currentFAI == null || fragmentOverflow(bootstrapBox, _currentFAI.fragId)) + { + // we're beyond the end of the bootstrap + _currentFAI = oldCurrentFAI; + if (!bootstrapBox.live || contentComplete) + { + // we're either: + // - vod, in which case we should stop playback + // - live/DVR, and there's a null term, meaning the content is done + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + else + { + // we're in live and we reached the end of content, but we're not done + _currentFAI = oldCurrentFAI; + return initiateLivenessFailure(quality); + } + } + else + { + // normal case: we found the fragment we were looking for. initiate a download request + return initiateNormalDownload(bootstrapBox, quality); + } + } + + + /** + * @private + * + * Initiates a live failed request (from getNextFile or getFileForTime). + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function initiateLivenessFailure(quality:int):HTTPStreamRequest + { + adjustDelay(); + refreshBootstrapBox(quality); + + var livenessDelay:Number; + if(_bestEffortEnabled) + { + // after half a fragment duration the bootstrap should be updated + // but at least a second + livenessDelay = Math.max((_f4fIndexInfo.bestEffortFetchInfo.fragmentDuration / 2) / 1000.0, 1); + } + else + { + // otherwise, just use the default delay + livenessDelay = _delay; + } + return new HTTPStreamRequest( + HTTPStreamRequestKind.LIVE_STALL, + null, // url + livenessDelay); // retryAfter + } + + /** + * @private + * + * Initiates a refresh request (from getNextFile or getFileForTime). + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function initiateBootstrapRefresh(quality:int):HTTPStreamRequest + { + adjustDelay(); + refreshBootstrapBox(quality); + return new HTTPStreamRequest( + HTTPStreamRequestKind.RETRY, + null, // url + _delay); // retryAfter + } + + /** + * @private + * + * Initiates a normal download request (from getNextFile or getFileForTime). + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function initiateNormalDownload(bootstrapBox:AdobeBootstrapBox, quality:int):HTTPStreamRequest + { + // if we had a pending BEF download, invalidate it + stopListeningToBestEffortDownload(); + + // if we encounter liveness in the future, restart BEFs + // after the current fragment + _bestEffortLivenessRestartPoint = _currentFAI.fragId; + CONFIG::LOGGING + { + logger.debug("Setting _bestEffortLivenessRestartPoint to "+_bestEffortLivenessRestartPoint+" because of normal download."); + } + + // remember that we started a download now + _bestEffortLastGoodFragmentDownloadTime = new Date(); + + playInProgress = true; + updateQuality(quality); + notifyFragmentDuration(_currentFAI.fragDuration / bootstrapBox.timeScale); + return new HTTPStreamRequest( + HTTPStreamRequestKind.DOWNLOAD, + getFragmentUrl(quality, _currentFAI)); // url + } + + /** + * Checks if specified fragment identifier overflows the actual + * fragments contained into the bootstrap. + * + * @param bootstrapBox The bootstrap which contains the fragment run table. + * @param fragId Specified fragment identifier which must be checked. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + private function fragmentOverflow(bootstrapBox:AdobeBootstrapBox, fragId:uint):Boolean + { + var fragmentRunTable:AdobeFragmentRunTable = bootstrapBox.fragmentRunTables[0]; + var fdp:FragmentDurationPair = fragmentRunTable.fragmentDurationPairs[0]; + var segmentRunTable:AdobeSegmentRunTable = bootstrapBox.segmentRunTables[0]; + return ((segmentRunTable == null) || ((segmentRunTable.totalFragments + fdp.firstFragment - 1) < fragId)); + } + + /** + * Checks if there is no more data available for a specified + * bootstrap and if we should stop playback. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + private function isStopped(bootstrapBox:AdobeBootstrapBox):Boolean + { + var result:Boolean = false; + + if (_f4fIndexInfo.dvrInfo != null) + { + // in DVR scenario, the content is considered stopped once the dvr + // data is taken offline + result = _f4fIndexInfo.dvrInfo.offline; + } + else if (bootstrapBox != null && bootstrapBox.live) + { + // in pure live, the content is considered stopped once the + // fragment run table reports complete flag is set + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + if (frt != null) + { + result = frt.tableComplete(); + } + } + + return result; + } + + /** + * Gets the url for specified fragment and quality. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function getFragmentUrl(quality:int, fragment:FragmentAccessInformation):String + { + var bootstrapBox:AdobeBootstrapBox = _bootstrapBoxes[quality]; + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + var fdp:FragmentDurationPair = frt.fragmentDurationPairs[0]; + var segId:uint = bootstrapBox.findSegmentId(fragment.fragId - fdp.firstFragment + 1); + + return constructFragmentRequest(_serverBaseURL, _streamNames[quality], segId, fragment.fragId); + } + + /** + * Constructs the url for specified parameters. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + protected function constructFragmentRequest(serverBaseURL:String, streamName:String, segmentId:uint, fragmentId:uint):String + { + var requestUrl:String = ""; + if (streamName != null && streamName.indexOf("http") != 0) + { + requestUrl = serverBaseURL + "/" ; + } + requestUrl += streamName; + + var tempURL:URL = new URL(requestUrl); + tempURL.path += "Seg" + segmentId + "-Frag" + fragmentId; + + requestUrl = tempURL.protocol + "://" + tempURL.host; + if (tempURL.port != null && tempURL.port.length > 0) + { + requestUrl += ":" + tempURL.port; + } + requestUrl += "/" + tempURL.path; + if (tempURL.query != null && tempURL.query.length > 0) + { + requestUrl += "?" + tempURL.query; + } + if (tempURL.fragment != null && tempURL.fragment.length > 0) + { + requestUrl += "#" + tempURL.fragment; + } + + return requestUrl; + } + + /** + * Returns the fragment run table from the specified bootstrap box. + * It assumes that there is only one fragment run table. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + private function getFragmentRunTable(bootstrapBox:AdobeBootstrapBox):AdobeFragmentRunTable + { + if (bootstrapBox == null) + return null; + + return bootstrapBox.fragmentRunTables[0]; + } + + /** + * Adjusts the delay for future inquires from clients. + * When the index handler needs more time to obtain data in order to + * respond to a request from its clients, it will return a response + * requesting more time. This method varies the delay. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function adjustDelay():void + { + if (_delay < 1.0) + { + _delay = _delay * 2.0; + if (_delay > 1.0) + { + _delay = 1.0; + } + } + } + + /** + * Issues a request for refreshing the specified quality bootstrap. + * + * @param quality Quality level for which a refresh should be requested. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + private function refreshBootstrapBox(quality:uint):void + { + var requestedUrl:String = _bootstrapBoxesURLs[quality]; + if (requestedUrl == null) + return; + + var pendingIndexUrl:Object = null; + if (_pendingIndexUrls.hasOwnProperty(requestedUrl)) + { + pendingIndexUrl = _pendingIndexUrls[requestedUrl]; + } + else + { + pendingIndexUrl = new Object(); + pendingIndexUrl["active"] = false; + pendingIndexUrl["date"] = null; + _pendingIndexUrls[requestedUrl] = pendingIndexUrl; + } + + var ignoreRefreshRequest:Boolean = pendingIndexUrl.active; + var newRequestDate:Date = new Date(); + var elapsedTime:Number = 0; + + if (!ignoreRefreshRequest && OSMFSettings.hdsMinimumBootstrapRefreshInterval > 0) + { + var previousRequestDate:Date = pendingIndexUrl["date"]; + elapsedTime = Number.MAX_VALUE; + if (previousRequestDate != null) + { + elapsedTime = newRequestDate.valueOf() - previousRequestDate.valueOf(); + } + + ignoreRefreshRequest = elapsedTime < OSMFSettings.hdsMinimumBootstrapRefreshInterval; + } + + if (!ignoreRefreshRequest) + { + _pendingIndexUrls[requestedUrl].date = newRequestDate; + _pendingIndexUrls[requestedUrl].active = true; + _pendingIndexUpdates++; + _indexUpdating = true; + + CONFIG::LOGGING + { + logger.debug("Refresh (quality=" + quality + ") using " + requestedUrl + ". [active=" + pendingIndexUrl.active + ", elapsedTime=" + elapsedTime.toFixed(2) + "]"); + } + + dispatchIndexLoadRequest(quality); + } + else + { + CONFIG::LOGGING + { + logger.debug("Refresh (quality=" + quality + ") ignored. [active=" + pendingIndexUrl.active + ", elapsedTime=" + elapsedTime.toFixed(2) + "]"); + } + } + } + + /** + * Updates the specified bootstrap box if the specified information + * is newer than the current one. If the updated box if the current one, + * it also refreshes the associated DVR information. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function updateBootstrapBox( + quality:int, + bootstrapBox:AdobeBootstrapBox, + sourceIsIndex:Boolean):void + { + + if (shouldAcceptBootstrapBox(quality, bootstrapBox, sourceIsIndex)) + { + CONFIG::LOGGING + { + logger.debug("Bootstrap information for quality[" + quality + "] updated. (" + + ", live=" + bootstrapBox.live + + ", time=" + bootstrapBox.currentMediaTime + + ", first="+ bootstrapBox.fragmentRunTables[0].firstFragmentId + + ", gapCount="+ bootstrapBox.fragmentRunTables[0].countGapFragments() + + ", done="+ bootstrapBox.contentComplete() +")"); + } + _bootstrapBoxes[quality] = bootstrapBox; + _delay = 0.05; + if (quality == _currentQuality) + { + dispatchDVRStreamInfo(bootstrapBox); + } + } + } + + /** + * @return true if the specified bootstrap should be accepted over the existing bootstrap + */ + private function shouldAcceptBootstrapBox(quality:int, + newBootstrap:AdobeBootstrapBox, + sourceIsIndex:Boolean):Boolean + { + var existingBootstrap:AdobeBootstrapBox = _bootstrapBoxes[quality]; + if(newBootstrap == null || + newBootstrap.fragmentRunTables.length == 0 || + newBootstrap.segmentRunTables.length == 0) + { + // reject invalid + return false; + } + var newFrt:AdobeFragmentRunTable = newBootstrap.fragmentRunTables[0]; + var newSrt:AdobeSegmentRunTable = newBootstrap.segmentRunTables[0]; + if(newFrt == null || newSrt == null) + { + // reject invalid + return false; + } + if(newFrt.firstFragmentId == 0) + { + // don't accept bootstraps that have no valid entries + return false; + } + if(existingBootstrap == null) + { + // accept if we don't have a bootstrap yet + return true; + } + if(existingBootstrap.live != newBootstrap.live) + { + // bootstrap went from live to vod or vod to live + // this is not good. reject the bootstrap. + return false; + } + if(!existingBootstrap.live) + { + // VOD + + // accept newer bootstrap if the version is newer + if(newBootstrap.version != existingBootstrap.version) + { + return newBootstrap.version > existingBootstrap.version; + } + + // tie breaker is the media time + return newBootstrap.currentMediaTime > existingBootstrap.currentMediaTime; + } + else + { + // LIVE + + if(!sourceIsIndex) + { + // do not accept bootstraps that are internal to the fragment since they lie. + return false; + } + + // historical note: we do not use the version anymore. with multiple packagers, + // the version can become out of sync when there are discontinuities. fixing + // this would require synchronization across packagers of bootstrap version which + // would be done by deriving version from the common clock (currentMediaTime). thus + // it makes sense to accept changes based on currentMediaTime instead and ignore + // the version. + + var existingFrt:AdobeFragmentRunTable = existingBootstrap.fragmentRunTables[0]; + var existingSrt:AdobeSegmentRunTable = existingBootstrap.segmentRunTables[0]; + + if(newBootstrap.currentMediaTime != existingBootstrap.currentMediaTime) + { + // prefer newer bootstraps + return newBootstrap.currentMediaTime > existingBootstrap.currentMediaTime; + } + + if(newFrt.firstFragmentId != existingFrt.firstFragmentId) + { + // prefer bootstraps with an earlier starting point + return newFrt.firstFragmentId < existingFrt.firstFragmentId; + } + + var newGapCount:uint = newFrt.countGapFragments(); + var existingGapCount:uint = existingFrt.countGapFragments(); + if(newGapCount != existingGapCount) + { + // prefer bootstraps with fewer gap fragments + return newGapCount < existingGapCount; + } + + if(newBootstrap.contentComplete() && !existingBootstrap.contentComplete()) + { + // prefer done bootstraps + return true; + } + + // otherwise reject bootstraps + return false; + } + } + + /** + * Processes bootstrap raw information and returns an AdobeBootstrapBox object. + * + * @param data The raw representation of bootstrap. + * @param indexContext The index context used while processing bootstrap. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function processBootstrapData(data:*, indexContext:Object):AdobeBootstrapBox + { + var parser:BoxParser = new BoxParser(); + data.position = 0; + parser.init(data); + try + { + var boxes:Vector. = parser.getBoxes(); + } + catch (e:Error) + { + boxes = null; + } + + if (boxes == null || boxes.length < 1) + { + return null; + } + + var bootstrapBox:AdobeBootstrapBox = boxes[0] as AdobeBootstrapBox; + if (bootstrapBox == null) + { + return null; + } + + if (_serverBaseURL == null || _serverBaseURL.length <= 0) + { + if (bootstrapBox.serverBaseURLs == null || bootstrapBox.serverBaseURLs.length <= 0) + { + // If serverBaseURL is not set from the external, we need to pick + // a server base URL from the bootstrap box. For now, we just + // pick the first one. It is an error if the server base URL is null + // under this circumstance. + return null; + } + + _serverBaseURL = bootstrapBox.serverBaseURLs[0]; + } + + return bootstrapBox; + } + + /** + * Updates the current quality index. + * + * Also in MBR scenarios with protected content we need to append the additionalHeader + * that contains the DRM metadata to the Flash Player for that fragment before any + * additional TCMessage. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function updateQuality(quality:int):void + { + if (quality != _currentQuality) + { + // we preserve this for later comparison + var prevAdditionalHeader:ByteArray = _currentAdditionalHeader; + var newAdditionalHeader:ByteArray = _streamInfos[quality].additionalHeader; + + CONFIG::LOGGING + { + logger.debug("Quality changed from " + _currentQuality + " to " + quality + "."); + } + _currentQuality = quality; + _currentAdditionalHeader = newAdditionalHeader; + + // We compare the two DRM headers and if they are different we inject + // the new one as script data into the underlying objects. + // Strictly speaking, the != comparison of additional header is not enough. + // Ideally, we need to do bytewise comparison, however there might be a performance + // hit considering the size of the additional header. + if (newAdditionalHeader != null && newAdditionalHeader != prevAdditionalHeader) + { + CONFIG::LOGGING + { + logger.debug("Update of DRM header is required."); + } + dispatchAdditionalHeader(newAdditionalHeader); + } + } + } + + /** + * Updates the metadata for the current quality. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function updateMetadata(quality:int):void + { + if (quality != _currentQuality) + { + var bootstrapBox:AdobeBootstrapBox = _bootstrapBoxes[quality]; + if (bootstrapBox != null) + { + //#136 when we are streaming live and not in dvr mode set the duration to zero. + notifyTotalDuration(bootstrapBox.live && !_f4fIndexInfo.dvrInfo ? 0 : bootstrapBox.totalDuration / bootstrapBox.timeScale, quality); + } + } + } + + /** + * Dispatches the protected content header. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function dispatchAdditionalHeader(additionalHeader:ByteArray):void + { + var flvTag:FLVTagScriptDataObject = new FLVTagScriptDataObject(); + flvTag.data = additionalHeader; + + dispatchEvent( + new HTTPStreamingEvent( + HTTPStreamingEvent.SCRIPT_DATA + , false + , false + , 0 + , flvTag + , FLVTagScriptDataMode.FIRST + ) + ); + } + + /** + * Dispatches the DVR information extracted from the specified bootstrap. + * + * @param bootstrapBox The bootstrap box containing the DVR information. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function dispatchDVRStreamInfo(bootstrapBox:AdobeBootstrapBox):void + { + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + + var dvrInfo:DVRInfo = _f4fIndexInfo.dvrInfo; + if (dvrInfo != null) + { + // update recording status from fragment runt table + dvrInfo.isRecording = !frt.tableComplete(); + + // calculate current duration + var currentDuration:Number = bootstrapBox.totalDuration/bootstrapBox.timeScale; + var currentTime:Number = bootstrapBox.currentMediaTime/bootstrapBox.timeScale; + + // update start time for the first time + if (isNaN(dvrInfo.startTime)) + { + if (!dvrInfo.isRecording) + { + dvrInfo.startTime = 0; + } + else + { + var beginOffset:Number = ((dvrInfo.beginOffset < 0) || isNaN(dvrInfo.beginOffset)) ? 0 : dvrInfo.beginOffset; + var endOffset:Number = ((dvrInfo.endOffset < 0) || isNaN(dvrInfo.endOffset))? 0 : dvrInfo.endOffset; + + dvrInfo.startTime = DVRUtils.calculateOffset(beginOffset, endOffset, currentDuration); + } + + dvrInfo.startTime += (frt.fragmentDurationPairs)[0].durationAccrued/bootstrapBox.timeScale; + if (dvrInfo.startTime > currentTime) + { + dvrInfo.startTime = currentTime; + } + } + + // update current length of the DVR window + dvrInfo.curLength = currentTime - dvrInfo.startTime; + + // adjust the start time if we have a DVR rooling window active + if ((dvrInfo.windowDuration != -1) && (dvrInfo.curLength > dvrInfo.windowDuration)) + { + dvrInfo.startTime += dvrInfo.curLength - dvrInfo.windowDuration; + dvrInfo.curLength = dvrInfo.windowDuration; + } + + dispatchEvent( + new DVRStreamInfoEvent( + DVRStreamInfoEvent.DVRSTREAMINFO, + false, + false, + dvrInfo + ) + ); + } + } + + + /** + * Dispatches an event requesting loading/refreshing of the specified quality. + * + * @param quality The quality level for which the request should be made. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function dispatchIndexLoadRequest(quality:int):void + { + dispatchEvent( + new HTTPStreamingIndexHandlerEvent( + HTTPStreamingIndexHandlerEvent.REQUEST_LOAD_INDEX + , false + , false + , false + , NaN + , null + , null + , new URLRequest(_bootstrapBoxesURLs[quality]) + , quality + , true + ) + ); + } + + /** + * Notifies clients that rates are ready. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function notifyRatesReady():void + { + dispatchEvent( + new HTTPStreamingIndexHandlerEvent( + HTTPStreamingIndexHandlerEvent.RATES_READY + , false + , false + , false + , NaN + , _streamNames + , _streamQualityRates + ) + ); + } + + /** + * Notifies clients that index is ready. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function notifyIndexReady(quality:int):void + { + var bootstrapBox:AdobeBootstrapBox = _bootstrapBoxes[quality]; + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + + if(!_bestEffortInited) + { + // initialize _bestEffortEnabled + // best effort is only enabled if + // - enabled in the f4m + // - the stream is live (the first bootstrap is marked as live) + // this codepath is executed via DVRGetStreamInfo + // after the first bootstrap fetch, but + // before the load state is ready. + _bestEffortEnabled =_f4fIndexInfo.bestEffortFetchInfo != null && bootstrapBox.live; + _bestEffortInited = true; + } + + dispatchDVRStreamInfo(bootstrapBox); + + if (!_invokedFromDvrGetStreamInfo) + { + // in pure live scenario, update the "closest" position to live we want + if (bootstrapBox.live && _f4fIndexInfo.dvrInfo == null && isNaN(_pureLiveOffset)) + { + _pureLiveOffset = bootstrapBox.currentMediaTime - OSMFSettings.hdsPureLiveOffset * bootstrapBox.timeScale; + if (_pureLiveOffset < 0) + { + _pureLiveOffset = NaN; + } + else + { + _pureLiveOffset = _pureLiveOffset / bootstrapBox.timeScale; + } + } + + // If the stream is live, initialize the bootstrap update timer + // if we are in a live stream with rolling window feature activated + if (bootstrapBox.live && _f4fIndexInfo.dvrInfo != null) + { + initializeBootstrapUpdateTimer(); + } + + if (frt.tableComplete()) + { + // Destroy the timer if the stream is no longer recording + destroyBootstrapUpdateTimer(); + } + + dispatchEvent( + new HTTPStreamingIndexHandlerEvent( + HTTPStreamingIndexHandlerEvent.INDEX_READY + , false + , false + , bootstrapBox.live + , _pureLiveOffset + ) + ); + } + _invokedFromDvrGetStreamInfo = false; + } + + /** + * Notifies clients that total duration is available through onMetadata message. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + private function notifyTotalDuration(duration:Number, quality:int):void + { + var metaInfo:Object = _streamInfos[quality].streamMetadata; + if (metaInfo == null) + { + metaInfo = new Object(); + } + + + metaInfo.duration = duration; + + var sdo:FLVTagScriptDataObject = new FLVTagScriptDataObject(); + sdo.objects = ["onMetaData", metaInfo]; + dispatchEvent( + new HTTPStreamingEvent( + HTTPStreamingEvent.SCRIPT_DATA + , false + , false + , 0 + , sdo + , FLVTagScriptDataMode.IMMEDIATE + ) + ); + } + + /** + * Notifies clients that total duration is available through onMetadata message. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.0 + */ + private function notifyFragmentDuration(duration:Number):void + { + // Update the bootstrap update interval; we set its value to the fragment duration + bootstrapUpdateInterval = duration * 1000; + if (bootstrapUpdateInterval < OSMFSettings.hdsMinimumBootstrapRefreshInterval) + { + bootstrapUpdateInterval = OSMFSettings.hdsMinimumBootstrapRefreshInterval; + } + + dispatchEvent( + new HTTPStreamingEvent( + HTTPStreamingEvent.FRAGMENT_DURATION + , false + , false + , duration + , null + , null + ) + ); + } + + private function initializeBootstrapUpdateTimer():void + { + if (bootstrapUpdateTimer == null) + { + // This will regularly update the bootstrap information; + // We just initialize the timer here; we'll start it in the first call of the getFileForTime method + // or in the first call of getNextFile + // The initial delay is 4000 (recommended fragment duration) + bootstrapUpdateTimer = new Timer(bootstrapUpdateInterval); + bootstrapUpdateTimer.addEventListener(TimerEvent.TIMER, onBootstrapUpdateTimer); + bootstrapUpdateTimer.start(); + } + } + + private function destroyBootstrapUpdateTimer():void + { + if (bootstrapUpdateTimer != null) + { + bootstrapUpdateTimer.removeEventListener(TimerEvent.TIMER, onBootstrapUpdateTimer); + bootstrapUpdateTimer = null; + } + } + + /// Event handlers + /** + * Handler called when bootstrap information is available from external objects + * (for exemple: the stream packager can insert bootstrap information into + * the stream itself, and this information is processed by file handler). + * + * We will use it to update the bootstrap information for current quality. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion OSMF 1.6 + */ + private function onBootstrapBox(event:HTTPStreamingFileHandlerEvent):void + { + CONFIG::LOGGING + { + logger.debug("Bootstrap box inside media stream found. Trying to update the bootstrap"); + } + updateBootstrapBox(_currentQuality, event.bootstrapBox, false /* sourceIsIndex */); + + // for best effort fetches, we will trigger the FRAGMENT_DURATION event after we finish the download. + notifyFragmentDurationForBestEffort(event.bootstrapBox); + } + + private function onBootstrapUpdateTimer(event:TimerEvent):void + { + if (_currentQuality != -1) + { + refreshBootstrapBox(_currentQuality); + bootstrapUpdateTimer.delay = bootstrapUpdateInterval; + } + } + + /** + * @private + * + * helper for getFileForTime, called when best effort fetch is enabled. + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function getFirstRequestForBestEffortSeek( + desiredTime:Number, + quality:int, + bootstrapBox:AdobeBootstrapBox):HTTPStreamRequest + { + bestEffortLog("Initiating best effort seek "+desiredTime); + + _bestEffortState = BEST_EFFORT_STATE_SEEK_BACKWARD; + _bestEffortSeekTime = desiredTime; + _bestEffortFailedFetches = 0; + _bestEffortLastGoodFragmentDownloadTime = null; + + return getNextRequestForBestEffortSeek(quality, bootstrapBox); + } + + /** + * @private + * + * helper. called when best effort fetch is enabled during the initial seek + * (getFileForTime) as well as in subsequent iterations (getNextFile). + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function getNextRequestForBestEffortSeek( + quality:int, + bootstrapBox:AdobeBootstrapBox):HTTPStreamRequest + { + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + if(frt == null) + { + // rare case: there were no fragment run table entries + bestEffortLog("Best effort done because the bootstrap box was invalid"); + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + + // if we had a pending BEF download, invalidate it + stopListeningToBestEffortDownload(); + + _currentFAI = null; + + var bestEffortSeekResult:uint = doBestEffortSeek(bootstrapBox, frt); + if(bestEffortSeekResult != 0) + { + // doing best effort + // initialize stuff related to reading the f4f + bestEffortLog("Best effort seek fetch for fragment "+bestEffortSeekResult); + _bestEffortF4FHandler.beginProcessFile(true, _bestEffortSeekTime); + _bestEffortSeekBuffer.length = 0; + _bestEffortSeekBuffer.position = 0; + return initiateBestEffortRequest(bestEffortSeekResult, quality); + } + else + { + // revert to normal fetch, usually because + // - the desired time is present in the FRT. + // - we're seeking to a time >= currentMediaTime (this occurs when + // when we're initially playing a live stream with no live offset.) + // - or, all best effort fetches failed + // + // we are not calling findFragmentIdByTime here because there are edge cases + // where findFragmentIdByTime will return null or invalid results. instead, + // use the well-defined getFragmentWithTimeGreq. + _bestEffortState = BEST_EFFORT_STATE_OFF; + _currentFAI = frt.getFragmentWithTimeGreq(_bestEffortSeekTime); + if (_currentFAI == null) + { + // we didn't find the time in the FRT. + // this is usually because we're seeking to a time >= currentMediaTime, + // or there are no FRT entries (rare). + // in any case, initiate playback from the specified time. + bestEffortLog("Best effort done because there were no bootstrap entries"); + _bestEffortState = BEST_EFFORT_STATE_OFF; + _bestEffortLivenessRestartPoint = Math.max(guessFragmentIdForTime(_bestEffortSeekTime), 1) - 1; + _currentFAI = new FragmentAccessInformation(); + _currentFAI.fragId = _bestEffortLivenessRestartPoint; + return getNextFile(quality); + } + else + { + // normal case. we found something, play it out. + bestEffortLog("Normal seek request for fragment "+_currentFAI.fragId); + return initiateNormalDownload(bootstrapBox, quality); + } + } + } + + /** + * @private + * + * @return the expected fragment number for the desired seek time + **/ + private function guessFragmentIdForTime(time:Number):uint + { + return uint(Math.floor(time / _f4fIndexInfo.bestEffortFetchInfo.fragmentDuration)) + 1; + } + + /** + * @private + * + * helper for getNextRequestForBestEffortSeek. figures out the next fragment number to best-effort-fetch for the current seek. + * + * @return the fragment number to best effort fetch, or 0 to revert to normal fetch + **/ + private function doBestEffortSeek( + bootstrapBox:AdobeBootstrapBox, + frt:AdobeFragmentRunTable):uint + { + if(_bestEffortSeekTime >= bootstrapBox.currentMediaTime) + { + // don't do best effort if we're looking for a future time + bestEffortLog("Seek time greter than current media time."); + return 0; + } + + if(!frt.isTimeInGap(_bestEffortSeekTime, _f4fIndexInfo.bestEffortFetchInfo.fragmentDuration)) + { + // don't do best effort if the time is present in the frt + bestEffortLog("Found seek time in FRT"); + return 0; + } + + var firstFragment:FragmentAccessInformation = frt.getFragmentWithIdGreq(0); + if(firstFragment != null) + { + // don't do best effort if we're looking for a time before the first bootstrap entry + var firstFragmentStartTime:Number = firstFragment.fragmentEndTime - firstFragment.fragDuration; + if(_bestEffortSeekTime < firstFragmentStartTime) + { + bestEffortLog("Seek time before first bootstrap entry time."); + return 0; + } + } + + if(_bestEffortState == BEST_EFFORT_STATE_SEEK_BACKWARD) + { + var backwardSeekResult:uint = doBestEffortSeekBackward(frt); + if(backwardSeekResult != 0) + { + return backwardSeekResult; + } + else + { + // backward seek failed + _bestEffortState = BEST_EFFORT_STATE_SEEK_FORWARD; + _bestEffortFailedFetches = 0; + } + } + // _bestEffortState == BEST_EFFORT_STATE_SEEK_FORWARD + var forwardSeekResult:uint = doBestEffortSeekForward(frt); + if(forwardSeekResult != 0) + { + return forwardSeekResult; + } + else + { + // forward seek failed + return 0; + } + } + + /** + * @private + * + * helper for doBestEffortSeek. figures out the next fragment number to best-effort-fetch for the current seek + * while in backward fetch state. + * + * @return the fragment number to best effort fetch, or 0 if we should not perform backward fetch. + **/ + private function doBestEffortSeekBackward(frt:AdobeFragmentRunTable):uint + { + // guess a fragment number for _bestEffortSeekTime + if(_bestEffortFailedFetches >= _f4fIndexInfo.bestEffortFetchInfo.maxBackwardFetches) + { + // we exhausted all our best effort backward fetches. move to forwards search. + bestEffortLog("Best effort seek backward failing due to too many failures"); + return 0; + } + var guessFragmentId:uint = guessFragmentIdForTime(_bestEffortSeekTime); + if(guessFragmentId <= _bestEffortFailedFetches + 1) + { + // going backwards would hit fragment number 0 + bestEffortLog("Best effort seek backward hit fragment 0"); + return 0; + } + var nextFragmentId:uint = guessFragmentId - (_bestEffortFailedFetches + 1); + + // search the fragment run table to see if the desired fragment is already available + if(!frt.isFragmentInGap(nextFragmentId)) + { + // special case: the fragment we were going to request already exists in + // the fragment run table, and already know from our findFragmentIdByTime + // call that it doesn't contain the desired time. move to forwards search. + bestEffortLog("Best effort seek backward hit an existing fragment "+nextFragmentId); + return 0; + } + + bestEffortLog("Best effort seek backward fetch "+nextFragmentId); + return nextFragmentId; // true because this is a best effort fetch + } + + /** + * @private + * + * helper for doBestEffortSeek. figures out the next fragment number to best-effort-fetch for the current seek + * while in forward fetch state. + * + * @return the fragment number to best effort fetch, or 0 if we should not perform forward fetch. + **/ + private function doBestEffortSeekForward(frt:AdobeFragmentRunTable):uint + { + if (_bestEffortFailedFetches >= _f4fIndexInfo.bestEffortFetchInfo.maxForwardFetches) + { + // all best effort fetches failed. + // give up and just perform a normal seek. + bestEffortLog("Best effort seek failing due to too many failures"); + return 0; + } + var nextFragmentId:uint = guessFragmentIdForTime(_bestEffortSeekTime) + _bestEffortFailedFetches; + + // search the fragment run table to see if the desired fragment is already available + if(!frt.isFragmentInGap(nextFragmentId)) + { + // special case: the fragment we were going to request already exists in + // the fragment run table. just use that fragment. + bestEffortLog("Best effort seek forward hit an existing fragment "+nextFragmentId); + return 0; + } + + // normal case: perform a best effort forward fetch + bestEffortLog("Best effort seek forward fetch "+nextFragmentId); + return nextFragmentId; // true because this is a best effort fetch + } + + /** + * @private + * + * helper for getNextFile. called when best effort fetch is enabled + * but we're not seeking. + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function getNextRequestForBestEffortPlay( + quality:int, + bootstrapBox:AdobeBootstrapBox):HTTPStreamRequest + { + // parse out the FRT and SRT + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + if(_currentFAI == null || + frt == null || + bootstrapBox == null || + bootstrapBox.segmentRunTables.length < 1 || + bootstrapBox.segmentRunTables[0].segmentFragmentPairs.length < 1) + { + // rare case #1: _currentFAI shouldn't ever be null. + // rare case #2: FRT was invalid + // rare case #3: SRT was invalid + bestEffortLog("Best effort in a weird state."); + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + var srt:AdobeSegmentRunTable = bootstrapBox.segmentRunTables[0]; + + // figure out the next fragment to fetch + var nextFragmentId : uint = _currentFAI.fragId + 1; + + // figure out the live point. the SRT is the best source for + // how many fragments are available. this is roughly equivalent to the + // check happening in fragmentOverflow + var firstFragmentId:uint = frt.firstFragmentId; + if(firstFragmentId == 0) + { + // rare case: FRT didn't contain any valid entries + bestEffortLog("Best effort in a weird state."); + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + var livePoint : uint = firstFragmentId + srt.totalFragments; + + // figure out what kind of situation we're in + // liveness, dropout, done, or normal + var situation:String; + if(nextFragmentId >= livePoint) + { + if(bootstrapBox.contentComplete()) + { + situation = BEST_EFFORT_PLAY_SITUAUTION_DONE; + } + else + { + situation = BEST_EFFORT_PLAY_SITUAUTION_LIVENESS; + } + } + else + { + if(frt.isFragmentInGap(nextFragmentId)) + { + situation = BEST_EFFORT_PLAY_SITUAUTION_DROPOUT; + } + else + { + situation = BEST_EFFORT_PLAY_SITUAUTION_NORMAL; + } + } + + if(situation == BEST_EFFORT_PLAY_SITUAUTION_DROPOUT || + situation == BEST_EFFORT_PLAY_SITUAUTION_LIVENESS) + { + // try to do BEF, we can still bail if there were too many failures. + + bestEffortLog("Best effort in "+situation); + + if(situation == BEST_EFFORT_PLAY_SITUAUTION_LIVENESS && + _bestEffortLastGoodFragmentDownloadTime != null) + { + var now:Date = new Date(); + var nextPossibleBEFTime:Number = + _bestEffortLastGoodFragmentDownloadTime.valueOf() + Math.max(_f4fIndexInfo.bestEffortFetchInfo.fragmentDuration, 1000); + if(now.valueOf() < nextPossibleBEFTime) + { + // in order to prevent too many spurious liveness BEFs, + // don't perform liveness BEF unless its been at least half a fragment interval since the last + // successful download + return initiateBootstrapRefresh(quality); + } + } + + if(_bestEffortState == BEST_EFFORT_STATE_OFF) + { + // we're beginning best effort fetch + bestEffortLog("Best effort play start"); + _bestEffortState = BEST_EFFORT_STATE_PLAY; + _bestEffortFailedFetches = 0; + } + + if(_bestEffortFailedFetches < _f4fIndexInfo.bestEffortFetchInfo.maxForwardFetches) + { + // perform a best effort fetch + return initiateBestEffortRequest(nextFragmentId, quality); + } + else + { + // oops, all best effort fetches failed. + // give up and just perform a normal next + bestEffortLog("Best effort play failing due to too many failures"); + // fall through to do non-BEF behavior + } + } + + // we're going to do the non-BEF behavior + if(situation == BEST_EFFORT_PLAY_SITUAUTION_LIVENESS) + { + bestEffortLog("Best effort in liveness"); + + // the next time through, restart just after the last good download point + _bestEffortState = BEST_EFFORT_STATE_OFF; + _currentFAI.fragId = _bestEffortLivenessRestartPoint; + + return initiateLivenessFailure(quality); + } + else if(situation == BEST_EFFORT_PLAY_SITUAUTION_DONE) + { + bestEffortLog("Best effort done"); + return new HTTPStreamRequest(HTTPStreamRequestKind.DONE); + } + else // implicit: situation is 'normal' or 'dropout' + { + // figure out the next fragment id after the gap + // we're not using validateFragment because it has incompatible behavior close to the live point + var oldCurrentFAI:FragmentAccessInformation = _currentFAI; + _currentFAI = frt.getFragmentWithIdGreq(nextFragmentId); + if(_currentFAI == null) + { + // very rare case: couldn't get the fragment because there were no valid bootstrap entries. + _currentFAI = oldCurrentFAI; + bestEffortLog("Best effort done because there were no bootstrap entries"); + return initiateBootstrapRefresh(quality); + } + + _bestEffortState = BEST_EFFORT_STATE_OFF; // make sure to set state to off in case we were in play state + bestEffortLog("Normal play request for fragment "+_currentFAI.fragId); + return initiateNormalDownload(bootstrapBox, quality); + } + } + + /** + * @private + * + * Initiates a best effort request (from getNextFile or getFileForTime) and constructs an HTTPStreamRequest. + * + * @return the action to take, expressed as an HTTPStreamRequest + **/ + private function initiateBestEffortRequest(nextFragmentId:uint, quality:int):HTTPStreamRequest + { + // if we had a pending BEF download, invalidate it + stopListeningToBestEffortDownload(); + + // update state + _currentFAI = new FragmentAccessInformation(); + _currentFAI.fragId = nextFragmentId; + _currentFAI.fragDuration = 0; // the only code that cares about this value is notifyFragmentDuration + _currentFAI.fragmentEndTime = 0; // currently nobody cares about this value + playInProgress = true; + updateQuality(quality); + + // we don't know the fragment duration, so update the bootstrap frequently + bootstrapUpdateInterval = OSMFSettings.hdsMinimumBootstrapRefreshInterval; + + // figure out the url to fetch + var guessSegmentNumber:uint = uint(Math.ceil(Number(nextFragmentId) / + (_f4fIndexInfo.bestEffortFetchInfo.segmentDuration/_f4fIndexInfo.bestEffortFetchInfo.fragmentDuration))); + var guessUrl:String = constructFragmentRequest( + _serverBaseURL, // serverBaseURL + _streamNames[quality], // streamName + guessSegmentNumber, // segmentId + nextFragmentId); //fragmentId + bestEffortLog("Best effort fetch for fragment "+nextFragmentId+" with url "+guessUrl+". State is "+_bestEffortState); + + // clean up best effort state + _bestEffortDownloadReply = null; + _bestEffortNeedsToFireFragmentDuration = false; + + // recreate the best effort download monitor + // this protects us against overlapping best effort downloads + _bestEffortDownloaderMonitor = new EventDispatcher(); + _bestEffortDownloaderMonitor.addEventListener(HTTPStreamingEvent.DOWNLOAD_COMPLETE, onBestEffortDownloadComplete); + _bestEffortDownloaderMonitor.addEventListener(HTTPStreamingEvent.DOWNLOAD_ERROR, onBestEffortDownloadError); + + var streamRequest:HTTPStreamRequest = new HTTPStreamRequest( + HTTPStreamRequestKind.BEST_EFFORT_DOWNLOAD, + guessUrl, // url + -1, // retryAfter + _bestEffortDownloaderMonitor); // bestEffortDownloaderMonitor + + // trigger a refresh + adjustDelay(); + refreshBootstrapBox(quality); + + return streamRequest; + } + + /** + * @private + * + * if we had a pending BEF download, invalid it + **/ + private function stopListeningToBestEffortDownload():void + { + if(_bestEffortDownloaderMonitor != null) + { + _bestEffortDownloaderMonitor.removeEventListener(HTTPStreamingEvent.DOWNLOAD_COMPLETE, onBestEffortDownloadComplete); + _bestEffortDownloaderMonitor.removeEventListener(HTTPStreamingEvent.DOWNLOAD_ERROR, onBestEffortDownloadError); + _bestEffortDownloaderMonitor = null; + } + } + + /** + * @private + * + * Best effort backward seek needs to pre-parse the fragment in order to determine if the + * downloaded fragment actually contains the desired seek time. This method performs that parse. + **/ + private function bufferAndParseDownloadedBestEffortBytes(url:String, downloader:HTTPStreamDownloader):void + { + if(_bestEffortDownloadReply != null) + { + // if we already decided to skip or continue, don't parse new bytes + return; + } + // annoying way to pass argument into onBestEffortF4FHandlerNotifyBootstrapBox + _bestEffortNotifyBootstrapBoxInfo = { + downloader: downloader, + url: url + }; + try + { + var downloaderAvailableBytes:uint = downloader.totalAvailableBytes; + if(downloaderAvailableBytes > 0) + { + // buffer the downloaded bytes + var downloadInput:IDataInput = downloader.getBytes(downloaderAvailableBytes); + if(downloadInput != null) + { + downloadInput.readBytes(_bestEffortSeekBuffer, _bestEffortSeekBuffer.length, downloaderAvailableBytes); + } + + // feed the bytes to our f4f handler in order to parse out the bootstrap box. + while(_bestEffortF4FHandler.inputBytesNeeded > 0 && + _bestEffortF4FHandler.inputBytesNeeded <= _bestEffortSeekBuffer.bytesAvailable && + _bestEffortDownloadReply == null) // changes to non-null once we parse out the bootstrap box + { + _bestEffortF4FHandler.processFileSegment(_bestEffortSeekBuffer); + } + if(_bestEffortDownloadReply == HTTPStreamingEvent.DOWNLOAD_CONTINUE) + { + // we're done parsing and the HTTPStreamSource is going to process the file, + // restore the contents of the downloader + downloader.clearSavedBytes(); + _bestEffortSeekBuffer.position = 0; + downloader.appendToSavedBytes(_bestEffortSeekBuffer, _bestEffortSeekBuffer.length); + _bestEffortSeekBuffer.length = 0; // release the buffer + } + } + } + finally + { + _bestEffortNotifyBootstrapBoxInfo = null; + } + } + + /** + * @private + * + * Fired when the _bestEffortF4FHandler fires a NOTIFY_BOOTSTRAP_BOX event. + * This occurs during the pre-parsing that occurs in best effort backward fetch. + **/ + private function onBestEffortF4FHandlerNotifyBootstrapBox(event:HTTPStreamingFileHandlerEvent):void + { + var url:String = _bestEffortNotifyBootstrapBoxInfo.url as String; + var downloader:HTTPStreamDownloader = _bestEffortNotifyBootstrapBoxInfo.downloader as HTTPStreamDownloader; + + if(_bestEffortDownloadReply != null) + { + bestEffortLog("Best effort found a bootstrap box in the downloaded fragment, but we already replied."); + return; + } + + var bootstrapBox:AdobeBootstrapBox = event.bootstrapBox; + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + if(frt == null) + { + bestEffortLog("Best effort download contained an invalid bootstrap box."); + skipBestEffortFetch(url, downloader); + return; + } + + if(frt.fragmentDurationPairs.length != 1) + { + bestEffortLog("Best effort download has an FRT with more than 1 entry."); + skipBestEffortFetch(url, downloader); + return; + } + var fdp:FragmentDurationPair = frt.fragmentDurationPairs[0]; + if(fdp.duration == 0) + { + bestEffortLog("Best effort download FDP was a discontinuity."); + skipBestEffortFetch(url, downloader); + return; + } + var fragmentEndTime:Number = fdp.durationAccrued + fdp.duration; + if(_bestEffortSeekTime < fragmentEndTime) + { + bestEffortLog("Best effort found the desired time within the downloaded fragment."); + continueBestEffortFetch(url, downloader); + } + else + { + bestEffortLog("Best effort didn't find the desired time within the downloaded fragment."); + skipBestEffortFetch(url, downloader); + _bestEffortState = BEST_EFFORT_STATE_SEEK_FORWARD; + _bestEffortFailedFetches = 0; + } + } + + /** + * @private + * + * Invoked on HTTPStreamingEvent.DOWNLOAD_COMPLETE for best effort downloads + */ + private function onBestEffortDownloadComplete(event:HTTPStreamingEvent):void + { + if(_bestEffortDownloaderMonitor == null || + _bestEffortDownloaderMonitor != event.target as IEventDispatcher) + { + // we're receiving an event for a download we abandoned + return; + } + bestEffortLog("Best effort download complete"); + + // unregister the listeners + stopListeningToBestEffortDownload(); + + // forward the DOWNLOAD_COMPLETE to HTTPStreamSource, but change the reason + var clone:HTTPStreamingEvent = new HTTPStreamingEvent( + event.type, + event.bubbles, + event.cancelable, + event.fragmentDuration, + event.scriptDataObject, + event.scriptDataMode, + event.url, + event.bytesDownloaded, + HTTPStreamingEventReason.BEST_EFFORT, + event.downloader); + dispatchEvent(clone); + + if(_bestEffortDownloadReply != null) + { + // we already said "continue" or "skip" + return; + } + + switch(_bestEffortState) + { + case BEST_EFFORT_STATE_PLAY: + case BEST_EFFORT_STATE_SEEK_FORWARD: + // we successfully got a fragment. + // tell HTTPStreamSource to go ahead and process this fragment. + continueBestEffortFetch(event.url, event.downloader); + break; + case BEST_EFFORT_STATE_SEEK_BACKWARD: + // in backward seek state we want to parse the fragment in order to see if it + // has the time we want. parse any remaining bytes + bufferAndParseDownloadedBestEffortBytes(event.url, event.downloader); + if(_bestEffortDownloadReply == null) + { + // rare case: we downloaded the fragment, but we never found a bootstrap box. + // just keep going + skipBestEffortFetch(event.url, event.downloader); + } + break; + default: + bestEffortLog("Best effort download complete received while in unexpected state ("+_bestEffortState+")"); + break; + } + } + + /** + * @private + * + * Invoked on HTTPStreamingEvent.DOWNLOAD_ERROR for best effort downloads + */ + private function onBestEffortDownloadError(event:HTTPStreamingEvent):void + { + if(_bestEffortDownloaderMonitor == null || + _bestEffortDownloaderMonitor != event.target as IEventDispatcher) + { + // we're receiving an event for a download we abandoned + return; + } + // unregister our listeners + stopListeningToBestEffortDownload(); + + if(_bestEffortDownloadReply != null) + { + // special case: if we received some bytes and said "continue", but then the download failed. + // there means there was a connection problem mid-download + bestEffortLog("Best effort download error after we already decided to skip or continue."); + dispatchEvent(event); // this stops playback + } + else if(event.reason == HTTPStreamingEventReason.TIMEOUT) + { + // special case: the download took too long and all the retries failed + bestEffortLog("Best effort download timed out"); + dispatchEvent(event); // this stops playback + } + else + { + // failure due to http status code, or some other reason. resume best effort fetch + bestEffortLog("Best effort download error."); + ++_bestEffortFailedFetches; + skipBestEffortFetch(event.url, event.downloader); + } + } + + /** + * @private + * + * After initiating a best effort fetch, call this function to tell the + * HTTPStreamSource that it should not continue processing the downloaded + * fragment. + * + **/ + private function skipBestEffortFetch(url:String, downloader:HTTPStreamDownloader):void + { + if(_bestEffortDownloadReply != null) + { + bestEffortLog("Best effort wanted to skip fragment, but we're already replied with "+_bestEffortDownloadReply); + return; + } + bestEffortLog("Best effort skipping fragment."); + var event:HTTPStreamingEvent = new HTTPStreamingEvent(HTTPStreamingEvent.DOWNLOAD_SKIP, + false, // bubbles + false, // cancelable + 0, // fragmentDuration + null, // scriptDataObject + FLVTagScriptDataMode.NORMAL, // scriptDataMode + url, // url + 0, // bytesDownloaded + HTTPStreamingEventReason.BEST_EFFORT, // reason + downloader); // downloader + dispatchEvent(event); + + _bestEffortDownloadReply = HTTPStreamingEvent.DOWNLOAD_SKIP; + _bestEffortNeedsToFireFragmentDuration = false; + } + + /** + * @private + * + * After initiating a best effort fetch, call this function to tell the + * HTTPStreamSource that it may continue processing the downloaded fragment. + * A continue event is assumed to mean that best effort fetch is complete. + **/ + private function continueBestEffortFetch(url:String, downloader:HTTPStreamDownloader):void + { + if(_bestEffortDownloadReply != null) + { + bestEffortLog("Best effort wanted to continue, but we're already replied with "+_bestEffortDownloadReply); + return; + } + bestEffortLog("Best effort received a desirable fragment."); + + var event:HTTPStreamingEvent = new HTTPStreamingEvent(HTTPStreamingEvent.DOWNLOAD_CONTINUE, + false, // bubbles + false, // cancelable + 0, // fragmentDuration + null, // scriptDataObject + FLVTagScriptDataMode.NORMAL, // scriptDataMode + url, // url + 0, // bytesDownloaded + HTTPStreamingEventReason.BEST_EFFORT, // reason + downloader); // downloader + + // if we encounter liveness in the future, restart BEFs + // after the current fragment + _bestEffortLivenessRestartPoint = _currentFAI.fragId; + CONFIG::LOGGING + { + logger.debug("Setting _bestEffortLivenessRestartPoint to "+_bestEffortLivenessRestartPoint+" because of successful BEF download."); + } + + // remember that we started a download now + _bestEffortLastGoodFragmentDownloadTime = new Date(); + + dispatchEvent(event); + _bestEffortDownloadReply = HTTPStreamingEvent.DOWNLOAD_CONTINUE; + _bestEffortNeedsToFireFragmentDuration = true; + _bestEffortState = BEST_EFFORT_STATE_OFF; + } + + /** + * @private + * + * After initiating a best effort fetch, call this function to tell the + * HTTPStreamSource that a bad download error occurred. This causes HTTPStreamSource + * to stop playback with an error. + **/ + private function errorBestEffortFetch(url:String, downloader:HTTPStreamDownloader):void + { + bestEffortLog("Best effort fetch error."); + var event:HTTPStreamingEvent = new HTTPStreamingEvent(HTTPStreamingEvent.DOWNLOAD_ERROR, + false, // bubbles + false, // cancelable + 0, // fragmentDuration + null, // scriptDataObject + FLVTagScriptDataMode.NORMAL, // scriptDataMode + url, // url + 0, // bytesDownloaded + HTTPStreamingEventReason.BEST_EFFORT, // reason + downloader); // downloader + dispatchEvent(event); + _bestEffortDownloadReply = HTTPStreamingEvent.DOWNLOAD_ERROR; + _bestEffortNeedsToFireFragmentDuration = false; + } + + /** + * @private + * + * Fires FRAGMENT_DURATION in response to best effort fetch. + * + * Normal downloads fire FRAGMENT_DURATION before the download starts. + * In the best effort case, the duration is unavailable at request time and only + * becomes available after the fragment downloaded and parsed (the duration is + * passed along with the fragment's boostrap box). Thus, in the best effor case, + * FRAGMENT_DURATION is fired after the fragment download completes. + **/ + private function notifyFragmentDurationForBestEffort(bootstrapBox:AdobeBootstrapBox):void + { + if(!_bestEffortNeedsToFireFragmentDuration || // we only care if we haven't fired an event yet + bootstrapBox == null) // safety check + { + return; + } + _bestEffortNeedsToFireFragmentDuration = false; // don't invoke again + + // look up the fragment duration in the fragment run table. + var frt:AdobeFragmentRunTable = getFragmentRunTable(bootstrapBox); + if(frt == null) + { + return; + } + var fragmentDuration:Number = frt.getFragmentDuration(_currentFAI.fragId); + if(fragmentDuration == 0) // missing + { + return; + } + + // unlike notifyFragmentDuration, we do not change bootstrapUpdateInterval since + // we're getting the information at a later time (after we've downloaded the fragment) + + // fire the event + bestEffortLog("Best effort fetch firing the fragment duration."); + dispatchEvent(new HTTPStreamingEvent( + HTTPStreamingEvent.FRAGMENT_DURATION, // type + false, // bubbles + false, // cancelable + fragmentDuration / bootstrapBox.timeScale, // fragmentDuration + null, // scriptDataObject + null)); // scriptDataMode + } + + /** + * @private + * logging related to best effort fetch + **/ + private function bestEffortLog(s:String):void + { + CONFIG::LOGGING + { + logger.debug("BEST EFFORT: "+s); + } + } + + + /** + * @inheritDoc + */ + public override function get isBestEffortFetchEnabled():Boolean + { + return _bestEffortEnabled; + } + +// /** +// * @private +// * +// * Given timeBias, calculates the corresponding segment duration. +// */ +// internal function calculateSegmentDuration(abst:AdobeBootstrapBox, timeBias:Number):Number +// { +// var fragmentDurationPairs:Vector. = (abst.fragmentRunTables)[0].fragmentDurationPairs; +// var fragmentId:uint = currentFAI.fragId; +// +// var index:int = fragmentDurationPairs.length - 1; +// while (index >= 0) +// { +// var fragmentDurationPair:FragmentDurationPair = fragmentDurationPairs[index]; +// if (fragmentDurationPair.firstFragment <= fragmentId) +// { +// var duration:Number = fragmentDurationPair.duration; +// var durationAccrued:Number = fragmentDurationPair.durationAccrued; +// durationAccrued += (fragmentId - fragmentDurationPair.firstFragment) * fragmentDurationPair.duration; +// if (timeBias > 0) +// { +// duration -= (timeBias - durationAccrued); +// } +// +// return duration; +// } +// else +// { +// index--; +// } +// } +// +// return 0; +// } +// +// override public function getFragmentDurationFromUrl(fragmentUrl:String):Number +// { +// // we assume that there is only one afrt in bootstrap +// +// var tempFragmentId:String = fragmentUrl.substr(fragmentUrl.indexOf("Frag")+4, fragmentUrl.length); +// var fragId:uint = uint(tempFragmentId); +// var abst:AdobeBootstrapBox = bootstrapBoxes[_currentQuality]; +// var afrt:AdobeFragmentRunTable = abst.fragmentRunTables[0]; +// return afrt.getFragmentDuration(fragId); +// } + + + /// Internals + private var _currentQuality:int = -1; + private var _currentAdditionalHeader:ByteArray = null; + private var _currentFAI:FragmentAccessInformation = null; // annoying way to pass argument into onBestEffortF4FHandlerNotifyBootstrapBox + + private var _pureLiveOffset:Number = NaN; + + private var _f4fIndexInfo:HTTPStreamingF4FIndexInfo = null; + private var _bootstrapBoxes:Vector. = null; + private var _bootstrapBoxesURLs:Vector. = null; + private var _streamInfos:Vector. = null; + private var _streamNames:Array = null; + private var _streamQualityRates:Array = null; + private var _serverBaseURL:String = null; + + private var _delay:Number = 0.05; + + private var _indexUpdating:Boolean = false; + private var _pendingIndexLoads:int = 0; + private var _pendingIndexUpdates:int = 0; + private var _pendingIndexUrls:Object = new Object(); + + private var _invokedFromDvrGetStreamInfo:Boolean = false; + + + private var playInProgress:Boolean; + + private var bootstrapUpdateTimer:Timer; + private var bootstrapUpdateInterval:Number = 4000; + public static const DEFAULT_FRAGMENTS_THRESHOLD:uint = 5; + + // _bestEffortState values + private static const BEST_EFFORT_STATE_OFF:String = "off"; // not performing best effort fetch + private static const BEST_EFFORT_STATE_PLAY:String = "play"; // doing best effort for liveness or dropout + private static const BEST_EFFORT_STATE_SEEK_BACKWARD:String = "seekBackward"; // in the backward fetch phase of best effort seek + private static const BEST_EFFORT_STATE_SEEK_FORWARD:String = "seekForward"; // in the forward fetch phase of best effort seek + + private var _bestEffortInited:Boolean = false; // did we initialize _bestEffortEnabled? + private var _bestEffortEnabled:Boolean = false; // is BEF enabled at all? + private var _bestEffortState:String = BEST_EFFORT_STATE_OFF; // the current state of best effort + private var _bestEffortSeekTime:Number = 0; // the time we're seeking to + private var _bestEffortDownloaderMonitor:EventDispatcher = new EventDispatcher(); // Special dispatcher to handler the results of best-effort downloads. + private var _bestEffortFailedFetches:uint = 0; // The number of fetches that have failed so far. + private var _bestEffortDownloadReply:String = null; // After initiating a download, this is the DOWNLOAD_CONTINUE or DOWNLOAD_SKIP reply that we sent + private var _bestEffortNeedsToFireFragmentDuration:Boolean = false; // Do we need to fire the FRAGMENT_DURATION event for the next fragment? + private var _bestEffortF4FHandler:HTTPStreamingF4FFileHandler = new HTTPStreamingF4FFileHandler(); // used to pre-parse backward seeks + private var _bestEffortSeekBuffer:ByteArray = new ByteArray(); // buffer for saving bytes when pre-parsing backward seek + private var _bestEffortNotifyBootstrapBoxInfo:Object = null; // hacky way to pass arguments to helper functions + private var _bestEffortLivenessRestartPoint:uint = 0; // if we have to restart BEF for liveness, the fragment number of the first BEF - 1 + private var _bestEffortLastGoodFragmentDownloadTime:Date = null; + + // constants used by getNextRequestForBestEffortPlay: + private static const BEST_EFFORT_PLAY_SITUAUTION_NORMAL:String = "normal"; + private static const BEST_EFFORT_PLAY_SITUAUTION_DROPOUT:String = "dropout"; + private static const BEST_EFFORT_PLAY_SITUAUTION_LIVENESS:String = "liveness"; + private static const BEST_EFFORT_PLAY_SITUAUTION_DONE:String = "done"; + + CONFIG::LOGGING + { + private static const logger:org.osmf.logging.Logger = org.osmf.logging.Log.getLogger("org.osmf.net.httpstreaming.f4f.HTTPStreamF4FIndexHandler"); + } + } +} diff --git a/plugins/infopanel/build.xml b/plugins/infopanel/build.xml index 1d82485..51c806d 100644 --- a/plugins/infopanel/build.xml +++ b/plugins/infopanel/build.xml @@ -6,11 +6,14 @@ - - + + + + + diff --git a/plugins/menu/README.txt b/plugins/menu/README.txt index 4eff9ea..f9f1866 100644 --- a/plugins/menu/README.txt +++ b/plugins/menu/README.txt @@ -1,5 +1,10 @@ Version history: +3.2.13 (Nov 2013) +------ +- #71 fixes for menu plugin to disable currently selected items to prevent toggling and over states. + When other items are clicked and selected all other items will become enabled. + 3.2.12 ------ - #36 adjust the menu during fullscreen events as this is prevented once added to the stage. diff --git a/plugins/menu/build.properties b/plugins/menu/build.properties index 6a80079..2df0862 100644 --- a/plugins/menu/build.properties +++ b/plugins/menu/build.properties @@ -1,2 +1,2 @@ devkit-dir=../../lib/devkit -version=3.2.12 \ No newline at end of file +version=3.2.13 \ No newline at end of file diff --git a/plugins/menu/build.xml b/plugins/menu/build.xml index ba54672..57ce3ef 100644 --- a/plugins/menu/build.xml +++ b/plugins/menu/build.xml @@ -4,11 +4,14 @@ - - + + + + + diff --git a/plugins/menu/src/actionscript/org/flowplayer/menu/ui/Menu.as b/plugins/menu/src/actionscript/org/flowplayer/menu/ui/Menu.as index 430ca71..d82371a 100644 --- a/plugins/menu/src/actionscript/org/flowplayer/menu/ui/Menu.as +++ b/plugins/menu/src/actionscript/org/flowplayer/menu/ui/Menu.as @@ -124,7 +124,8 @@ package org.flowplayer.menu.ui { public function enableItems(enabled:Boolean, indexes:Array = null):void { log.debug("enableItems()"); iterateViews(function(item:MenuItem, index:int):void { - item.enabled = enabled; + //#71 enable items that are not currently selected as default. + if (!item.selected) item.enabled = enabled; }, indexes); } /** @@ -320,13 +321,17 @@ package org.flowplayer.menu.ui { itemConfig.width = model.widthPx; var item:MenuItem = new MenuItem(_player, itemConfig, _player.animationEngine); itemConfig.view = item; + item.mouseChildren = false; item.tabEnabled = true; item.tabIndex = tabIndex; var menu:Menu = this; item.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void { - if (! item.enabled) return; + //#71 return if the item is selected and currently disabled. + if (!MenuItem(event.target).enabled) return; if (menu.alpha == 0) return; + //#71 select the current item here, to disable and enable other items. + MenuItem(event.target).selected = true; _player.animationEngine.fadeOut(menu); itemConfig.fireCallback(model); deselectOtherItemsInGroup(itemConfig); diff --git a/plugins/menu/src/actionscript/org/flowplayer/menu/ui/MenuItem.as b/plugins/menu/src/actionscript/org/flowplayer/menu/ui/MenuItem.as index 6401f73..597ab26 100644 --- a/plugins/menu/src/actionscript/org/flowplayer/menu/ui/MenuItem.as +++ b/plugins/menu/src/actionscript/org/flowplayer/menu/ui/MenuItem.as @@ -37,34 +37,40 @@ package org.flowplayer.menu.ui { private var _mask:Sprite; private var _image:DisplayObject; private var _player:Flowplayer; + private var _selected:Boolean; private var _buffer:int = 10; public function MenuItem(player:Flowplayer, config:MenuItemConfig, animationEngine:AnimationEngine) { _player = player; + super(config, animationEngine); + } - override protected function onClicked(event:MouseEvent):void { - if (! itemConfig.toggle) return; - if (_tickMark.parent) { - removeChild(_tickMark); - } else { - addChild(_tickMark); - } + //#71 prevent the over state when the item is disabled + override protected function onMouseOver(event:MouseEvent):void { + if (!this.enabled) return; + super.onMouseOver(event); } public function set selected(selected:Boolean):void { -// if (! _tickMark) return; + + //#71 set the selection and enabled state of the item + _selected = selected; + this.enabled = !selected; + + if (! _tickMark) return; + if (selected && ! _tickMark.parent) { addChild(_tickMark); - } else if (_tickMark.parent) { + } else if (_tickMark.parent && !selected) { removeChild(_tickMark); } } public function get selected():Boolean { - return _tickMark.parent != null; + return _selected; } override protected function createFace():DisplayObjectContainer { @@ -78,6 +84,10 @@ package org.flowplayer.menu.ui { addChild(_tickMark); } } + + //#71 set the default selection + _selected = itemConfig.selected; + _text = addChild(TextUtil.createTextField(false, null, 12, true)) as TextField; _text.selectable = false; _text.type = TextFieldType.DYNAMIC; @@ -147,6 +157,8 @@ package org.flowplayer.menu.ui { _text.x = _image ? (_image.x + _image.width + _buffer) : _buffer; Arrange.center(_text, 0, height); } + + } override protected function doEnable(enabled:Boolean):void { diff --git a/plugins/pseudostreaming/README.txt b/plugins/pseudostreaming/README.txt index a5f7ae2..8941f92 100644 --- a/plugins/pseudostreaming/README.txt +++ b/plugins/pseudostreaming/README.txt @@ -1,5 +1,9 @@ Version history: +3.2.13 (Nov 2013) +----------------- +- #88 fix for bitrate switching updates on metadata change events since changes to the metadata events. + 3.2.12 ------ - #31 fix to dispatch start events properly when loading new items. diff --git a/plugins/pseudostreaming/build-byterange.xml b/plugins/pseudostreaming/build-byterange.xml index 122a16f..1d43012 100644 --- a/plugins/pseudostreaming/build-byterange.xml +++ b/plugins/pseudostreaming/build-byterange.xml @@ -2,13 +2,13 @@ - + - + diff --git a/plugins/pseudostreaming/build.properties b/plugins/pseudostreaming/build.properties index a0a586d..64b0219 100644 --- a/plugins/pseudostreaming/build.properties +++ b/plugins/pseudostreaming/build.properties @@ -1,3 +1,4 @@ devkit-dir=../../lib/devkit -osmf-dir=/Users/api/code/osmf/framework/OSMF -version=3.2.12 \ No newline at end of file +osmf-dir=../../lib/osmf/framework/OSMF +#osmf-dir=/Users/api/code/osmf/framework/OSMF +version=3.2.13 \ No newline at end of file diff --git a/plugins/pseudostreaming/build.xml b/plugins/pseudostreaming/build.xml index 0516715..c5ae8f1 100644 --- a/plugins/pseudostreaming/build.xml +++ b/plugins/pseudostreaming/build.xml @@ -2,14 +2,17 @@ - + - + + + + diff --git a/plugins/pseudostreaming/src/actionscript/org/flowplayer/pseudostreaming/PseudoStreamProvider.as b/plugins/pseudostreaming/src/actionscript/org/flowplayer/pseudostreaming/PseudoStreamProvider.as index 77d143e..f694357 100644 --- a/plugins/pseudostreaming/src/actionscript/org/flowplayer/pseudostreaming/PseudoStreamProvider.as +++ b/plugins/pseudostreaming/src/actionscript/org/flowplayer/pseudostreaming/PseudoStreamProvider.as @@ -1 +1 @@ -/* * This file is part of Flowplayer, http://flowplayer.org * * By: Anssi Piirainen, * Copyright (c) 2008-2011 Flowplayer Oy * H.264 support by: Arjen Wagenaar, * Copyright (c) 2009 CodeShop B.V. * * Released under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.pseudostreaming { import flash.events.NetStatusEvent; import flash.net.NetConnection; import flash.net.NetStream; import flash.system.Security; import org.flowplayer.controller.NetStreamControllingStreamProvider; import org.flowplayer.model.Clip; import org.flowplayer.model.ClipEvent; import org.flowplayer.model.ClipEventType; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginModel; import org.flowplayer.util.PropertyBinder; import org.flowplayer.view.Flowplayer; /** * @author api */ public class PseudoStreamProvider extends NetStreamControllingStreamProvider implements Plugin { private var _bufferStart:Number; private var _config:Config; private var _fileWithKeyframeInfo:String; private var _serverSeekInProgress:Boolean; private var _startSeekDone:Boolean; private var _model:PluginModel; private var _seekDataStore:DefaultSeekDataStore; private var _currentClip:Clip; private var _player:Flowplayer; /** * Called by the player to set my config. */ override public function onConfig(model:PluginModel):void { _model = model; _config = new PropertyBinder(new Config(), null).copyProperties(model.config) as Config; } /** * Called by the player to set the Flowplayer API. */ override public function onLoad(player:Flowplayer):void { log.info("onLoad()"); _model.dispatchOnLoad(); _player = player; } override protected function getClipUrl(clip:Clip):String { return _config.rangeRequests ? clip.completeUrl : appendQueryString(clip.completeUrl, 0); } override protected function doLoad(event:ClipEvent, netStream:NetStream, clip:Clip):void { log.debug("doLoad()"); _bufferStart = clip.currentTime; _startSeekDone = false; //#31 fix to dispatch start events properly when loading new items. _fileWithKeyframeInfo = null; if (! _seekDataStore || isNewFile(clip)) { _seekDataStore = new DefaultSeekDataStore(); } _seekDataStore.reset(); super.doLoad(event, netStream, clip); } private function isNewFile(clip:Clip):Boolean { return clip.url != _fileWithKeyframeInfo; } override protected function doSeek(event:ClipEvent, netStream:NetStream, seconds:Number):void { log.debug("doSeek()"); var target:Number = clip.start + seconds; //if target is near the end do a server seek to get the correct seekpoint to end correctly. if (target >= clip.duration) { serverSeek(netStream, target); return; } if (isInBuffer(target)) { log.debug("seeking inside buffer, target " + target + " seconds"); netStream.seek(_seekDataStore.inBufferSeekTarget(target)); } else if (event) { //#630 when the event is null we're in silent seek during controlbar dragging, only seek when not silent. silentSeek = false; serverSeek(netStream, target); } } override protected function doStop(event:ClipEvent, netStream:NetStream, closeStreamAndConnection:Boolean = false):void { //reset the current clip _currentClip = null; log.debug("Clearing clip and stopping "); super.doStop(event, netStream, closeStreamAndConnection); } override protected function doSwitchStream(event:ClipEvent, netStream:NetStream, clip:Clip, netStreamPlayOptions:Object = null):void { log.debug("doSwitchStream()"); clip.currentTime = time; _bufferStart = clip.currentTime; _currentClip = clip; log.debug("Switching stream with current time: " + clip.currentTime); //#385 regression issue caused by #365, added old switching code back in, and tested seeking and switching work correctly. clip.unbind(onMetaData); clip.onMetaData(switchOnMetaData); //#404 refactoring switchStream to suit changes with http streams and the use of the play2 method for resetting the stream. super.doSwitchStream(event, netStream, clip, netStreamPlayOptions); } private function switchOnMetaData(event:ClipEvent):void { log.debug("switchOnMetaData(), netStream " + netStream); clip.onMetaData(onMetaData); clip.unbind(switchOnMetaData); _startSeekDone = true; createSeekDataStore(Clip(event.target)); serverSeek(netStream, Clip(event.target).currentTime, true); } override public function get bufferStart():Number { if (! clip) return 0; return _bufferStart - clip.start; } override public function get bufferEnd():Number { if (! netStream) return 0; if (! clip) return 0; return bufferStart + netStream.bytesLoaded / netStream.bytesTotal * (clip.duration - bufferStart); } override protected function getCurrentPlayheadTime(netStream:NetStream):Number { if (! clip) return 0; var value:Number = _seekDataStore.currentPlayheadTime(netStream.time, clip.start); if (clip.duration != clip.durationFromMetadata && Math.abs(clip.duration - value) <= 1) { // duration configured and we are reaching the end. Round the value so that end is reached at the correct configured end point. return Math.round(value); } return value < 0 ? 0 : value; } override public function get allowRandomSeek():Boolean { if (! _seekDataStore) return false; return _seekDataStore.allowRandomSeek(); } private function isInBuffer(seconds:Number):Boolean { if (!_seekDataStore.dataAvailable) { log.debug("No keyframe data available, can only seek inside the buffer"); return true; } if (_config.rangeRequests) return false; return bufferStart <= seconds - clip.start && seconds - clip.start <= bufferEnd; } private function serverSeek(netStream:NetStream, seconds:Number, setBufferStart:Boolean = true):void { log.debug("serverSeek()"); if (setBufferStart) { _bufferStart = seconds; } if (_config.rangeRequests) { //#409 preventing seeking during silent seeking as is unstable with byte range seeking. if (silentSeek) return; log.debug("Making range request to server, usin URL " + clip.completeUrl); netStream.play(clip.completeUrl, seconds, _seekDataStore); return; } // issue #315 //this resets on replay before time is updated if (seconds == 0) { _seekDataStore.reset(); } var requestUrl:String = appendQueryString(clip.completeUrl, seconds); log.debug("doing server seek, url " + requestUrl); _serverSeekInProgress = true; netStream.play(requestUrl); } private function getByteRange(start:Number):Number { return _seekDataStore.getQueryStringStartValue(start); } private function appendQueryString(url:String, start:Number):String { log.debug("appendQueryString(), start == " + start); // http://flowplayer.org/forum/7/48461 if (start == 0) return url; //#565 append the url params to the generated start param //#568 fix parameter undefined issue var urlParts:Array = url.split("?"); var query:String = urlParts[0] + _config.queryString.replace("${start}", _seekDataStore.getQueryStringStartValue(start)) + (urlParts[1] !== undefined ? ("&" + urlParts[1]) : ""); log.debug("query string is " + query); return query; } override protected function onMetaData(event:ClipEvent):void { if (_startSeekDone) { return; } log.info("received metaData for clip" + Clip(event.target)); log.debug("clip file is " + clip.url); if (isNewFile(event.target as Clip)) { log.info("new file, creating new keyframe store"); createSeekDataStore(Clip(event.target)); clip.dispatch(ClipEventType.START, pauseAfterStart); // at this point we seek to the start position if it's greater than zero log.debug("seeking to start, pausing after start: " + pauseAfterStart); if (clip.start > 0) { serverSeek(netStream, clip.start, true); } else if (pauseAfterStart) { log.debug("started: pausing to pos 0 in netStream"); //#486 implement pauseToFrame to unmute audio when autoBuffering. pauseToFrame(); } } } override protected function pauseToFrame():void { log.debug("seeking to frame zero"); //#363 pause stream here after metadata or else no metadata is sent for rtmp clips pause(new ClipEvent(ClipEventType.PAUSE)); //#363 silent seek and force to seek to a frame or else video will not display silentSeek = true; //#602 don't seek to frame when start is set. if (!clip.start) netStream.seek(0); _player.muted = false; pauseAfterStart = false; } private function createSeekDataStore(clip:Clip):void { _seekDataStore = DefaultSeekDataStore.create(clip, clip.metaData); // # 75, events should be dispatched only once _fileWithKeyframeInfo = clip.url; } override protected function canDispatchBegin():Boolean { // before start seek we dispatch the initial onBegin if (! _startSeekDone) return true; if (_serverSeekInProgress) return false; return true; } override protected function onNetStatus(event:NetStatusEvent):void { log.info("onNetStatus: " + event.info.code); // #61, must wait buffer full instead of Play.Start for videos without metadatas. if (event.info.code == "NetStream.Buffer.Full") { // at this stage the server seek is in target, and we can dispatch the seek event //#630 regression move seek event dispatching to buffer full or else the time hasn't been updated yet. if (_serverSeekInProgress) { _startSeekDone = true; _serverSeekInProgress = false; //#568 when paused and seeking, silentseek is true therefore check also for paused to dispatch seek. if (paused || !silentSeek) { clip.dispatch(ClipEventType.SEEK, seekTarget); } if (this.switching) { //#385 dispatch switch complete event this.dispatchEvent(new ClipEvent(ClipEventType.SWITCH_COMPLETE)); this.switching = false; } else if (paused) { //#568 when seeking when paused pause the stream here again. netStream.pause(); } } log.debug("started, will pause after start: " + pauseAfterStart); // we need to pause here because the stream was started when server-seeking to start pos if (pauseAfterStart) { if (_startSeekDone) { //#363 pause after the server seek here switching = false; //#486 implement pauseToFrame to unmute audio when autoBuffering. pauseToFrame(); } } } else if (event.info.code == "NetStream.Seek.InvalidTime") { //#385 when scrubbing to the edge of the buffer seeking sometimes failed, need to reset the seek time to continue playback. log.debug("Buffer seek failed, setting seek time to " + event.info.details); netStream.seek(event.info.details); //to the closest valid seek time by looking in the info object netStream.resume(); } else if (event.info.code == "NetStream.Play.Stop") { //#403 when seeking to outside the allowed keyframes, stop is called, require to trigger buffer full to complete correctly. if (_serverSeekInProgress) { _startSeekDone = true; _serverSeekInProgress = false; clip.dispatch(ClipEventType.BUFFER_FULL); } } } public function getDefaultConfig():Object { return null; } override public function get type():String { return "pseudo"; } override protected function createNetStream(connection:NetConnection):NetStream { CONFIG::enableByteRange { import org.flowplayer.pseudostreaming.net.ByteRangeNetStream; if (_config.rangeRequests) { log.debug("Using ByteRangeNetStream"); Security.allowInsecureDomain("*"); Security.allowDomain("*"); if (_config.policyURL) Security.loadPolicyFile("xmlsocket://" + _config.policyURL); return new ByteRangeNetStream(connection); } } return null; } } } \ No newline at end of file +/* * This file is part of Flowplayer, http://flowplayer.org * * By: Anssi Piirainen, * Copyright (c) 2008-2011 Flowplayer Oy * H.264 support by: Arjen Wagenaar, * Copyright (c) 2009 CodeShop B.V. * * Released under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.pseudostreaming { import flash.events.NetStatusEvent; import flash.net.NetConnection; import flash.net.NetStream; import flash.system.Security; import org.flowplayer.controller.NetStreamControllingStreamProvider; import org.flowplayer.model.Clip; import org.flowplayer.model.ClipEvent; import org.flowplayer.model.ClipEventType; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginModel; import org.flowplayer.util.PropertyBinder; import org.flowplayer.view.Flowplayer; /** * @author api */ public class PseudoStreamProvider extends NetStreamControllingStreamProvider implements Plugin { private var _bufferStart:Number; private var _config:Config; private var _fileWithKeyframeInfo:String; private var _serverSeekInProgress:Boolean; private var _startSeekDone:Boolean; private var _model:PluginModel; private var _seekDataStore:DefaultSeekDataStore; private var _currentClip:Clip; private var _player:Flowplayer; /** * Called by the player to set my config. */ override public function onConfig(model:PluginModel):void { _model = model; _config = new PropertyBinder(new Config(), null).copyProperties(model.config) as Config; } /** * Called by the player to set the Flowplayer API. */ override public function onLoad(player:Flowplayer):void { log.info("onLoad()"); _model.dispatchOnLoad(); _player = player; } override protected function getClipUrl(clip:Clip):String { return _config.rangeRequests ? clip.completeUrl : appendQueryString(clip.completeUrl, 0); } override protected function doLoad(event:ClipEvent, netStream:NetStream, clip:Clip):void { log.debug("doLoad()"); _bufferStart = clip.currentTime; _startSeekDone = false; //#31 fix to dispatch start events properly when loading new items. _fileWithKeyframeInfo = null; if (! _seekDataStore || isNewFile(clip)) { _seekDataStore = new DefaultSeekDataStore(); } _seekDataStore.reset(); super.doLoad(event, netStream, clip); } private function isNewFile(clip:Clip):Boolean { return clip.url != _fileWithKeyframeInfo; } override protected function doSeek(event:ClipEvent, netStream:NetStream, seconds:Number):void { log.debug("doSeek()"); var target:Number = clip.start + seconds; //if target is near the end do a server seek to get the correct seekpoint to end correctly. if (target >= clip.duration) { serverSeek(netStream, target); return; } if (isInBuffer(target)) { log.debug("seeking inside buffer, target " + target + " seconds"); netStream.seek(_seekDataStore.inBufferSeekTarget(target)); } else if (event) { //#630 when the event is null we're in silent seek during controlbar dragging, only seek when not silent. silentSeek = false; serverSeek(netStream, target); } } override protected function doStop(event:ClipEvent, netStream:NetStream, closeStreamAndConnection:Boolean = false):void { //reset the current clip _currentClip = null; log.debug("Clearing clip and stopping "); super.doStop(event, netStream, closeStreamAndConnection); } override protected function doSwitchStream(event:ClipEvent, netStream:NetStream, clip:Clip, netStreamPlayOptions:Object = null):void { log.debug("doSwitchStream()"); clip.currentTime = time; _bufferStart = clip.currentTime; _currentClip = clip; log.debug("Switching stream with current time: " + clip.currentTime); //#385 regression issue caused by #365, added old switching code back in, and tested seeking and switching work correctly. clip.unbind(onMetaData); //#88 fix for bitrate switching updates on metadata change events since changes to the metadata events. clip.onMetaDataChange(switchOnMetaData); //#404 refactoring switchStream to suit changes with http streams and the use of the play2 method for resetting the stream. super.doSwitchStream(event, netStream, clip, netStreamPlayOptions); } private function switchOnMetaData(event:ClipEvent):void { log.debug("switchOnMetaData(), netStream " + netStream); clip.onMetaData(onMetaData); clip.onMetaDataChange(onMetaData); clip.unbind(switchOnMetaData); _startSeekDone = true; createSeekDataStore(Clip(event.target)); serverSeek(netStream, Clip(event.target).currentTime, true); } override public function get bufferStart():Number { if (! clip) return 0; return _bufferStart - clip.start; } override public function get bufferEnd():Number { if (! netStream) return 0; if (! clip) return 0; return bufferStart + netStream.bytesLoaded / netStream.bytesTotal * (clip.duration - bufferStart); } override protected function getCurrentPlayheadTime(netStream:NetStream):Number { if (! clip) return 0; var value:Number = _seekDataStore.currentPlayheadTime(netStream.time, clip.start); if (clip.duration != clip.durationFromMetadata && Math.abs(clip.duration - value) <= 1) { // duration configured and we are reaching the end. Round the value so that end is reached at the correct configured end point. return Math.round(value); } return value < 0 ? 0 : value; } override public function get allowRandomSeek():Boolean { if (! _seekDataStore) return false; return _seekDataStore.allowRandomSeek(); } private function isInBuffer(seconds:Number):Boolean { if (!_seekDataStore.dataAvailable) { log.debug("No keyframe data available, can only seek inside the buffer"); return true; } if (_config.rangeRequests) return false; return bufferStart <= seconds - clip.start && seconds - clip.start <= bufferEnd; } private function serverSeek(netStream:NetStream, seconds:Number, setBufferStart:Boolean = true):void { log.debug("serverSeek()"); if (setBufferStart) { _bufferStart = seconds; } if (_config.rangeRequests) { //#409 preventing seeking during silent seeking as is unstable with byte range seeking. if (silentSeek) return; log.debug("Making range request to server, usin URL " + clip.completeUrl); netStream.play(clip.completeUrl, seconds, _seekDataStore); return; } // issue #315 //this resets on replay before time is updated if (seconds == 0) { _seekDataStore.reset(); } var requestUrl:String = appendQueryString(clip.completeUrl, seconds); log.debug("doing server seek, url " + requestUrl); _serverSeekInProgress = true; netStream.play(requestUrl); } private function getByteRange(start:Number):Number { return _seekDataStore.getQueryStringStartValue(start); } private function appendQueryString(url:String, start:Number):String { log.debug("appendQueryString(), start == " + start); // http://flowplayer.org/forum/7/48461 if (start == 0) return url; //#565 append the url params to the generated start param //#568 fix parameter undefined issue var urlParts:Array = url.split("?"); var query:String = urlParts[0] + _config.queryString.replace("${start}", _seekDataStore.getQueryStringStartValue(start)) + (urlParts[1] !== undefined ? ("&" + urlParts[1]) : ""); log.debug("query string is " + query); return query; } override protected function onMetaData(event:ClipEvent):void { if (_startSeekDone) { return; } log.info("received metaData for clip" + Clip(event.target)); log.debug("clip file is " + clip.url); if (isNewFile(event.target as Clip)) { log.info("new file, creating new keyframe store"); createSeekDataStore(Clip(event.target)); clip.dispatch(ClipEventType.START, pauseAfterStart); // at this point we seek to the start position if it's greater than zero log.debug("seeking to start, pausing after start: " + pauseAfterStart); if (clip.start > 0) { serverSeek(netStream, clip.start, true); } else if (pauseAfterStart) { log.debug("started: pausing to pos 0 in netStream"); //#486 implement pauseToFrame to unmute audio when autoBuffering. pauseToFrame(); } } } override protected function pauseToFrame():void { log.debug("seeking to frame zero"); //#363 pause stream here after metadata or else no metadata is sent for rtmp clips pause(new ClipEvent(ClipEventType.PAUSE)); //#363 silent seek and force to seek to a frame or else video will not display silentSeek = true; //#602 don't seek to frame when start is set. if (!clip.start) netStream.seek(0); _player.muted = false; pauseAfterStart = false; } private function createSeekDataStore(clip:Clip):void { _seekDataStore = DefaultSeekDataStore.create(clip, clip.metaData); // # 75, events should be dispatched only once _fileWithKeyframeInfo = clip.url; } override protected function canDispatchBegin():Boolean { // before start seek we dispatch the initial onBegin if (! _startSeekDone) return true; if (_serverSeekInProgress) return false; return true; } override protected function onNetStatus(event:NetStatusEvent):void { log.info("onNetStatus: " + event.info.code); // #61, must wait buffer full instead of Play.Start for videos without metadatas. if (event.info.code == "NetStream.Buffer.Full") { // at this stage the server seek is in target, and we can dispatch the seek event //#630 regression move seek event dispatching to buffer full or else the time hasn't been updated yet. if (_serverSeekInProgress) { _startSeekDone = true; _serverSeekInProgress = false; //#568 when paused and seeking, silentseek is true therefore check also for paused to dispatch seek. if (paused || !silentSeek) { clip.dispatch(ClipEventType.SEEK, seekTarget); } if (this.switching) { //#385 dispatch switch complete event this.dispatchEvent(new ClipEvent(ClipEventType.SWITCH_COMPLETE)); this.switching = false; } else if (paused) { //#568 when seeking when paused pause the stream here again. netStream.pause(); } } log.debug("started, will pause after start: " + pauseAfterStart); // we need to pause here because the stream was started when server-seeking to start pos if (pauseAfterStart) { if (_startSeekDone) { //#363 pause after the server seek here switching = false; //#486 implement pauseToFrame to unmute audio when autoBuffering. pauseToFrame(); } } } else if (event.info.code == "NetStream.Seek.InvalidTime") { //#385 when scrubbing to the edge of the buffer seeking sometimes failed, need to reset the seek time to continue playback. log.debug("Buffer seek failed, setting seek time to " + event.info.details); netStream.seek(event.info.details); //to the closest valid seek time by looking in the info object netStream.resume(); } else if (event.info.code == "NetStream.Play.Stop") { //#403 when seeking to outside the allowed keyframes, stop is called, require to trigger buffer full to complete correctly. if (_serverSeekInProgress) { _startSeekDone = true; _serverSeekInProgress = false; clip.dispatch(ClipEventType.BUFFER_FULL); } } } public function getDefaultConfig():Object { return null; } override public function get type():String { return "pseudo"; } override protected function createNetStream(connection:NetConnection):NetStream { CONFIG::enableByteRange { import org.flowplayer.pseudostreaming.net.ByteRangeNetStream; if (_config.rangeRequests) { log.debug("Using ByteRangeNetStream"); Security.allowInsecureDomain("*"); Security.allowDomain("*"); if (_config.policyURL) Security.loadPolicyFile("xmlsocket://" + _config.policyURL); return new ByteRangeNetStream(connection); } } return null; } } } \ No newline at end of file diff --git a/plugins/qosmonitor/build.xml b/plugins/qosmonitor/build.xml index 476fa13..4a82e8f 100644 --- a/plugins/qosmonitor/build.xml +++ b/plugins/qosmonitor/build.xml @@ -9,10 +9,13 @@ - - + + + + + diff --git a/plugins/rtmp/README.txt b/plugins/rtmp/README.txt index ea92523..f5a545e 100644 --- a/plugins/rtmp/README.txt +++ b/plugins/rtmp/README.txt @@ -1,5 +1,10 @@ Version history: +3.2.13 (Nov 2013) +------ +- #77 for live streams once unpublished, stop the player to prevent streamnotfound errors reconnecting or if the server shuts down. +- #28 fix for live rtmp servers which don't provide metadata needed for red5 and vp6 live streaming, 1500ms should give metadata time if available + 3.2.12 ------ - fix for resuming live streams with Wowza diff --git a/plugins/rtmp/build.properties b/plugins/rtmp/build.properties index cc87b2c..9595b06 100644 --- a/plugins/rtmp/build.properties +++ b/plugins/rtmp/build.properties @@ -1,2 +1,2 @@ -version=3.2.12 +version=3.2.13 devkit-dir=../../lib/devkit \ No newline at end of file diff --git a/plugins/rtmp/build.xml b/plugins/rtmp/build.xml index 751df23..6ede9f4 100644 --- a/plugins/rtmp/build.xml +++ b/plugins/rtmp/build.xml @@ -5,12 +5,15 @@ - - + + + + + diff --git a/plugins/rtmp/src/actionscript/org/flowplayer/rtmp/RTMPStreamProvider.as b/plugins/rtmp/src/actionscript/org/flowplayer/rtmp/RTMPStreamProvider.as index 94ed300..a73ab8b 100644 --- a/plugins/rtmp/src/actionscript/org/flowplayer/rtmp/RTMPStreamProvider.as +++ b/plugins/rtmp/src/actionscript/org/flowplayer/rtmp/RTMPStreamProvider.as @@ -1 +1 @@ -/* * This file is part of Flowplayer, http://flowplayer.org * * By: Anssi Piirainen, * Copyright (c) 2008 Flowplayer Ltd * * Released under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.rtmp { import flash.events.NetStatusEvent; import flash.events.Event; import flash.utils.setTimeout; CONFIG::FLASH_10_1 { import flash.net.GroupSpecifier; } import flash.net.NetConnection; import flash.net.NetStream; import org.flowplayer.controller.ConnectionProvider; import org.flowplayer.controller.NetStreamControllingStreamProvider; import org.flowplayer.model.Clip; import org.flowplayer.model.ClipEvent; import org.flowplayer.model.ClipEventType; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginModel; import org.flowplayer.util.PropertyBinder; import org.flowplayer.util.URLUtil; import org.flowplayer.util.VersionUtil; import org.flowplayer.view.Flowplayer; /** * A RTMP stream provider. Supports following: *
        *
      • Starting in the middle of the clip's timeline using the clip.start property.
      • *
      • Stopping before the clip file ends using the clip.duration property.
      • *
      • Ability to combine a group of clips into one gapless stream.
      • *
      *

      * Stream group is configured in a clip like this: * * { streams: [ { url: 'metacafe', duration: 20 }, { url: 'honda_accord', start: 10, duration: 20 } ] } * * The group is played back seamlessly as one gapless stream. The individual streams in a group can * be cut out from a larger file using the 'start' and 'duration' properties as shown in the example above. * * @author api */ public class RTMPStreamProvider extends NetStreamControllingStreamProvider implements Plugin { private var _config : Config; private var _model : PluginModel; private var _bufferStart : Number = 0; private var _player : Flowplayer; private var _rtmpConnectionProvider : ConnectionProvider; private var _subscribingConnectionProvider : ConnectionProvider; private var _durQueryingConnectionProvider : ConnectionProvider; private var _previousClip : Clip; private var _dvrLiveStarted : Boolean; private var _receivedStop : Boolean; private var _stepping:Boolean; private var _endSeekBuffer:Number = 0.1; private var _reconnecting:Boolean; private var _reconnectTime:Number = -1; private var _id3Stream:NetStream; private var _streamsStarted:Boolean; private var _hasNext:Boolean; override protected function createNetStream(connection:NetConnection):NetStream { CONFIG::FLASH_10_1 { if (clip.getCustomProperty("p2pGroupSpec")) { return createP2PStream(connection); } } log.debug("createNetStream(), (non p2p)"); return new NetStream(connection); } CONFIG::FLASH_10_1 private function createP2PStream(connection:NetConnection):NetStream { log.debug("createP2PStream(), p2pGroup == " + String(clip.getCustomProperty("p2pGroupSpec"))); return new NetStream(connection, String(clip.getCustomProperty("p2pGroupSpec"))); } CONFIG::FLASH_10_1 override protected function onNetStreamCreated(netStream:NetStream):void { if (netStream.hasOwnProperty("backBufferLength")) { log.debug("setting backBufferLength to " + clip.backBufferLength + " seconds"); netStream.backBufferTime = clip.backBufferLength; netStream.inBufferSeek = _config.inBufferSeek; } } override protected function onNetStatus(event:NetStatusEvent) : void { log.info("onNetStatus(), code: " + event.info.code + ", paused? " + paused + ", seeking? " + seeking); switch(event.info.code){ case "NetStream.Play.Start": if (_stepping) return; if (paused){ dispatchEvent(new ClipEvent(ClipEventType.SEEK, seekTarget)); seeking = false; } if (_config.dvrSubscribeLive && !_dvrLiveStarted){ netStream.seek(1000000); _dvrLiveStarted = true; } //#593 if this clip has a stream group, prevent onbegin from dispatching during playback. if (hasStreamGroup(clip)) _streamsStarted = true; break; case "NetStream.Play.Stop": _stepping = false; _receivedStop = true; _streamsStarted = false; _hasNext = _player.playlist.hasNext(); break; case "NetStream.Buffer.Empty": if (_stepping) return; //#614 check if the current playlist item is the previously loaded item to prevent ending early as the provider stream is still open. //if (_currentClip.type.type == "audio") { //doStop(null, netStream, true); //clip.dispatchBeforeEvent(new ClipEvent(ClipEventType.BUFFER_FULL)); // return; // } //case "NetStream.Buffer.Flush": // #107, dispatch finish when we already got a stop // #113, dispatch finish also when we're around the end of the clip // && clip. duration > 0 added for this http://flowplayer.org/forum/8/46963 // #403 when seeking to the duration the buffer will flush and needs to end correctly //#614 also test if there is no more playlist items left to dispatch finish. if ((_receivedStop || clip.duration - _player.status.time < 1 && clip.duration > 0) && !_hasNext) { clip.dispatchBeforeEvent(new ClipEvent(ClipEventType.FINISH)); } break; case "NetStream.Play.Transition": log.debug("Stream Transition -- " + event.info.details); dispatchEvent(new ClipEvent(ClipEventType.SWITCH, event.info.details)); break; case "NetStream.Play.Failed": case "NetStream.Failed": log.debug("Stream Transition Failed -- " + event.info.description); dispatchEvent(new ClipEvent(ClipEventType.SWITCH_FAILED, event.info.description)); switchStreamNative(); break; case "NetStream.Step.Notify": _stepping = true; break; case "NetStream.Unpause.Notify": _stepping = false; break; case "NetConnection.Connect.NetworkChange": //#430 on intermittent client connection failures, attempt a reconnect, or wait until connection is active again for rtmp connections. //Do not attempt to connect here, this may be done in the connection providers. if (_reconnectTime < 0) _reconnectTime = time; _reconnecting = true; break; } return; } private function onPlayStatus(event:ClipEvent) : void { log.debug("onPlayStatus() -- " + event.info.code, event.info); if (event.info.code == "NetStream.Play.TransitionComplete"){ dispatchEvent(new ClipEvent(ClipEventType.SWITCH_COMPLETE)); } return; } override protected function canDispatchBegin():Boolean { return !_stepping && !_streamsStarted; } /** * Called by the player to set my model object. */ override public function onConfig(model : PluginModel) : void { log.debug("onConfig()"); if (_model) return; _model = model; _config = new PropertyBinder(new Config(), null).copyProperties(model.config) as Config; } /** * Called by the player to set the Flowplayer API. */ override public function onLoad(player : Flowplayer) : void { _player = player; if (_config.streamCallbacks) { log.debug("configuration has " + _config.streamCallbacks + " stream callbacks"); } else { log.debug("no stream callbacks in config"); } _model.dispatchOnLoad(); // _model.dispatchError(PluginError.INIT_FAILED, "failed for no fucking reason"); } public function get durationFunc() : String { return clip.getCustomProperty("rtmpDurationFunc") as String || _config.durationFunc; } override protected function getConnectionProvider(clip : Clip) : ConnectionProvider { if (clip.getCustomProperty("rtmpSubscribe") || _config.subscribe) { log.debug("using FCSubscribe to connect"); if (!_subscribingConnectionProvider) { _subscribingConnectionProvider = new SubscribingRTMPConnectionProvider(_config); } return _subscribingConnectionProvider; } if (durationFunc) { log.debug("using " + durationFunc + " to fetch stream duration from the server"); if (!_durQueryingConnectionProvider) { _durQueryingConnectionProvider = new DurationQueryingRTMPConnectionProvider(_config, durationFunc); } return _durQueryingConnectionProvider; } log.debug("using the default connection provider"); if (!_rtmpConnectionProvider) { _rtmpConnectionProvider = new RTMPConnectionProvider(_config); } return _rtmpConnectionProvider; } /** * Overridden to allow random seeking in the timeline. */ override public function get allowRandomSeek() : Boolean { return true; } /** * Starts loading using the specified netStream and clip. */ override protected function doLoad(event : ClipEvent, netStream : NetStream, clip : Clip) : void { _bufferStart = 0; _stepping = false; _streamsStarted = false; if (hasStreamGroup(clip)) { startStreamGroup(clip, netStream); } else { startStream(clip); } } /** * onId3 obtain the metadata for an mp3 stream * @param info */ public function onId3(info:Object):void { clip.metaData = info; clip.dispatch(ClipEventType.METADATA); _id3Stream.close(); _id3Stream = null; } private function startStream(clip : Clip) : void { _receivedStop = false; var streamName : String = getStreamName(clip); var start : int = clip.start > 0 ? clip.start : 0; var duration : int = clip.duration > 0 ? clip.duration + 1 /* let some time to the duration tracker */: -1; log.debug("startStream() starting playback of stream '" + streamName + "', start: " + start + ", duration: " + duration); clip.onPlayStatus(onPlayStatus); if ( clip.live ) { netStream.play(streamName, -1); } else if (_config.dvrSubscribeStart || _config.dvrSubscribeLive) { netStream.play(streamName, 0, -1); } else { netStream.play(streamName, start, duration); } //#545 for mp3 streams, we need to call the file with an id3 prefix on the server to obtain the metadata if (clip.type.type == "audio") { if (!_id3Stream) _id3Stream = new NetStream(this.netConnection); _id3Stream.client = this; _id3Stream.addEventListener(Event.ID3,onId3); _id3Stream.play("id3:" + streamName.slice(4)); } } private function getStreamName(clip : Clip) : String { log.debug("getStreamName() " + clip); //#494 generate the complete url only if a base url is set. regression caused by #412. var url : String = (clip.baseUrl ? clip.completeUrl : clip.url); //#439 just check for an rtmp complete url when parsing complete urls to allow other complete urls used for re-streaming to pass through. if (URLUtil.isRtmpUrl(url)) { //TODO: Parse rtmp complete urls correctly. var lastSlashPos : Number = url.lastIndexOf("/"); return url.substring(lastSlashPos + 1); } return clip.url; } /** * Overridden to be able to store the latest seek target position. */ override protected function doSeek(event : ClipEvent, netStream : NetStream, seconds : Number) : void { _receivedStop = false; //#424 force an end seek buffer to allow some playback and prevent hanging when seeking to the duration. seconds = (seconds >= clip.duration ? clip.duration - _endSeekBuffer : seconds); //#534 don't round seek times for frame accurate seeking //var time:int = int(seconds); _bufferStart = seconds; super.doSeek(event, netStream, seconds); } override protected function doSwitchStream(event : ClipEvent, netStream : NetStream, clip : Clip, netStreamPlayOptions : Object = null) : void { _receivedStop = false; _previousClip = clip; //#406 don't run version checks here anymore to work with Flash 11 if (netStreamPlayOptions) { import flash.net.NetStreamPlayOptions; if (netStreamPlayOptions is NetStreamPlayOptions) { log.debug("doSwitchStream() calling play2()") netStream.play2(netStreamPlayOptions as NetStreamPlayOptions); } } else { //fix for #338, don't set the currentTime when dynamic stream switching _bufferStart = clip.currentTime; clip.currentTime = Math.floor(_previousClip.currentTime + netStream.time); switchStreamNative(); dispatchEvent(event); } } private function switchStreamNative() : void { log.debug("Switching stream with netstream time: " + clip.currentTime); netStream.play(clip.url, clip.live ? (-1) : (clip.currentTime)); return; } override public function get bufferStart() : Number { if (!clip) return 0; if (!netStream) return 0; var backBuffer:Number = 0; CONFIG::FLASH_10_1 { backBuffer = netStream.backBufferLength; } //var backBuffer:Number = netStream.hasOwnProperty("backBufferLength") ? netStream.backBufferLength : 0; //var backBuffer:Number = netStream.backBufferLength; return Math.max(0, getCurrentPlayheadTime(netStream) - backBuffer); } override public function get bufferEnd() : Number { if (!clip) return 0; if (!netStream) return 0; return getCurrentPlayheadTime(netStream) + netStream.bufferLength; } /** * Starts streaming a stream group. */ protected function startStreamGroup(clip : Clip, netStream : NetStream) : void { var streams : Array = clip.customProperties.streams as Array; _receivedStop = false; log.debug("starting a group of " + streams.length + " streams"); var totalDuration : int = 0; for (var i : Number = 0;i < streams.length;i++) { var stream : Object = streams[i]; var duration : int = getDuration(stream); var reset : Object = i == 0 ? 1 : 0; netStream.play(stream.url, getStart(stream), duration, reset); if (duration > 0) { totalDuration += duration; } log.debug("added " + stream.url + " to playlist, total duration " + totalDuration); } if (totalDuration > 0) { clip.duration = totalDuration; } } /** * Does the specified clip have a configured stream group? */ protected function hasStreamGroup(clip : Clip) : Boolean { return clip.customProperties && clip.customProperties.streams; } private function getDuration(stream : Object) : int { return stream.duration || -1; } private function getStart(stream : Object) : int { return stream.start || 0; } public function getDefaultConfig() : Object { return null; } override public function get type() : String { return "rtmp"; } override public function get time() : Number { if (!netStream) return 0; return getCurrentPlayheadTime(netStream) + clip.currentTime; } //#363 overridable pause to frame for different seek functionality. override protected function pauseToFrame():void { //#594 when pausing to a frame, set a 100ms timeout to pause instead of a seek which was causing some streams to hang. setTimeout(function():void { log.debug("seeking to frame zero"); //#363 pause stream here after metadata or else no metadata is sent for rtmp clips pause(new ClipEvent(ClipEventType.PAUSE)); //#363 silent seek and force to seek to a frame or else video will not display silentSeek = true; pauseAfterStart = false; //#486 unmute when auto buffering and pausing to a frame. _player.muted = false; }, 100); } override protected function onMetaData(event:ClipEvent):void { super.onMetaData(event); //#430 if there is a client connection failure reconnect to the specified time for rtmp streams. if (_reconnecting) { seek(null, _reconnectTime); _reconnectTime = -1; _reconnecting = false; } } } } \ No newline at end of file +/** * This file is part of Flowplayer, http://flowplayer.org * * By: Anssi Piirainen, * Copyright (c) 2008-2013 Flowplayer Ltd * * Released under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.rtmp { import flash.events.NetStatusEvent; import flash.events.Event; import flash.utils.setTimeout; CONFIG::FLASH_10_1 { import flash.net.GroupSpecifier; } import flash.net.NetConnection; import flash.net.NetStream; import org.flowplayer.controller.ConnectionProvider; import org.flowplayer.controller.NetStreamControllingStreamProvider; import org.flowplayer.model.Clip; import org.flowplayer.model.ClipEvent; import org.flowplayer.model.ClipEventType; import org.flowplayer.model.Plugin; import org.flowplayer.model.PluginModel; import org.flowplayer.util.PropertyBinder; import org.flowplayer.util.URLUtil; import org.flowplayer.util.VersionUtil; import org.flowplayer.view.Flowplayer; /** * A RTMP stream provider. Supports following: *

        *
      • Starting in the middle of the clip's timeline using the clip.start property.
      • *
      • Stopping before the clip file ends using the clip.duration property.
      • *
      • Ability to combine a group of clips into one gapless stream.
      • *
      *

      * Stream group is configured in a clip like this: * * { streams: [ { url: 'metacafe', duration: 20 }, { url: 'honda_accord', start: 10, duration: 20 } ] } * * The group is played back seamlessly as one gapless stream. The individual streams in a group can * be cut out from a larger file using the 'start' and 'duration' properties as shown in the example above. * * @author api */ public class RTMPStreamProvider extends NetStreamControllingStreamProvider implements Plugin { private var _config : Config; private var _model : PluginModel; private var _bufferStart : Number = 0; private var _player : Flowplayer; private var _rtmpConnectionProvider : ConnectionProvider; private var _subscribingConnectionProvider : ConnectionProvider; private var _durQueryingConnectionProvider : ConnectionProvider; private var _previousClip : Clip; private var _dvrLiveStarted : Boolean; private var _receivedStop : Boolean; private var _stepping:Boolean; private var _endSeekBuffer:Number = 0.1; private var _reconnecting:Boolean; private var _reconnectTime:Number = -1; private var _id3Stream:NetStream; private var _streamsStarted:Boolean; private var _hasNext:Boolean; override protected function createNetStream(connection:NetConnection):NetStream { CONFIG::FLASH_10_1 { if (clip.getCustomProperty("p2pGroupSpec")) { return createP2PStream(connection); } } log.debug("createNetStream(), (non p2p)"); return new NetStream(connection); } CONFIG::FLASH_10_1 private function createP2PStream(connection:NetConnection):NetStream { log.debug("createP2PStream(), p2pGroup == " + String(clip.getCustomProperty("p2pGroupSpec"))); return new NetStream(connection, String(clip.getCustomProperty("p2pGroupSpec"))); } CONFIG::FLASH_10_1 override protected function onNetStreamCreated(netStream:NetStream):void { if (netStream.hasOwnProperty("backBufferLength")) { log.debug("setting backBufferLength to " + clip.backBufferLength + " seconds"); netStream.backBufferTime = clip.backBufferLength; netStream.inBufferSeek = _config.inBufferSeek; } } override protected function onNetStatus(event:NetStatusEvent) : void { log.info("onNetStatus(), code: " + event.info.code + ", paused? " + paused + ", seeking? " + seeking); switch(event.info.code){ case "NetStream.Play.Start": if (_stepping) return; if (paused){ dispatchEvent(new ClipEvent(ClipEventType.SEEK, seekTarget)); seeking = false; } if (_config.dvrSubscribeLive && !_dvrLiveStarted){ netStream.seek(1000000); _dvrLiveStarted = true; } //#28 fix for live rtmp servers which don't provide metadata, 1500ms should give metadata time if available if (clip.live) { setTimeout(function():void { if (!clip.startDispatched) { clip.dispatch(ClipEventType.START, false); clip.startDispatched = true; } }, 1500); } //#593 if this clip has a stream group, prevent onbegin from dispatching during playback. if (hasStreamGroup(clip)) _streamsStarted = true; break; case "NetStream.Play.Stop": _stepping = false; _receivedStop = true; _streamsStarted = false; _hasNext = _player.playlist.hasNext(); break; case "NetStream.Buffer.Empty": if (_stepping) return; //#614 check if the current playlist item is the previously loaded item to prevent ending early as the provider stream is still open. //if (_currentClip.type.type == "audio") { //doStop(null, netStream, true); //clip.dispatchBeforeEvent(new ClipEvent(ClipEventType.BUFFER_FULL)); // return; // } //case "NetStream.Buffer.Flush": // #107, dispatch finish when we already got a stop // #113, dispatch finish also when we're around the end of the clip // && clip. duration > 0 added for this http://flowplayer.org/forum/8/46963 // #403 when seeking to the duration the buffer will flush and needs to end correctly //#614 also test if there is no more playlist items left to dispatch finish. if ((_receivedStop || clip.duration - _player.status.time < 1 && clip.duration > 0) && !_hasNext) { clip.dispatchBeforeEvent(new ClipEvent(ClipEventType.FINISH)); } break; case "NetStream.Play.Transition": log.debug("Stream Transition -- " + event.info.details); dispatchEvent(new ClipEvent(ClipEventType.SWITCH, event.info.details)); break; case "NetStream.Play.Failed": case "NetStream.Failed": log.debug("Stream Transition Failed -- " + event.info.description); dispatchEvent(new ClipEvent(ClipEventType.SWITCH_FAILED, event.info.description)); switchStreamNative(); break; case "NetStream.Step.Notify": _stepping = true; break; case "NetStream.Unpause.Notify": _stepping = false; break; //#77 for live streams once unpublished, stop the player to prevent streamnotfound errors reconnecting or if the server shuts down. case "NetConnection.Connect.Closed": case "NetStream.Play.UnpublishNotify": if (clip.live) _player.stop(); break; case "NetConnection.Connect.NetworkChange": //#430 on intermittent client connection failures, attempt a reconnect, or wait until connection is active again for rtmp connections. //Do not attempt to connect here, this may be done in the connection providers. if (_reconnectTime < 0) _reconnectTime = time; _reconnecting = true; break; } return; } private function onPlayStatus(event:ClipEvent) : void { log.debug("onPlayStatus() -- " + event.info.code, event.info); if (event.info.code == "NetStream.Play.TransitionComplete"){ dispatchEvent(new ClipEvent(ClipEventType.SWITCH_COMPLETE)); } return; } override protected function canDispatchBegin():Boolean { return !_stepping && !_streamsStarted; } /** * Called by the player to set my model object. */ override public function onConfig(model : PluginModel) : void { log.debug("onConfig()"); if (_model) return; _model = model; _config = new PropertyBinder(new Config(), null).copyProperties(model.config) as Config; } /** * Called by the player to set the Flowplayer API. */ override public function onLoad(player : Flowplayer) : void { _player = player; if (_config.streamCallbacks) { log.debug("configuration has " + _config.streamCallbacks + " stream callbacks"); } else { log.debug("no stream callbacks in config"); } _model.dispatchOnLoad(); // _model.dispatchError(PluginError.INIT_FAILED, "failed for no fucking reason"); } public function get durationFunc() : String { return clip.getCustomProperty("rtmpDurationFunc") as String || _config.durationFunc; } override protected function getConnectionProvider(clip : Clip) : ConnectionProvider { if (clip.getCustomProperty("rtmpSubscribe") || _config.subscribe) { log.debug("using FCSubscribe to connect"); if (!_subscribingConnectionProvider) { _subscribingConnectionProvider = new SubscribingRTMPConnectionProvider(_config); } return _subscribingConnectionProvider; } if (durationFunc) { log.debug("using " + durationFunc + " to fetch stream duration from the server"); if (!_durQueryingConnectionProvider) { _durQueryingConnectionProvider = new DurationQueryingRTMPConnectionProvider(_config, durationFunc); } return _durQueryingConnectionProvider; } log.debug("using the default connection provider"); if (!_rtmpConnectionProvider) { _rtmpConnectionProvider = new RTMPConnectionProvider(_config); } return _rtmpConnectionProvider; } /** * Overridden to allow random seeking in the timeline. */ override public function get allowRandomSeek() : Boolean { return true; } /** * Starts loading using the specified netStream and clip. */ override protected function doLoad(event : ClipEvent, netStream : NetStream, clip : Clip) : void { _bufferStart = 0; _stepping = false; _streamsStarted = false; if (hasStreamGroup(clip)) { startStreamGroup(clip, netStream); } else { startStream(clip); } } /** * onId3 obtain the metadata for an mp3 stream * @param info */ public function onId3(info:Object):void { clip.metaData = info; clip.dispatch(ClipEventType.METADATA); _id3Stream.close(); _id3Stream = null; } private function startStream(clip : Clip) : void { _receivedStop = false; var streamName : String = getStreamName(clip); var start : int = clip.start > 0 ? clip.start : 0; var duration : int = clip.duration > 0 ? clip.duration + 1 /* let some time to the duration tracker */: -1; log.debug("startStream() starting playback of stream '" + streamName + "', start: " + start + ", duration: " + duration); clip.onPlayStatus(onPlayStatus); if ( clip.live ) { netStream.play(streamName, -1); } else if (_config.dvrSubscribeStart || _config.dvrSubscribeLive) { netStream.play(streamName, 0, -1); } else { netStream.play(streamName, start, duration); } //#545 for mp3 streams, we need to call the file with an id3 prefix on the server to obtain the metadata if (clip.type.type == "audio") { if (!_id3Stream) _id3Stream = new NetStream(this.netConnection); _id3Stream.client = this; _id3Stream.addEventListener(Event.ID3,onId3); _id3Stream.play("id3:" + streamName.slice(4)); } } private function getStreamName(clip : Clip) : String { log.debug("getStreamName() " + clip); //#494 generate the complete url only if a base url is set. regression caused by #412. var url : String = (clip.baseUrl ? clip.completeUrl : clip.url); //#439 just check for an rtmp complete url when parsing complete urls to allow other complete urls used for re-streaming to pass through. if (URLUtil.isRtmpUrl(url)) { //TODO: Parse rtmp complete urls correctly. var lastSlashPos : Number = url.lastIndexOf("/"); return url.substring(lastSlashPos + 1); } return clip.url; } /** * Overridden to be able to store the latest seek target position. */ override protected function doSeek(event : ClipEvent, netStream : NetStream, seconds : Number) : void { _receivedStop = false; //#424 force an end seek buffer to allow some playback and prevent hanging when seeking to the duration. seconds = (seconds >= clip.duration ? clip.duration - _endSeekBuffer : seconds); //#534 don't round seek times for frame accurate seeking //var time:int = int(seconds); _bufferStart = seconds; super.doSeek(event, netStream, seconds); } override protected function doSwitchStream(event : ClipEvent, netStream : NetStream, clip : Clip, netStreamPlayOptions : Object = null) : void { _receivedStop = false; _previousClip = clip; //#406 don't run version checks here anymore to work with Flash 11 if (netStreamPlayOptions) { import flash.net.NetStreamPlayOptions; if (netStreamPlayOptions is NetStreamPlayOptions) { log.debug("doSwitchStream() calling play2()") netStream.play2(netStreamPlayOptions as NetStreamPlayOptions); } } else { //fix for #338, don't set the currentTime when dynamic stream switching _bufferStart = clip.currentTime; clip.currentTime = Math.floor(_previousClip.currentTime + netStream.time); switchStreamNative(); dispatchEvent(event); } } private function switchStreamNative() : void { log.debug("Switching stream with netstream time: " + clip.currentTime); netStream.play(clip.url, clip.live ? (-1) : (clip.currentTime)); return; } override public function get bufferStart() : Number { if (!clip) return 0; if (!netStream) return 0; var backBuffer:Number = 0; CONFIG::FLASH_10_1 { backBuffer = netStream.backBufferLength; } //var backBuffer:Number = netStream.hasOwnProperty("backBufferLength") ? netStream.backBufferLength : 0; //var backBuffer:Number = netStream.backBufferLength; return Math.max(0, getCurrentPlayheadTime(netStream) - backBuffer); } override public function get bufferEnd() : Number { if (!clip) return 0; if (!netStream) return 0; return getCurrentPlayheadTime(netStream) + netStream.bufferLength; } /** * Starts streaming a stream group. */ protected function startStreamGroup(clip : Clip, netStream : NetStream) : void { var streams : Array = clip.customProperties.streams as Array; _receivedStop = false; log.debug("starting a group of " + streams.length + " streams"); var totalDuration : int = 0; for (var i : Number = 0;i < streams.length;i++) { var stream : Object = streams[i]; var duration : int = getDuration(stream); var reset : Object = i == 0 ? 1 : 0; netStream.play(stream.url, getStart(stream), duration, reset); if (duration > 0) { totalDuration += duration; } log.debug("added " + stream.url + " to playlist, total duration " + totalDuration); } if (totalDuration > 0) { clip.duration = totalDuration; } } /** * Does the specified clip have a configured stream group? */ protected function hasStreamGroup(clip : Clip) : Boolean { return clip.customProperties && clip.customProperties.streams; } private function getDuration(stream : Object) : int { return stream.duration || -1; } private function getStart(stream : Object) : int { return stream.start || 0; } public function getDefaultConfig() : Object { return null; } override public function get type() : String { return "rtmp"; } override public function get time() : Number { if (!netStream) return 0; return getCurrentPlayheadTime(netStream) + clip.currentTime; } //#363 overridable pause to frame for different seek functionality. override protected function pauseToFrame():void { //#594 when pausing to a frame, set a 100ms timeout to pause instead of a seek which was causing some streams to hang. setTimeout(function():void { log.debug("seeking to frame zero"); //#363 pause stream here after metadata or else no metadata is sent for rtmp clips pause(new ClipEvent(ClipEventType.PAUSE)); //#363 silent seek and force to seek to a frame or else video will not display silentSeek = true; pauseAfterStart = false; //#486 unmute when auto buffering and pausing to a frame. _player.muted = false; }, 100); } override protected function onMetaData(event:ClipEvent):void { super.onMetaData(event); //#430 if there is a client connection failure reconnect to the specified time for rtmp streams. if (_reconnecting) { seek(null, _reconnectTime); _reconnectTime = -1; _reconnecting = false; } } } } \ No newline at end of file diff --git a/plugins/securestreaming/build.xml b/plugins/securestreaming/build.xml index 49f8a14..9267235 100644 --- a/plugins/securestreaming/build.xml +++ b/plugins/securestreaming/build.xml @@ -2,17 +2,22 @@ - - + + + + - + + + + \ No newline at end of file diff --git a/plugins/securestreaming/src/actionscript/org/flowplayer/securestreaming/SecureStreaming.as b/plugins/securestreaming/src/actionscript/org/flowplayer/securestreaming/SecureStreaming.as index e7f9698..c593a46 100644 --- a/plugins/securestreaming/src/actionscript/org/flowplayer/securestreaming/SecureStreaming.as +++ b/plugins/securestreaming/src/actionscript/org/flowplayer/securestreaming/SecureStreaming.as @@ -92,7 +92,7 @@ package org.flowplayer.securestreaming { } private static function checkDomain(url:String, acceptedDomains:Array):Boolean { - var domain:String = DomainUtil.parseDomain(url, true); + var domain:String = DomainUtil.parseDomain(url, true, (CONFIG::secondaryDomains).split(" ")); // log.debug("domain is '" + domain + "'"); return acceptedDomains.indexOf(domain) >= 0; } diff --git a/plugins/sharing/README.txt b/plugins/sharing/README.txt index ebeaabf..a0cbcde 100644 --- a/plugins/sharing/README.txt +++ b/plugins/sharing/README.txt @@ -1,5 +1,9 @@ Version history: +3.2.15 +------ +- New build because of changes in shared code + 3.2.14 ------ - Added helper methods to hide / show the dock when autohide is enabled or not, issue #60 diff --git a/plugins/sharing/build.properties b/plugins/sharing/build.properties index b8d9671..3f83fc8 100644 --- a/plugins/sharing/build.properties +++ b/plugins/sharing/build.properties @@ -1,2 +1,2 @@ devkit-dir=../../lib/devkit -version=3.2.14 \ No newline at end of file +version=3.2.15 \ No newline at end of file diff --git a/plugins/sharing/build.xml b/plugins/sharing/build.xml index 11e5196..85bde2b 100644 --- a/plugins/sharing/build.xml +++ b/plugins/sharing/build.xml @@ -3,13 +3,16 @@ - - + + + + + diff --git a/plugins/slowmotion/build.xml b/plugins/slowmotion/build.xml index 473a7d4..38ca385 100644 --- a/plugins/slowmotion/build.xml +++ b/plugins/slowmotion/build.xml @@ -2,13 +2,16 @@ - - + + - + + + + diff --git a/plugins/smil/build.xml b/plugins/smil/build.xml index 401f99a..9ed3edb 100644 --- a/plugins/smil/build.xml +++ b/plugins/smil/build.xml @@ -2,12 +2,15 @@ - - + + - + + + + diff --git a/plugins/viralvideos/README.txt b/plugins/viralvideos/README.txt index 919a047..1fa6669 100644 --- a/plugins/viralvideos/README.txt +++ b/plugins/viralvideos/README.txt @@ -2,7 +2,8 @@ sVersion history: 3.2.14 ------ -- Added helper methods to hide / show the dock when autohide is enabled or not, issue #60 +- Added helper methods hide() and show(). Can be used to show the viralvideos form when the dock is not used (or is hidden). +- Sharing is now enabled in virally shared players. #110 3.2.12 ------ diff --git a/plugins/viralvideos/build.properties b/plugins/viralvideos/build.properties index 2df0862..b8d9671 100644 --- a/plugins/viralvideos/build.properties +++ b/plugins/viralvideos/build.properties @@ -1,2 +1,2 @@ devkit-dir=../../lib/devkit -version=3.2.13 \ No newline at end of file +version=3.2.14 \ No newline at end of file diff --git a/plugins/viralvideos/build.xml b/plugins/viralvideos/build.xml index d6e6679..3b4c358 100644 --- a/plugins/viralvideos/build.xml +++ b/plugins/viralvideos/build.xml @@ -4,13 +4,16 @@ - - + + + + + diff --git a/plugins/viralvideos/src/actionscript/org/flowplayer/viralvideos/EmailView.as b/plugins/viralvideos/src/actionscript/org/flowplayer/viralvideos/EmailView.as index c365c12..879b85c 100644 --- a/plugins/viralvideos/src/actionscript/org/flowplayer/viralvideos/EmailView.as +++ b/plugins/viralvideos/src/actionscript/org/flowplayer/viralvideos/EmailView.as @@ -8,7 +8,7 @@ * http://www.opensource.org/licenses/mit-license.php */ package org.flowplayer.viralvideos { - import com.adobe.serialization.json.JSON; + import com.adobe.serialization.json.JSONforFP; import flash.display.Sprite; import flash.events.Event; @@ -353,7 +353,7 @@ package org.flowplayer.viralvideos { var data:Object = null; try { - data = JSON.decode(loader.data.toString()); + data = JSONforFP.decode(loader.data.toString()); } catch(e:Error) { } diff --git a/plugins/viralvideos/src/actionscript/org/flowplayer/viralvideos/PlayerEmbed.as b/plugins/viralvideos/src/actionscript/org/flowplayer/viralvideos/PlayerEmbed.as index 86afafd..dd72286 100644 --- a/plugins/viralvideos/src/actionscript/org/flowplayer/viralvideos/PlayerEmbed.as +++ b/plugins/viralvideos/src/actionscript/org/flowplayer/viralvideos/PlayerEmbed.as @@ -9,7 +9,7 @@ * Additional Term, see http://flowplayer.org/license_gpl.html */ package org.flowplayer.viralvideos { - import com.adobe.serialization.json.JSON; + import com.adobe.serialization.json.JSONforFP; import flash.display.Stage; import flash.net.URLVariables; @@ -110,8 +110,7 @@ package org.flowplayer.viralvideos { if (configObj && String(configObj).indexOf("{") > 0 && ! configObj.hasOwnProperty("url")) { // a regular configuration object - _playerConfig = JSON.decode(configObj); - + _playerConfig = JSONforFP.decode(configObj); } else { // had an external config file configured using 'url', use the loaded config object //_playerConfig = _player.config.configObject; @@ -167,7 +166,6 @@ package org.flowplayer.viralvideos { } } } - updatedConfig.plugins[_viralPluginConfiguredName].share = false; fixPluginsURLs(updatedConfig); fixPageUrl(updatedConfig); @@ -229,7 +227,7 @@ package org.flowplayer.viralvideos { var configStr:String = _embedConfig.configUrl; if (! configStr) { var conf:Object = updateConfig(_playerConfig); - configStr = escaped ? escape(JSON.encode(conf)) : JSON.encode(conf); + configStr = escaped ? escape(JSONforFP.encode(conf)) : JSONforFP.encode(conf); } return configStr;