v2.0.17~dfsg/0000755000000000000000000000000012625374554011546 5ustar rootrootv2.0.17~dfsg/src/0000755000000000000000000000000012625374554012335 5ustar rootrootv2.0.17~dfsg/src/jaris/0000755000000000000000000000000012625374554013445 5ustar rootrootv2.0.17~dfsg/src/jaris/utils/0000755000000000000000000000000012625374554014605 5ustar rootrootv2.0.17~dfsg/src/jaris/utils/Utils.hx0000644000000000000000000001027312625374554016251 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.utils; /** * Some utility functions */ class Utils { /** * Converts degrees to radians for easy rotation where applicable * @param value A radian value to convert * @return conversion of degree to radian */ public static function degreesToRadians(value:Float):Float { return (Math.PI / 180) * value; } /** * Converts a float value representing seconds to a readale string * @param time A given time in seconds * @return A string in the format 00:00:00 */ public static function formatTime(time:Float):String { var seconds:String = ""; var minutes:String = ""; var hours:String = ""; var timeString:String = ""; if (((time / 60) / 60) >= 1) { if (Math.floor((time / 60)) / 60 < 10) { hours = "0" + Math.floor((time / 60) / 60) + ":"; } else { hours = Math.floor((time / 60) / 60) + ":"; } if (Math.floor((time / 60) % 60) < 10) { minutes = "0" + Math.floor((time / 60) % 60) + ":"; } else { minutes = Math.floor((time / 60) % 60) + ":"; } if (Math.floor(time % 60) < 10) { seconds = "0" + Math.floor(time % 60); } else { seconds = Std.string(Math.floor(time % 60)); } } else if((time / 60) >= 1) { hours = "00:"; if (Math.floor(time / 60) < 10) { minutes = "0" + Math.floor(time / 60) + ":"; } else { minutes = Math.floor(time / 60) + ":"; } if (Math.floor(time % 60) < 10) { seconds = "0" + Math.floor(time % 60); } else { seconds = Std.string(Math.floor(time % 60)); } } else { hours = "00:"; minutes = "00:"; if (Math.floor(time) < 10) { seconds = "0" + Math.floor(time); } else { seconds = Std.string(Math.floor(time)); } } timeString += hours + minutes + seconds; return timeString; } /** * Converts a given rtmp source to a valid format for NetStream * @param source * @return */ public static function rtmpSourceParser(source:String):String { if (source.indexOf(".flv") != -1) { return source.split(".flv").join(""); } else if (source.indexOf(".mp3") != -1) { return "mp3:" + source.split(".mp3").join(""); } else if (source.indexOf(".mp4") != -1) { return "mp4:" + source; } else if (source.indexOf(".f4v") != -1) { return "mp4:" + source; } return source; } /** * Changes a youtube url to the format youtube.com/v/video_id * @param source * @return */ public static function youtubeSourceParse(source:String):String { return source.split("watch?v=").join("v/"); } } v2.0.17~dfsg/src/jaris/display/0000755000000000000000000000000012625374554015112 5ustar rootrootv2.0.17~dfsg/src/jaris/display/Poster.hx0000644000000000000000000001126612625374554016735 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.display; import flash.display.DisplayObject; import flash.display.Loader; import flash.display.MovieClip; import flash.display.Sprite; import flash.display.Stage; import flash.events.Event; import flash.events.IOErrorEvent; import flash.Lib; import flash.net.URLRequest; import jaris.events.PlayerEvents; import jaris.player.InputType; import jaris.player.Player; /** * To display an png, jpg or gif as preview of video content */ class Poster extends Sprite { private var _stage:Stage; private var _movieClip:MovieClip; private var _loader:Loader; private var _source:String; private var _width:Float; private var _height:Float; private var _loading:Bool; private var _loaderStatus:jaris.display.Loader; private var _player:Player; public function new(source:String) { super(); _stage = Lib.current.stage; _movieClip = Lib.current; _loader = new Loader(); _source = source; _loading = true; //Reads flash vars var parameters:Dynamic = flash.Lib.current.loaderInfo.parameters; //Draw Loader status var loaderColors:Array = ["", "", "", ""]; loaderColors[0] = parameters.brightcolor != null ? parameters.brightcolor : ""; loaderColors[1] = parameters.controlcolor != null ? parameters.controlcolor : ""; _loaderStatus = new jaris.display.Loader(); _loaderStatus.show(); _loaderStatus.setColors(loaderColors); addChild(_loaderStatus); _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete); _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onNotLoaded); _loader.load(new URLRequest(source)); } /** * Triggers when the poster image could not be loaded * @param event */ private function onNotLoaded(event:IOErrorEvent):Void { _loaderStatus.hide(); removeChild(_loaderStatus); } /** * Triggers when the poster image finalized loading * @param event */ private function onLoaderComplete(event:Event):Void { _loaderStatus.hide(); removeChild(_loaderStatus); addChild(_loader); _width = this.width; _height = this.height; _loading = false; _stage.addEventListener(Event.RESIZE, onStageResize); resizeImage(); } /** * Triggers when the stage is resized to resize the poster image * @param event */ private function onStageResize(event:Event):Void { resizeImage(); } private function onPlayerMediaInitialized(event:PlayerEvents) { if (_player.getType() == InputType.VIDEO) { this.visible = false; } } private function onPlayerPlay(event:PlayerEvents) { if (_player.getType() == InputType.VIDEO) { this.visible = false; } } private function onPlayBackFinished(event:PlayerEvents) { this.visible = true; } /** * Resizes the poster image to take all the stage */ private function resizeImage():Void { this.height = _stage.stageHeight; this.width = ((_width / _height) * this.height); this.x = (_stage.stageWidth / 2) - (this.width / 2); } /** * To check if the poster image stills loading * @return true if stills loading false if loaded */ public function isLoading():Bool { return _loading; } public function setPlayer(player:Player):Void { _player = player; _player.addEventListener(PlayerEvents.MEDIA_INITIALIZED, onPlayerMediaInitialized); _player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayBackFinished); _player.addEventListener(PlayerEvents.PLAY_PAUSE, onPlayerPlay); } } v2.0.17~dfsg/src/jaris/display/Logo.hx0000644000000000000000000001142012625374554016351 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.display; import flash.display.Loader; import flash.display.MovieClip; import flash.display.Sprite; import flash.display.Stage; import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.MouseEvent; import flash.Lib; import flash.net.URLRequest; /** * To display an image in jpg, png or gif format as logo */ class Logo extends Sprite { private var _stage:Stage; private var _movieClip:MovieClip; private var _loader:Loader; private var _position:String; private var _alpha:Float; private var _source:String; private var _width:Float; private var _link:String; private var _loading:Bool; public function new(source:String, position:String, alpha:Float, width:Float=0.0) { super(); _stage = Lib.current.stage; _movieClip = Lib.current; _loader = new Loader(); _position = position; _alpha = alpha; _source = source; _width = width; _loading = true; this.tabEnabled = false; _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete); _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onNotLoaded); _loader.load(new URLRequest(source)); } /** * Triggers when the logo image could not be loaded * @param event */ private function onNotLoaded(event:IOErrorEvent):Void { //Image not loaded } /** * Triggers when the logo image finished loading. * @param event */ private function onLoaderComplete(event:Event):Void { addChild(_loader); setWidth(_width); setPosition(_position); setAlpha(_alpha); _loading = false; _stage.addEventListener(Event.RESIZE, onStageResize); } /** * Recalculate logo position on stage resize * @param event */ private function onStageResize(event:Event):Void { setPosition(_position); } /** * Opens the an url when the logo is clicked * @param event */ private function onLogoClick(event:MouseEvent):Void { Lib.getURL(new URLRequest(_link), "_blank"); } /** * Position where logo will be showing * @param position values could be top left, top right, bottom left, bottom right */ public function setPosition(position:String):Void { switch(position) { case "top left": this.x = 25; this.y = 25; case "top right": this.x = _stage.stageWidth - this._width - 25; this.y = 25; case "bottom left": this.x = 25; this.y = _stage.stageHeight - this.height - 25; case "bottom right": this.x = _stage.stageWidth - this.width - 25; this.y = _stage.stageHeight - this.height - 25; default: this.x = 25; this.y = 25; } } /** * To set logo transparency * @param alpha */ public function setAlpha(alpha:Float):Void { this.alpha = alpha; } /** * Sets logo width and recalculates height keeping aspect ratio * @param width */ public function setWidth(width:Float):Void { if (width > 0) { this.height = (this.height / this.width) * width; this.width = width; } } /** * Link that opens when clicked the logo image is clicked * @param link */ public function setLink(link:String):Void { _link = link; this.buttonMode = true; this.useHandCursor = true; this.addEventListener(MouseEvent.CLICK, onLogoClick); } /** * To check if the logo stills loading * @return true if loading false otherwise */ public function isLoading():Bool { return _loading; } } v2.0.17~dfsg/src/jaris/display/Menu.hx0000644000000000000000000001655512625374554016373 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.display; import flash.display.MovieClip; import flash.events.ContextMenuEvent; import flash.Lib; import flash.net.URLRequest; import flash.ui.ContextMenu; import flash.ui.ContextMenuItem; import jaris.player.Player; import jaris.player.AspectRatio; import jaris.Version; /** * Modify original context menu */ class Menu { private var _movieClip:MovieClip; public static var _player:Player; private var _contextMenu:ContextMenu; private var _jarisVersionMenuItem:ContextMenuItem; private var _playMenuItem:ContextMenuItem; private var _fullscreenMenuItem:ContextMenuItem; private var _aspectRatioMenuItem:ContextMenuItem; private var _muteMenuItem:ContextMenuItem; private var _volumeUpMenuItem:ContextMenuItem; private var _volumeDownMenuItem:ContextMenuItem; private var _qualityContextMenu:ContextMenuItem; public function new(player:Player) { _movieClip = Lib.current; _player = player; //Initialize context menu replacement _contextMenu = new ContextMenu(); _contextMenu.hideBuiltInItems(); _contextMenu.addEventListener(ContextMenuEvent.MENU_SELECT, onMenuOpen); //Initialize each menu item _jarisVersionMenuItem = new ContextMenuItem("Jaris Player v" + Version.NUMBER + " " + Version.STATUS, true, true, true); _jarisVersionMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onJarisVersion); _playMenuItem = new ContextMenuItem("Play (SPACE)", true, true, true); _playMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onPlay); _fullscreenMenuItem = new ContextMenuItem("Fullscreen View (F)"); _fullscreenMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onFullscreen); _aspectRatioMenuItem = new ContextMenuItem("Aspect Ratio (original) (TAB)"); _aspectRatioMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onAspectRatio); _muteMenuItem = new ContextMenuItem("Mute (M)"); _muteMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onMute); _volumeUpMenuItem = new ContextMenuItem("Volume + (arrow UP)"); _volumeUpMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onVolumeUp); _volumeDownMenuItem = new ContextMenuItem("Volume - (arrow DOWN)"); _volumeDownMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onVolumeDown); _qualityContextMenu = new ContextMenuItem("Lower Quality", true, true, true); _qualityContextMenu.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onQuality); //add all context menu items to context menu object _contextMenu.customItems.push(_jarisVersionMenuItem); _contextMenu.customItems.push(_playMenuItem); _contextMenu.customItems.push(_fullscreenMenuItem); _contextMenu.customItems.push(_aspectRatioMenuItem); _contextMenu.customItems.push(_muteMenuItem); _contextMenu.customItems.push(_volumeUpMenuItem); _contextMenu.customItems.push(_volumeDownMenuItem); _contextMenu.customItems.push(_qualityContextMenu); //override default context menu _movieClip.contextMenu = _contextMenu; } /** * Update context menu item captions depending on player status before showing them * @param event */ private function onMenuOpen(event:ContextMenuEvent):Void { if (_player.isPlaying()) { _playMenuItem.caption = "Pause (SPACE)"; } else { _playMenuItem.caption = "Play (SPACE)"; } if (_player.isFullscreen()) { _fullscreenMenuItem.caption = "Normal View"; } else { _fullscreenMenuItem.caption = "Fullscreen View (F)"; } if (_player.getMute()) { _muteMenuItem.caption = _player.isFullscreen()?"Unmute":"Unmute (M)"; } else { _muteMenuItem.caption = _player.isFullscreen()?"Mute":"Mute (M)"; } switch(_player.getAspectRatioString()) { case "original": _aspectRatioMenuItem.caption = "Aspect Ratio (1:1) (TAB)"; case "1:1": _aspectRatioMenuItem.caption = "Aspect Ratio (3:2) (TAB)"; case "3:2": _aspectRatioMenuItem.caption = "Aspect Ratio (4:3) (TAB)"; case "4:3": _aspectRatioMenuItem.caption = "Aspect Ratio (5:4) (TAB)"; case "5:4": _aspectRatioMenuItem.caption = "Aspect Ratio (14:9) (TAB)"; case "14:9": _aspectRatioMenuItem.caption = "Aspect Ratio (14:10) (TAB)"; case "14:10": _aspectRatioMenuItem.caption = "Aspect Ratio (16:9) (TAB)"; case "16:9": _aspectRatioMenuItem.caption = "Aspect Ratio (16:10) (TAB)"; case "16:10": _aspectRatioMenuItem.caption = "Aspect Ratio (original) (TAB)"; } if (_player.getQuality()) { _qualityContextMenu.caption = "Lower Quality"; } else { _qualityContextMenu.caption = "Higher Quality"; } } /** * Open jaris player website * @param event */ private function onJarisVersion(event:ContextMenuEvent) { Lib.getURL(new URLRequest("http://jaris.sourceforge.net"), "_blank"); } /** * Toggles playback * @param event */ private function onPlay(event:ContextMenuEvent) { _player.togglePlay(); } /** * Toggles fullscreen * @param event */ private function onFullscreen(event:ContextMenuEvent) { _player.toggleFullscreen(); } /** * Toggles aspect ratio * @param event */ private function onAspectRatio(event:ContextMenuEvent) { _player.toggleAspectRatio(); } /** * Toggles mute * @param event */ private function onMute(event:ContextMenuEvent) { _player.toggleMute(); } /** * Raise volume * @param event */ private function onVolumeUp(event:ContextMenuEvent) { _player.volumeUp(); } /** * Lower volume * @param event */ private function onVolumeDown(event:ContextMenuEvent) { _player.volumeDown(); } /** * Toggle video quality * @param event */ private function onQuality(event:ContextMenuEvent) { _player.toggleQuality(); } } v2.0.17~dfsg/src/jaris/display/Loader.hx0000644000000000000000000001163512625374554016667 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.display; import flash.display.MovieClip; import flash.display.Sprite; import flash.display.Stage; import flash.events.Event; import flash.Lib; /** * Draws a loading bar */ class Loader extends Sprite { private var _stage:Stage; private var _movieClip:MovieClip; private var _background:Sprite; private var _loaderTrack:Sprite; private var _loaderThumb:Sprite; private var _visible:Bool; private var _brightColor:UInt; private var _controlColor:UInt; private var _forward:Bool; public function new() { super(); _stage = Lib.current.stage; _movieClip = Lib.current; _background = new Sprite(); addChild(_background); _loaderTrack = new Sprite(); addChild(_loaderTrack); _loaderThumb = new Sprite(); addChild(_loaderThumb); _brightColor = 0x4c4c4c; _controlColor = 0xFFFFFF; _forward = true; _visible = true; addEventListener(Event.ENTER_FRAME, onEnterFrame); _stage.addEventListener(Event.RESIZE, onResize); drawLoader(); } /** * Animation of a thumb moving on the track * @param event */ private function onEnterFrame(event:Event):Void { if (_visible) { if (_forward) { if ((_loaderThumb.x + _loaderThumb.width) >= (_loaderTrack.x + _loaderTrack.width)) { _forward = false; } else { _loaderThumb.x += 10; } } else { if (_loaderThumb.x <= _loaderTrack.x) { _forward = true; } else { _loaderThumb.x -= 10; } } } } /** * Redraws the loader to match new stage size * @param event */ private function onResize(event:Event):Void { drawLoader(); } /** * Draw loader graphics */ private function drawLoader():Void { //Clear graphics _background.graphics.clear(); _loaderTrack.graphics.clear(); _loaderThumb.graphics.clear(); //Draw background var backgroundWidth:Float = (65 / 100) * _stage.stageWidth; var backgroundHeight:Float = 30; _background.x = (_stage.stageWidth / 2) - (backgroundWidth / 2); _background.y = (_stage.stageHeight / 2) - (backgroundHeight / 2); _background.graphics.lineStyle(); _background.graphics.beginFill(_brightColor, 0.5); _background.graphics.drawRoundRect(0, 0, backgroundWidth, backgroundHeight, 6, 6); _background.graphics.endFill(); //Draw track var trackWidth:Float = (50 / 100) * _stage.stageWidth; var trackHeight:Float = 15; _loaderTrack.x = (_stage.stageWidth / 2) - (trackWidth / 2); _loaderTrack.y = (_stage.stageHeight / 2) - (trackHeight / 2); _loaderTrack.graphics.lineStyle(2, _controlColor); _loaderTrack.graphics.drawRect(0, 0, trackWidth, trackHeight); //Draw thumb _loaderThumb.x = _loaderTrack.x; _loaderThumb.y = _loaderTrack.y; _loaderThumb.graphics.lineStyle(); _loaderThumb.graphics.beginFill(_controlColor, 1); _loaderThumb.graphics.drawRect(0, 0, trackHeight, trackHeight); } /** * Stops drawing the loader */ public function hide():Void { this.visible = false; _visible = false; } /** * Starts drawing the loader */ public function show():Void { this.visible = true; _visible = true; } /** * Set loader colors * @param colors */ public function setColors(colors:Array):Void { _brightColor = colors[0].length > 0? Std.parseInt("0x" + colors[0]) : 0x4c4c4c; _controlColor = colors[1].length > 0? Std.parseInt("0x" + colors[1]) : 0xFFFFFF; drawLoader(); } } v2.0.17~dfsg/src/jaris/animation/0000755000000000000000000000000012625374554015424 5ustar rootrootv2.0.17~dfsg/src/jaris/animation/Animation.hx0000644000000000000000000000474112625374554017712 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.animation; /** * Gives quick access usage to jaris animations */ class Animation { /** * Quick access to fade in effect * @param object the object to animate * @param seconds the duration of the animation */ public static function fadeIn(object:Dynamic, seconds:Float):Void { var animation:AnimationsBase = new AnimationsBase(); animation.fadeIn(object, seconds); } /** * Quick access to fade out effect * @param object the object to animate * @param seconds the duration of the animation */ public static function fadeOut(object:Dynamic, seconds:Float):Void { var animation:AnimationsBase = new AnimationsBase(); animation.fadeOut(object, seconds); } /** * Quick access to slide in effect * @param object the object to animate * @param position could be top, left, bottom or right * @param seconds the duration of the animation */ public static function slideIn(object:Dynamic, position:String, seconds:Float):Void { var animation:AnimationsBase = new AnimationsBase(); animation.slideIn(object, position, seconds); } /** * Quick access to slide out effect * @param object the object to animate * @param position could be top, left, bottom or right * @param seconds the duration of the animation */ public static function slideOut(object:Dynamic, position:String, seconds:Float):Void { var animation:AnimationsBase = new AnimationsBase(); animation.slideOut(object, position, seconds); } } v2.0.17~dfsg/src/jaris/animation/AnimationsBase.hx0000644000000000000000000002072512625374554020670 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.animation; import flash.display.MovieClip; import flash.display.Stage; import flash.events.TimerEvent; import flash.Lib; import flash.utils.Timer; /** * Jaris main animations */ class AnimationsBase { private var _fadeInTimer:Timer; private var _fadeOutTimer:Timer; private var _slideInTimer:Timer; private var _slideInOrigX:Float; private var _slideInOrigY:Float; private var _slideInPosition:String; private var _slideInIncrements:Float; private var _slideOutTimer:Timer; private var _slideOutOrigX:Float; private var _slideOutOrigY:Float; private var _slideOutPosition:String; private var _slideOutIncrements:Float; private var _stage:Stage; private var _movieClip:MovieClip; private var _currentObject:Dynamic; public function new() { _stage = Lib.current.stage; _movieClip = Lib.current; } /** * Moves an object until is shown * @param event */ private function slideInTimer(event:TimerEvent):Void { var last:Bool = false; switch(_slideInPosition) { case "top": if (_currentObject.y >= _slideInOrigY) { last = true; } _currentObject.y += _slideInIncrements; case "left": if (_currentObject.x >= _slideInOrigX) { last = true; } _currentObject.x += _slideInIncrements; case "bottom": if (_currentObject.y <= _slideInOrigY) { last = true; } _currentObject.y -= _slideInIncrements; case "right": if (_currentObject.x <= _slideInOrigX) { last = true; } _currentObject.x -= _slideInIncrements; } if (last) { _currentObject.x = _slideInOrigX; _currentObject.y = _slideInOrigY; _slideInTimer.stop(); } } /** * Moves an object until is hidden * @param event */ private function slideOutTimer(event:TimerEvent):Void { if (((_currentObject.x + _currentObject.width) < 0) || (_currentObject.y + _currentObject.height < 0)) { _currentObject.visible = false; _currentObject.x = _slideOutOrigX; _currentObject.y = _slideOutOrigY; _slideOutTimer.stop(); } else if (((_currentObject.x) > _stage.stageWidth) || (_currentObject.y > _stage.stageHeight)) { _currentObject.visible = false; _currentObject.x = _slideOutOrigX; _currentObject.y = _slideOutOrigY; _slideOutTimer.stop(); } else { switch(_slideOutPosition) { case "top": _currentObject.y -= _slideOutIncrements; case "left": _currentObject.x -= _slideOutIncrements; case "bottom": _currentObject.y += _slideOutIncrements; case "right": _currentObject.x += _slideOutIncrements; } } } /** * Lower object transparency until not visible * @param event */ private function fadeOutTimer(event:TimerEvent):Void { if (_currentObject.alpha > 0) { _currentObject.alpha -= 1 / 10; } else { _currentObject.visible = false; _fadeOutTimer.stop(); } } /** * Highers object transparency until visible * @param event */ private function fadeInTimer(event:TimerEvent):Void { if (_currentObject.alpha < 1) { _currentObject.alpha += 1 / 10; } else { _fadeInTimer.stop(); } } /** * Effect that moves an object into stage * @param object the element to move * @param slidePosition could be top, left bottom or right * @param speed the time in seconds for duration of the animation */ public function slideIn(object:Dynamic, slidePosition:String, speed:Float=1000):Void { if (object.visible) { object.visible = false; } _slideInOrigX = object.x; _slideInOrigY = object.y; _slideInPosition = slidePosition; var increments:Float = 0; switch(slidePosition) { case "top": object.y = 0 - object.height; increments = object.height + _slideInOrigY; case "left": object.x = 0 - object.width; increments = object.width + _slideInOrigX; case "bottom": object.y = _stage.stageHeight; increments = _stage.stageHeight - _slideInOrigY; case "right": object.x = _stage.stageWidth; increments = _stage.stageWidth - _slideInOrigX; } _slideInIncrements = increments / (speed / 100); _currentObject = object; _currentObject.visible = true; _currentObject.alpha = 1; _slideInTimer = new Timer(speed / 100); _slideInTimer.addEventListener(TimerEvent.TIMER, slideInTimer); _slideInTimer.start(); } /** * Effect that moves an object out of stage * @param object the element to move * @param slidePosition could be top, left bottom or right * @param speed the time in seconds for duration of the animation */ public function slideOut(object:Dynamic, slidePosition:String, speed:Float=1000):Void { if (!object.visible) { object.visible = true; } _slideOutOrigX = object.x; _slideOutOrigY = object.y; _slideOutPosition = slidePosition; var increments:Float = 0; switch(slidePosition) { case "top": increments = object.height + _slideOutOrigY; case "left": increments = object.width + _slideOutOrigX; case "bottom": increments = _stage.stageHeight - _slideOutOrigY; case "right": increments = _stage.stageWidth - _slideOutOrigX; } _slideOutIncrements = increments / (speed / 100); _currentObject = object; _currentObject.visible = true; _currentObject.alpha = 1; _slideOutTimer = new Timer(speed / 100); _slideOutTimer.addEventListener(TimerEvent.TIMER, slideOutTimer); _slideOutTimer.start(); } /** * Effect that dissapears an object from stage * @param object the element to dissapear * @param speed the time in seconds for the duration of the animation */ public function fadeOut(object:Dynamic, speed:Float=500):Void { if (!object.visible) { object.visible = true; } object.alpha = 1; _currentObject = object; _fadeOutTimer = new Timer(speed / 10); _fadeOutTimer.addEventListener(TimerEvent.TIMER, fadeOutTimer); _fadeOutTimer.start(); } /** * Effect that shows a hidden object an in stage * @param object the element to show * @param speed the time in seconds for the duration of the animation */ public function fadeIn(object:Dynamic, speed:Float=500):Void { if (object.visible) { object.visible = false; } object.alpha = 0; _currentObject = object; _currentObject.visible = true; _fadeInTimer = new Timer(speed / 10); _fadeInTimer.addEventListener(TimerEvent.TIMER, fadeInTimer); _fadeInTimer.start(); } } v2.0.17~dfsg/src/jaris/events/0000755000000000000000000000000012625374554014751 5ustar rootrootv2.0.17~dfsg/src/jaris/events/PlayerEvents.hx0000644000000000000000000000551012625374554017734 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.events; import flash.events.Event; import flash.media.ID3Info; import flash.media.Sound; import flash.net.NetStream; /** * Implements the player events */ class PlayerEvents extends Event { public static var ASPECT_RATIO = "onAspectRatio"; public static var MOUSE_SHOW = "onMouseShow"; public static var MOUSE_HIDE = "onMouseHide"; public static var FULLSCREEN = "onFullscreen"; public static var VOLUME_UP = "onVolumeUp"; public static var VOLUME_DOWN = "onVolumeDown"; public static var VOLUME_CHANGE= "onVolumeChange"; //Nuevo public static var MUTE = "onMute"; public static var FORWARD = "onForward"; public static var REWIND = "onRewind"; public static var PLAY_PAUSE = "onPlayPause"; public static var SEEK = "onSeek"; public static var TIME = "onTimeUpdate"; public static var PROGRESS = "onProgress"; public static var BUFFERING = "onBuffering"; public static var NOT_BUFFERING = "onNotBuffering"; public static var CONNECTION_FAILED = "onConnectionFailed"; public static var CONNECTION_SUCCESS = "onConnectionSuccess"; public static var MEDIA_INITIALIZED = "onDataInitialized"; public static var PLAYBACK_FINISHED = "onPlaybackFinished"; public static var STOP_CLOSE = "onStopAndClose"; public static var RESIZE = "onResize"; public var name:String; public var aspectRatio:Float; public var duration:Float; public var fullscreen:Bool; public var mute:Bool; public var volume:Float; public var width:Float; public var height:Float; public var stream:NetStream; public var sound:Sound; public var time:Float; public var id3Info:ID3Info; public function new(type:String, bubbles:Bool=false, cancelable:Bool=false) { super(type, bubbles, cancelable); fullscreen = false; mute = false; volume = 1.0; duration = 0; width = 0; height = 0; time = 0; name = type; } } v2.0.17~dfsg/src/jaris/Version.hx0000644000000000000000000000224512625374554015436 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris; /** * Actual jaris flv player version and date */ class Version { public static var NUMBER:String = "2.0.17"; public static var STATUS:String = "stable"; public static var DATE:String = "22"; public static var MONTH:String = "11"; public static var YEAR:String = "2015"; } v2.0.17~dfsg/src/jaris/player/0000755000000000000000000000000012625374554014741 5ustar rootrootv2.0.17~dfsg/src/jaris/player/AspectRatio.hx0000644000000000000000000000307112625374554017521 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player; /** * Stores the player used aspect ratio constants */ class AspectRatio { public static var _1_1:Float = 1 / 1; public static var _3_2:Float = 3 / 2; public static var _4_3:Float = 4 / 3; public static var _5_4:Float = 5 / 4; public static var _14_9:Float = 14 / 9; public static var _14_10:Float = 14 / 10; public static var _16_9:Float = 16 / 9; public static var _16_10:Float = 16 / 10; /** * Calculates the ratio for a given width and height * @param width * @param height * @return aspect ratio */ public static function getAspectRatio(width:Float, height:Float):Float { return width / height; } } v2.0.17~dfsg/src/jaris/player/UserSettings.hx0000644000000000000000000000543712625374554017752 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player; import flash.net.SharedObject; /** * To store and retrieve user settings so the player can load them next time it loads. * In this way player can remember user selected aspect ratio and volume. */ class UserSettings { private var _settings:SharedObject; public function new() { _settings = SharedObject.getLocal("JarisPlayerUserSettings"); } //{Methods /** * Deletes all user settings */ public function deleteSettings():Void { _settings.clear(); } /** * Checks if a user setting is available * @param field The name of the setting * @return true if is set false otherwise */ public function isSet(field:String):Bool { return Reflect.hasField(_settings.data, field); } //} //{Properties Setters /** * Stores the volume value * @param level */ public function setVolume(level:Float):Void { _settings.data.volume = level; _settings.flush(); } /** * Stores the aspect ratio value * @param aspect */ public function setAspectRatio(aspectratio:Float):Void { _settings.data.aspectratio = aspectratio; _settings.flush(); } //} //{Properties Getters /** * The last user selected volume value * @return Last user selected volume value or default if not set. */ public function getVolume():Float { if (!isSet("volume")) { return 1.0; //The maximum volume value } return _settings.data.volume; } /** * The last user selected aspect ratio value * @return Last user selected aspect ratio value or default if not set. */ public function getAspectRatio():Float { if (!isSet("aspectratio")) { return 0.0; //Equivalent to original } return _settings.data.aspectratio; } //} } v2.0.17~dfsg/src/jaris/player/Player.hx0000644000000000000000000014422012625374554016541 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player; import flash.display.Loader; import flash.display.MovieClip; import flash.display.Sprite; import flash.display.Stage; import flash.display.StageDisplayState; import flash.events.AsyncErrorEvent; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.FullScreenEvent; import flash.events.IOErrorEvent; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.events.NetStatusEvent; import flash.events.ProgressEvent; import flash.events.TimerEvent; import flash.geom.Rectangle; import flash.Lib; import flash.media.ID3Info; import flash.media.Sound; import flash.media.SoundChannel; import flash.media.SoundTransform; import flash.media.Video; import flash.net.NetConnection; import flash.net.NetStream; import flash.net.URLRequest; import flash.system.Capabilities; import flash.system.Security; import flash.ui.Keyboard; import flash.ui.Mouse; import flash.utils.Timer; import jaris.events.PlayerEvents; import jaris.utils.Utils; import jaris.player.AspectRatio; import jaris.player.UserSettings; /** * Jaris main video player */ class Player extends EventDispatcher { //{Member variables private var _stage:Stage; private var _movieClip:MovieClip; private var _connection:NetConnection; private var _stream:NetStream; private var _fullscreen:Bool; private var _soundMuted:Bool; private var _volume:Float; private var _bufferTime:Float; private var _mouseVisible:Bool; private var _mediaLoaded:Bool; private var _hideMouseTimer:Timer; private var _checkAudioTimer:Timer; private var _mediaSource:String; private var _type:String; private var _streamType:String; private var _server:String; //For future use on rtmp private var _sound:Sound; private var _soundChannel:SoundChannel; private var _id3Info:ID3Info; private var _video:Video; private var _videoWidth:Float; private var _videoHeight:Float; private var _videoMask:Sprite; private var _videoQualityHigh:Bool; private var _mediaDuration:Float; private var _lastTime:Float; private var _lastProgress:Float; private var _isPlaying:Bool; private var _aspectRatio:Float; private var _currentAspectRatio:String; private var _originalAspectRatio:Float; private var _mediaEndReached:Bool; private var _seekPoints:Array; private var _downloadCompleted:Bool; private var _startTime:Float; private var _firstLoad:Bool; private var _stopped:Bool; private var _useHardWareScaling:Bool; private var _youtubeLoader:Loader; private var _userSettings:UserSettings; //} //{Constructor public function new() { super(); //{Main Variables Init _stage = Lib.current.stage; _movieClip = Lib.current; _mouseVisible = true; _soundMuted = false; _volume = 1.0; _bufferTime = 10; _fullscreen = false; _mediaLoaded = false; _hideMouseTimer = new Timer(1500); _checkAudioTimer = new Timer(100); _seekPoints = new Array(); _downloadCompleted = false; _startTime = 0; _firstLoad = true; _stopped = false; _videoQualityHigh = false; _isPlaying = false; _streamType = StreamType.FILE; _type = InputType.VIDEO; _server = ""; _currentAspectRatio = "original"; _aspectRatio = 0; _lastTime = 0; _lastProgress = 0; _userSettings = new UserSettings(); //} //{Initialize sound object _sound = new Sound(); _sound.addEventListener(Event.COMPLETE, onSoundComplete); _sound.addEventListener(Event.ID3, onSoundID3); _sound.addEventListener(IOErrorEvent.IO_ERROR, onSoundIOError); _sound.addEventListener(ProgressEvent.PROGRESS, onSoundProgress); //} //{Initialize video and connection objects _connection = new NetConnection(); _connection.client = this; _connection.connect(null); _stream = new NetStream(_connection); _video = new Video(_stage.stageWidth, _stage.stageHeight); _movieClip.addChild(_video); //} //Video mask so that custom menu items work _videoMask = new Sprite(); _movieClip.addChild(_videoMask); //Set initial rendering to high quality toggleQuality(); //{Initialize system event listeners _movieClip.addEventListener(Event.ENTER_FRAME, onEnterFrame); _stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); _stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); _stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullScreen); _stage.addEventListener(Event.RESIZE, onResize); _hideMouseTimer.addEventListener(TimerEvent.TIMER, hideMouseTimer); _checkAudioTimer.addEventListener(TimerEvent.TIMER, checkAudioTimer); _connection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); _connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError); //} } //} //{Timers /** * Timer that hides the mouse pointer when it is idle and dispatch the PlayerEvents.MOUSE_HIDE * @param event */ private function hideMouseTimer(event:TimerEvent):Void { if (_fullscreen) { if (_mouseVisible) { _mouseVisible = false; } else { Mouse.hide(); callEvents(PlayerEvents.MOUSE_HIDE); _hideMouseTimer.stop(); } } } /** * To check if the sound finished playing * @param event */ private function checkAudioTimer(event:TimerEvent):Void { if (_soundChannel.position + 100 >= _sound.length) { _isPlaying = false; _mediaEndReached = true; callEvents(PlayerEvents.PLAYBACK_FINISHED); _checkAudioTimer.stop(); } } //} //{Events /** * Callback after bandwidth calculation for rtmp streams */ private function onBWDone():Void { //Need to study this more } /** * Triggers error event on rtmp connections * @param event */ private function onAsyncError(event:AsyncErrorEvent):Void { //TODO: Should trigger event for controls to display error message //trace(event.error); } /** * Checks if connection failed or succeed * @param event */ private function onNetStatus(event:NetStatusEvent):Void { switch (event.info.code) { case "NetConnection.Connect.Success": if (_streamType == StreamType.RTMP) { _stream = new NetStream(_connection); _stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); _stream.bufferTime = 10; //_stream.play(Utils.rtmpSourceParser(_mediaSource), true); _stream.play(_mediaSource); _stream.client = this; if(_type == InputType.VIDEO) {_video.attachNetStream(_stream); } } callEvents(PlayerEvents.CONNECTION_SUCCESS); case "NetStream.Play.StreamNotFound": trace("Stream not found: " + _mediaSource); //Replace with a dispatch for error event callEvents(PlayerEvents.CONNECTION_FAILED); case "NetStream.Play.Stop": if (_streamType != StreamType.RTMP) { if (_isPlaying) { _stream.togglePause(); } _isPlaying = false; _mediaEndReached = true; callEvents(PlayerEvents.PLAYBACK_FINISHED); } case "NetStream.Play.Start": _isPlaying = true; _mediaEndReached = false; if (_stream.bytesLoaded != _stream.bytesTotal || _streamType == StreamType.RTMP) { callEvents(PlayerEvents.BUFFERING); } case "NetStream.Seek.Notify": _mediaEndReached = false; if (_streamType == StreamType.RTMP) { _isPlaying = true; callEvents(PlayerEvents.PLAY_PAUSE); callEvents(PlayerEvents.BUFFERING); } case "NetStream.Buffer.Empty": if (_stream.bytesLoaded != _stream.bytesTotal) { callEvents(PlayerEvents.BUFFERING); } case "NetStream.Buffer.Full": callEvents(PlayerEvents.NOT_BUFFERING); case "NetStream.Buffer.Flush": if (_stream.bytesLoaded == _stream.bytesTotal) { _downloadCompleted = true; } } } /** * Proccess keyboard shortcuts * @param event */ private function onKeyDown(event:KeyboardEvent):Void { var F_KEY:UInt = 70; var M_KEY:UInt = 77; var X_KEY:UInt = 88; if(event.keyCode == Keyboard.TAB) { toggleAspectRatio(); } else if(event.keyCode == F_KEY) { toggleFullscreen(); } else if(event.keyCode == M_KEY) { toggleMute(); } else if(event.keyCode == Keyboard.UP) { volumeUp(); } else if(event.keyCode == Keyboard.DOWN) { volumeDown(); } else if(event.keyCode == Keyboard.RIGHT) { forward(); } else if(event.keyCode == Keyboard.LEFT) { rewind(); } else if(event.keyCode == Keyboard.SPACE) { togglePlay(); } else if(event.keyCode == X_KEY) { stopAndClose(); } } /** * IF player is full screen shows the mouse when gets hide * @param event */ private function onMouseMove(event:MouseEvent):Void { if (_fullscreen && !_mouseVisible) { if (!_hideMouseTimer.running) { _hideMouseTimer.start(); } _mouseVisible = true; Mouse.show(); callEvents(PlayerEvents.MOUSE_SHOW); } } /** * Resize video player * @param event */ private function onResize(event:Event):Void { resizeAndCenterPlayer(); } /** * Dispath a full screen event to listeners as redraw player an takes care of some other aspects * @param event */ private function onFullScreen(event:FullScreenEvent):Void { _fullscreen = event.fullScreen; if (!event.fullScreen) { Mouse.show(); callEvents(PlayerEvents.MOUSE_SHOW); _mouseVisible = true; } else { _mouseVisible = true; _hideMouseTimer.start(); } resizeAndCenterPlayer(); callEvents(PlayerEvents.FULLSCREEN); } /** * Sits for any cue points available * @param data * @note Planned future implementation */ private function onCuePoint(data:Dynamic):Void { } /** * After a video is loaded this callback gets the video information at start and stores it on variables * @param data */ private function onMetaData(data:Dynamic):Void { if (_firstLoad) { _isPlaying = true; _firstLoad = false; if (data.width) { _videoWidth = data.width; _videoHeight = data.height; } else { _videoWidth = _video.width; _videoHeight = _video.height; } //Store seekpoints times if (data.hasOwnProperty("seekpoints")) //MP4 { for (position in Reflect.fields(data.seekpoints)) { _seekPoints.push(Reflect.field(data.seekpoints, position).time); } } else if (data.hasOwnProperty("keyframes")) //FLV { for (position in Reflect.fields(data.keyframes.times)) { _seekPoints.push(Reflect.field(data.keyframes.times, position)); } } _mediaLoaded = true; _mediaDuration = data.duration; _originalAspectRatio = AspectRatio.getAspectRatio(_videoWidth, _videoHeight); if (_aspectRatio <= 0) { _aspectRatio = _originalAspectRatio; } callEvents(PlayerEvents.MEDIA_INITIALIZED); resizeAndCenterPlayer(); //Retrieve the volume that user selected last time setVolume(_userSettings.getVolume()); } } /** * Dummy function invoked for pseudostream servers * @param data */ private function onLastSecond(data:Dynamic):Void { trace("last second pseudostream"); } /** * Broadcast Timeupdate and Duration */ private function onEnterFrame(event:Event):Void { if (getDuration() > 0 && _lastTime != getCurrentTime()) { _lastTime = getCurrentTime(); callEvents(PlayerEvents.TIME); } if (getBytesLoaded() > 0 && _lastProgress < getBytesLoaded()) { _lastProgress = getBytesLoaded(); callEvents(PlayerEvents.PROGRESS); } } /** * Triggers when playbacks end on rtmp streaming server */ private function onPlayStatus(info:Dynamic):Void { _isPlaying = false; _mediaEndReached = true; callEvents(PlayerEvents.PLAYBACK_FINISHED); } /** * When sound finished downloading * @param event */ private function onSoundComplete(event:Event) { _mediaDuration = _sound.length / 1000; _downloadCompleted = true; callEvents(PlayerEvents.MEDIA_INITIALIZED); } /** * Mimic stream onMetaData * @param event */ private function onSoundID3(event:Event) { if (_firstLoad) { _soundChannel = _sound.play(); _checkAudioTimer.start(); _isPlaying = true; _firstLoad = false; _mediaLoaded = true; _mediaDuration = ((_sound.bytesTotal / _sound.bytesLoaded) * _sound.length) / 1000; _aspectRatio = AspectRatio.getAspectRatio(_videoWidth, _videoHeight); _originalAspectRatio = _aspectRatio; _id3Info = _sound.id3; callEvents(PlayerEvents.CONNECTION_SUCCESS); callEvents(PlayerEvents.MEDIA_INITIALIZED); resizeAndCenterPlayer(); //Retrieve the volume that user selected last time setVolume(_userSettings.getVolume()); } } /** * Dispatch connection failed event on error * @param event */ private function onSoundIOError(event:IOErrorEvent) { callEvents(PlayerEvents.CONNECTION_FAILED); } /** * Monitor sound download progress * @param event */ private function onSoundProgress(event:ProgressEvent) { if (_sound.isBuffering) { callEvents(PlayerEvents.BUFFERING); } else { callEvents(PlayerEvents.NOT_BUFFERING); } _mediaDuration = ((_sound.bytesTotal / _sound.bytesLoaded) * _sound.length) / 1000; callEvents(PlayerEvents.MEDIA_INITIALIZED); } /** * Initializes the youtube loader object * @param event */ private function onYouTubeLoaderInit(event:Event):Void { _youtubeLoader.content.addEventListener("onReady", onYoutubeReady); _youtubeLoader.content.addEventListener("onError", onYoutubeError); _youtubeLoader.content.addEventListener("onStateChange", onYoutubeStateChange); _youtubeLoader.content.addEventListener("onPlaybackQualityChange", onYoutubePlaybackQualityChange); } /** * This event is fired when the player is loaded and initialized, meaning it is ready to receive API calls. */ private function onYoutubeReady(event:Event):Void { _movieClip.addChild(_youtubeLoader.content); _movieClip.setChildIndex(_youtubeLoader.content, 0); Reflect.field(_youtubeLoader.content, "setSize")(_stage.stageWidth, _stage.stageHeight); Reflect.field(_youtubeLoader.content, "loadVideoByUrl")(Utils.youtubeSourceParse(_mediaSource)); callEvents(PlayerEvents.BUFFERING); } /** * This event is fired whenever the player's state changes. Possible values are unstarted (-1), ended (0), * playing (1), paused (2), buffering (3), video cued (5). When the SWF is first loaded it will broadcast * an unstarted (-1) event. When the video is cued and ready to play it will broadcast a video cued event (5). * @param event */ private function onYoutubeStateChange(event:Event):Void { var status:UInt = Std.parseInt(Reflect.field(event, "data")); switch(status) { case -1: callEvents(PlayerEvents.BUFFERING); case 0: _isPlaying = false; _mediaEndReached = true; callEvents(PlayerEvents.PLAYBACK_FINISHED); case 1: if (_firstLoad) { _isPlaying = true; _videoWidth = _stage.stageWidth; _videoHeight = _stage.stageHeight; _firstLoad = false; _mediaLoaded = true; _mediaDuration = Reflect.field(_youtubeLoader.content, "getDuration")(); _aspectRatio = AspectRatio.getAspectRatio(_videoWidth, _videoHeight); _originalAspectRatio = _aspectRatio; callEvents(PlayerEvents.CONNECTION_SUCCESS); callEvents(PlayerEvents.MEDIA_INITIALIZED); resizeAndCenterPlayer(); //Retrieve the volume that user selected last time setVolume(_userSettings.getVolume()); } callEvents(PlayerEvents.NOT_BUFFERING); case 2: callEvents(PlayerEvents.NOT_BUFFERING); case 3: callEvents(PlayerEvents.BUFFERING); case 5: callEvents(PlayerEvents.NOT_BUFFERING); } } /** * This event is fired whenever the video playback quality changes. For example, if you call the * setPlaybackQuality(suggestedQuality) function, this event will fire if the playback quality actually * changes. Your code should respond to the event and should not assume that the quality will automatically * change when the setPlaybackQuality(suggestedQuality) function is called. Similarly, your code should not * assume that playback quality will only change as a result of an explicit call to setPlaybackQuality or any * other function that allows you to set a suggested playback quality. * * The value that the event broadcasts is the new playback quality. Possible values are "small", "medium", * "large" and "hd720". * @param event */ private function onYoutubePlaybackQualityChange(event:Event):Void { //trace(Reflect.field(event, "data")); } /** * This event is fired when an error in the player occurs. The possible error codes are 100, 101, * and 150. The 100 error code is broadcast when the video requested is not found. This occurs when * a video has been removed (for any reason), or it has been marked as private. The 101 error code is * broadcast when the video requested does not allow playback in the embedded players. The error code * 150 is the same as 101, it's just 101 in disguise! * @param event */ private function onYoutubeError(event:Event):Void { trace(Reflect.field(event, "data")); } //} //{Private Methods /** * Function used each time is needed to dispatch an event * @param type */ private function callEvents(type:String):Void { var playerEvent:PlayerEvents = new PlayerEvents(type, true); playerEvent.aspectRatio = getAspectRatio(); playerEvent.duration = getDuration(); playerEvent.fullscreen = isFullscreen(); playerEvent.mute = getMute(); playerEvent.volume = getVolume(); playerEvent.width = _video.width; playerEvent.height = _video.height; playerEvent.stream = getNetStream(); playerEvent.sound = getSound(); playerEvent.time = getCurrentTime(); playerEvent.id3Info = getId3Info(); dispatchEvent(playerEvent); } /** * Reposition and resizes the video player to fit on screen */ private function resizeAndCenterPlayer():Void { if (_streamType != StreamType.YOUTUBE) { _video.height = _stage.stageHeight; _video.width = _video.height * _aspectRatio; _video.x = (_stage.stageWidth / 2) - (_video.width / 2); _video.y = 0; if (_video.width > _stage.stageWidth && _aspectRatio == _originalAspectRatio) { var aspectRatio:Float = _videoHeight / _videoWidth; _video.width = _stage.stageWidth; _video.height = aspectRatio * _video.width; _video.x = 0; _video.y = (_stage.stageHeight / 2) - (_video.height / 2); } _videoMask.graphics.clear(); _videoMask.graphics.lineStyle(); _videoMask.graphics.beginFill(0x000000, 0); _videoMask.graphics.drawRect(_video.x, _video.y, _video.width, _video.height); _videoMask.graphics.endFill(); } else { Reflect.field(_youtubeLoader.content, "setSize")(_stage.stageWidth, _stage.stageHeight); _videoMask.graphics.clear(); _videoMask.graphics.lineStyle(); _videoMask.graphics.beginFill(0x000000, 0); _videoMask.graphics.drawRect(0, 0, _stage.stageWidth, _stage.stageHeight); _videoMask.graphics.endFill(); } callEvents(PlayerEvents.RESIZE); } /** * Check the best seek point available if the seekpoints array is available * @param time time in seconds * @return best seek point in seconds or given one if no seekpoints array is available */ private function getBestSeekPoint(time:Float):Float { if (_seekPoints.length > 0) { var timeOne:String="0"; var timeTwo:String="0"; for(prop in Reflect.fields(_seekPoints)) { if(Reflect.field(_seekPoints,prop) < time) { timeOne = prop; } else { timeTwo = prop; break; } } if(time - _seekPoints[Std.parseInt(timeOne)] < _seekPoints[Std.parseInt(timeTwo)] - time) { return _seekPoints[Std.parseInt(timeOne)]; } else { return _seekPoints[Std.parseInt(timeTwo)]; } } return time; } /** * Checks if the given seek time is already buffered * @param time time in seconds * @return true if can seek false if not in buffer */ private function canSeek(time:Float):Bool { if (_type == InputType.VIDEO) { time = getBestSeekPoint(time); } var cacheTotal = Math.floor((getDuration() - _startTime) * (getBytesLoaded() / getBytesTotal())) - 1; if(time >= _startTime && time < _startTime + cacheTotal) { return true; } return false; } //} //{Public methods /** * Loads a video and starts playing it * @param video video url to load */ public function load(source:String, type:String="video", streamType:String="file", server:String=""):Void { stopAndClose(); _type = type; _streamType = streamType; _mediaSource = source; _stopped = false; _mediaLoaded = false; _firstLoad = true; _startTime = 0; _downloadCompleted = false; _seekPoints = new Array(); _server = server; callEvents(PlayerEvents.BUFFERING); if (_streamType == StreamType.YOUTUBE) { Security.allowDomain("*"); Security.allowDomain("www.youtube.com"); Security.allowDomain("youtube.com"); Security.allowDomain("s.ytimg.com"); Security.allowDomain("i.ytimg.com"); _youtubeLoader = new Loader(); _youtubeLoader.contentLoaderInfo.addEventListener(Event.INIT, onYouTubeLoaderInit); _youtubeLoader.load(new URLRequest("http://www.youtube.com/apiplayer?version=3")); } else if (_type == InputType.VIDEO && (_streamType == StreamType.FILE || _streamType == StreamType.PSEUDOSTREAM)) { _connection.connect(null); _stream = new NetStream(_connection); _stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); _stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, doAsyncError); _stream.bufferTime = _bufferTime; _stream.play(source); _stream.client = this; _video.attachNetStream(_stream); } else if (_type == InputType.VIDEO && _streamType == StreamType.RTMP) { _connection.connect(_server); } else if (_type == InputType.AUDIO && _streamType == StreamType.RTMP) { _connection.connect(_server); } else if(_type == InputType.AUDIO && _streamType == StreamType.FILE) { _sound.load(new URLRequest(source)); } } private function doAsyncError(e:AsyncErrorEvent) : Void { // Do nothing, to block the exception. } /** * Closes the connection and makes player available for another video */ public function stopAndClose():Void { if (_mediaLoaded) { _mediaLoaded = false; _isPlaying = false; _stopped = true; _startTime = 0; if (_streamType == StreamType.YOUTUBE) { Reflect.field(_youtubeLoader.content, "destroy")(); } else if (_type == InputType.VIDEO) { _stream.close(); } else { _soundChannel.stop(); _sound.close(); } } callEvents(PlayerEvents.STOP_CLOSE); } /** * Seeks 8 seconds forward from the current position. * @return current play time after forward */ public function forward():Float { var seekTime = (getCurrentTime() + 8) + _startTime; if (getDuration() > seekTime) { seekTime = seek(seekTime); } return seekTime; } /** * Seeks 8 seconds back from the current position. * @return current play time after rewind */ public function rewind():Float { var seekTime = (getCurrentTime() - 8) + _startTime; if (seekTime >= _startTime) { seekTime = seek(seekTime); } return seekTime; } /** * Seeks video player to a given time in seconds * @param seekTime time in seconds to seek * @return current play time after seeking */ public function seek(seekTime:Float):Float { if (_startTime <= 1 && _downloadCompleted) { if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { _stream.seek(seekTime); } else if (_type == InputType.AUDIO) { _soundChannel.stop(); _soundChannel = _sound.play(seekTime * 1000); if (!_isPlaying) { _soundChannel.stop(); } setVolume(_userSettings.getVolume()); } } else if(_seekPoints.length > 0 && _streamType == StreamType.PSEUDOSTREAM) { seekTime = getBestSeekPoint(seekTime); if (canSeek(seekTime)) { _stream.seek(seekTime - _startTime); } else if(seekTime != _startTime) { _startTime = seekTime; var url:String; if (_mediaSource.indexOf("?") != -1) { url = _mediaSource + "&start=" + seekTime; } else { url = _mediaSource + "?start=" + seekTime; } _stream.play(url); } } else if (_streamType == StreamType.YOUTUBE) { if (!canSeek(seekTime)) { _startTime = seekTime; Reflect.field(_youtubeLoader.content, "seekTo")(seekTime); } else { Reflect.field(_youtubeLoader.content, "seekTo")(seekTime); } } else if (_streamType == StreamType.RTMP) { // seekTime = getBestSeekPoint(seekTime); //Not Needed? _stream.seek(seekTime); } else if(canSeek(seekTime)) { if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { _stream.seek(seekTime); } else if (_type == InputType.AUDIO) { _soundChannel.stop(); _soundChannel = _sound.play(seekTime * 1000); if (!_isPlaying) { _soundChannel.stop(); } setVolume(_userSettings.getVolume()); } } callEvents(PlayerEvents.SEEK); return seekTime; } /** * To check wheter the media is playing * @return true if is playing false otherwise */ public function isPlaying():Bool { return _isPlaying; } /** * Cycle betewen aspect ratios * @return new aspect ratio in use */ public function toggleAspectRatio():Float { switch(_currentAspectRatio) { case "original": _aspectRatio = AspectRatio._1_1; _currentAspectRatio = "1:1"; case "1:1": _aspectRatio = AspectRatio._3_2; _currentAspectRatio = "3:2"; case "3:2": _aspectRatio = AspectRatio._4_3; _currentAspectRatio = "4:3"; case "4:3": _aspectRatio = AspectRatio._5_4; _currentAspectRatio = "5:4"; case "5:4": _aspectRatio = AspectRatio._14_9; _currentAspectRatio = "14:9"; case "14:9": _aspectRatio = AspectRatio._14_10; _currentAspectRatio = "14:10"; case "14:10": _aspectRatio = AspectRatio._16_9; _currentAspectRatio = "16:9"; case "16:9": _aspectRatio = AspectRatio._16_10; _currentAspectRatio = "16:10"; case "16:10": _aspectRatio = _originalAspectRatio; _currentAspectRatio = "original"; default: _aspectRatio = _originalAspectRatio; _currentAspectRatio = "original"; } resizeAndCenterPlayer(); callEvents(PlayerEvents.ASPECT_RATIO); //Store aspect ratio into user settings if (_aspectRatio == _originalAspectRatio) { _userSettings.setAspectRatio(0.0); } else { _userSettings.setAspectRatio(_aspectRatio); } return _aspectRatio; } /** * Swithces between play and pause */ public function togglePlay():Bool { if (_mediaLoaded) { if (_mediaEndReached) { _mediaEndReached = false; if (_streamType == StreamType.YOUTUBE) { Reflect.field(_youtubeLoader.content, "seekTo")(0); Reflect.field(_youtubeLoader.content, "playVideo")(); } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { _stream.seek(0); _stream.togglePause(); } else if (_type == InputType.AUDIO) { _checkAudioTimer.start(); _soundChannel = _sound.play(); setVolume(_userSettings.getVolume()); } } else if (_mediaLoaded) { if (_streamType == StreamType.YOUTUBE) { if (_isPlaying) { Reflect.field(_youtubeLoader.content, "pauseVideo")(); } else { Reflect.field(_youtubeLoader.content, "playVideo")(); } } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { _stream.togglePause(); } else if (_type == InputType.AUDIO) { if (_isPlaying) { _soundChannel.stop(); } else { //If end of audio reached start from beggining if (_soundChannel.position + 100 >= _sound.length) { _soundChannel = _sound.play(); } else { _soundChannel = _sound.play(_soundChannel.position); } setVolume(_userSettings.getVolume()); } } } else if (_stopped) { load(_mediaSource, _type, _streamType, _server); } _isPlaying = !_isPlaying; callEvents(PlayerEvents.PLAY_PAUSE); return _isPlaying; } else if(_mediaSource != "") { load(_mediaSource, _type, _streamType, _server); callEvents(PlayerEvents.BUFFERING); return true; } callEvents(PlayerEvents.PLAY_PAUSE); return false; } /** * Switches on or off fullscreen * @return true if fullscreen otherwise false */ public function toggleFullscreen():Bool { if (_fullscreen) { _stage.displayState = StageDisplayState.NORMAL; _stage.focus = _stage; return false; } else { if (_useHardWareScaling) { //Match full screen aspec ratio to desktop var aspectRatio = Capabilities.screenResolutionY / Capabilities.screenResolutionX; _stage.fullScreenSourceRect = new Rectangle(0, 0, _videoWidth, _videoWidth * aspectRatio); } else { //Use desktop resolution _stage.fullScreenSourceRect = new Rectangle(0, 0, Capabilities.screenResolutionX ,Capabilities.screenResolutionY); } _stage.displayState = StageDisplayState.FULL_SCREEN; _stage.focus = _stage; return true; } } /** * Toggles betewen high and low quality image rendering * @return true if quality high false otherwise */ public function toggleQuality():Bool { if (_videoQualityHigh) { _video.smoothing = false; _video.deblocking = 1; } else { _video.smoothing = true; _video.deblocking = 5; } _videoQualityHigh = _videoQualityHigh?false:true; return _videoQualityHigh; } /** * Mutes or unmutes the sound * @return true if muted false if unmuted */ public function toggleMute():Bool { var soundTransform:SoundTransform = new SoundTransform(); var isMute:Bool; //unmute sound if (_soundMuted) { _soundMuted = false; if (_volume > 0) { soundTransform.volume = _volume; } else { _volume = 1.0; soundTransform.volume = _volume; } isMute = false; } //mute sound else { _soundMuted = true; _volume = _stream.soundTransform.volume; soundTransform.volume = 0; _stream.soundTransform = soundTransform; isMute = true; } if (_streamType == StreamType.YOUTUBE) { Reflect.field(_youtubeLoader.content, "setVolume")(soundTransform.volume * 100); } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { _stream.soundTransform = soundTransform; } else if (_type == InputType.AUDIO) { _soundChannel.soundTransform = soundTransform; setVolume(_userSettings.getVolume()); } callEvents(PlayerEvents.MUTE); return isMute; } /** * Check if player is running on fullscreen mode * @return true if fullscreen false if not */ public function isFullscreen():Bool { return _stage.displayState == StageDisplayState.FULL_SCREEN; } /** * Raises the volume * @return volume value after raising */ public function volumeUp():Float { var soundTransform:SoundTransform = new SoundTransform(); if (_soundMuted) { _soundMuted = false; } //raise volume if not already at max if (_volume < 1) { if (_streamType == StreamType.YOUTUBE) { _volume = (Reflect.field(_youtubeLoader.content, "getVolume")() + 10) / 100; Reflect.field(_youtubeLoader.content, "setVolume")(_volume * 100); } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { _volume = _stream.soundTransform.volume + (10/100); soundTransform.volume = _volume; _stream.soundTransform = soundTransform; } else if (_type == InputType.AUDIO) { _volume = _soundChannel.soundTransform.volume + (10/100); soundTransform.volume = _volume; _soundChannel.soundTransform = soundTransform; } } //reset volume to 1.0 if already reached max if (_volume >= 1) { _volume = 1.0; } //Store volume into user settings _userSettings.setVolume(_volume); callEvents(PlayerEvents.VOLUME_UP); return _volume; } /** * Lower the volume * @return volume value after lowering */ public function volumeDown():Float { var soundTransform:SoundTransform = new SoundTransform(); //lower sound if(!_soundMuted) { if (_streamType == StreamType.YOUTUBE) { _volume = (Reflect.field(_youtubeLoader.content, "getVolume")() - 10) / 100; Reflect.field(_youtubeLoader.content, "setVolume")(_volume * 100); } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { _volume = _stream.soundTransform.volume - (10/100); soundTransform.volume = _volume; _stream.soundTransform = soundTransform; } else if (_type == InputType.AUDIO) { _volume = _soundChannel.soundTransform.volume - (10/100); soundTransform.volume = _volume; _soundChannel.soundTransform = soundTransform; } //if volume reached min is muted if (_volume <= 0) { _soundMuted = true; _volume = 0; } } //Store volume into user settings _userSettings.setVolume(_volume); callEvents(PlayerEvents.VOLUME_DOWN); return _volume; } //} //{Setters /** * Set input type * @param type Allowable values are audio, video */ public function setType(type:String):Void { _type = type; } /** * Set streaming type * @param streamType Allowable values are file, http, rmtp */ public function setStreamType(streamType:String):Void { _streamType = streamType; } /** * Sets the server url for rtmp streams * @param server */ public function setServer(server:String):Void { _server = server; } /** * To set the video source in case we dont want to start downloading at first so when use tooglePlay the * media is loaded automatically * @param source */ public function setSource(source):Void { _mediaSource = source; } /** * Changes the current volume * @param volume */ public function setVolume(volume:Float):Void { var soundTransform:SoundTransform = new SoundTransform(); if (volume > _volume) { callEvents(PlayerEvents.VOLUME_UP); } if (volume < _volume) { callEvents(PlayerEvents.VOLUME_DOWN); } if (volume > 0) { _soundMuted = false; _volume = volume; } else { _soundMuted = true; _volume = 1.0; } soundTransform.volume = volume; if (!_firstLoad) //To prevent errors if objects aren't initialized { if (_streamType == StreamType.YOUTUBE) { Reflect.field(_youtubeLoader.content, "setVolume")(soundTransform.volume * 100); } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { _stream.soundTransform = soundTransform; } else if (_type == InputType.AUDIO) { _soundChannel.soundTransform = soundTransform; } } //Store volume into user settings _userSettings.setVolume(_volume); callEvents(PlayerEvents.VOLUME_CHANGE); } /** * Changes the buffer time for local and pseudo streaming * @param time in seconds */ public function setBufferTime(time:Float):Void { if (time > 0) { _bufferTime = time; } } /** * Changes the aspec ratio of current playing media and resizes video player * @param aspectRatio new aspect ratio value */ public function setAspectRatio(aspectRatio:Float):Void { _aspectRatio = aspectRatio; switch(_aspectRatio) { case 0.0: _currentAspectRatio = "original"; case AspectRatio._1_1: _currentAspectRatio = "1:1"; case AspectRatio._3_2: _currentAspectRatio = "3:2"; case AspectRatio._4_3: _currentAspectRatio = "4:3"; case AspectRatio._5_4: _currentAspectRatio = "5:4"; case AspectRatio._14_9: _currentAspectRatio = "14:9"; case AspectRatio._14_10: _currentAspectRatio = "14:10"; case AspectRatio._16_9: _currentAspectRatio = "16:9"; case AspectRatio._16_10: _currentAspectRatio = "16:10"; } resizeAndCenterPlayer(); //Store aspect ratio into user settings _userSettings.setAspectRatio(_aspectRatio); } /** * Enable or disable hardware scaling * @param value true to enable false to disable */ public function setHardwareScaling(value:Bool):Void { _useHardWareScaling = value; } //} //{Getters /** * Gets the volume amount 0.0 to 1.0 * @return */ public function getVolume():Float { return _volume; } /** * The current aspect ratio of the loaded Player * @return */ public function getAspectRatio():Float { return _aspectRatio; } /** * The current aspect ratio of the loaded Player in string format * @return */ public function getAspectRatioString():String { return _currentAspectRatio; } /** * Original aspect ratio of the video * @return original aspect ratio */ public function getOriginalAspectRatio():Float { return _originalAspectRatio; } /** * Total duration time of the loaded media * @return time in seconds */ public function getDuration():Float { return _mediaDuration; } /** * The time in seconds where the player started downloading * @return time in seconds */ public function getStartTime():Float { return _startTime; } /** * The stream associated with the player * @return netstream object */ public function getNetStream():NetStream { return _stream; } /** * Video object associated to the player * @return video object for further manipulation */ public function getVideo():Video { return _video; } /** * Sound object associated to the player * @return sound object for further manipulation */ public function getSound():Sound { return _sound; } /** * The id3 info of sound object * @return */ public function getId3Info():ID3Info { return _id3Info; } /** * The current sound state * @return true if mute otherwise false */ public function getMute():Bool { return _soundMuted; } /** * The amount of total bytes * @return amount of bytes */ public function getBytesTotal():Float { var bytesTotal:Float = 0; if (_streamType == StreamType.YOUTUBE) { if(_youtubeLoader != null && _mediaLoaded) bytesTotal = Reflect.field(_youtubeLoader.content, "getVideoBytesTotal")(); } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { bytesTotal = _stream.bytesTotal; } else if (_type == InputType.AUDIO) { bytesTotal = _sound.bytesTotal; } return bytesTotal; } /** * The amount of bytes loaded * @return amount of bytes */ public function getBytesLoaded():Float { var bytesLoaded:Float = 0; if (_streamType == StreamType.YOUTUBE) { if(_youtubeLoader != null && _mediaLoaded) bytesLoaded = Reflect.field(_youtubeLoader.content, "getVideoBytesLoaded")(); } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { bytesLoaded = _stream.bytesLoaded; } else if (_type == InputType.AUDIO) { bytesLoaded = _sound.bytesLoaded; } return bytesLoaded; } /** * Current playing file type * @return audio or video */ public function getType():String { return _type; } /** * The stream method for the current playing media * @return */ public function getStreamType():String { return _streamType; } /** * The server url for current rtmp stream * @return */ public function getServer():String { return _server; } /** * To check current quality mode * @return true if high quality false if low */ public function getQuality():Bool { return _videoQualityHigh; } /** * The current playing time * @return current playing time in seconds */ public function getCurrentTime():Float { var time:Float = 0; if (_streamType == StreamType.YOUTUBE) { if(_youtubeLoader != null) { time = Reflect.field(_youtubeLoader.content, "getCurrentTime")(); } else { time = 0; } } else if (_streamType == StreamType.PSEUDOSTREAM) { time = getStartTime() + _stream.time; } else if (_type == InputType.VIDEO || _streamType == StreamType.RTMP) { time = _stream.time; } else if (_type == InputType.AUDIO) { if(_soundChannel != null) { time = _soundChannel.position / 1000; } else { time = 0; } } return time; } //} } v2.0.17~dfsg/src/jaris/player/JsApi.hx0000755000000000000000000001644512625374554016325 0ustar rootroot/** * @author Sascha Kluger * @copyright 2010 Jefferson González, Sascha Kluger * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player; //{Libraries import flash.system.Capabilities; import flash.system.Security; import flash.external.ExternalInterface; import flash.display.GradientType; import flash.events.Event; import flash.events.TimerEvent; import flash.geom.Matrix; import flash.Lib; import flash.events.MouseEvent; import flash.display.MovieClip; import flash.net.NetStream; import flash.geom.Rectangle; import flash.net.ObjectEncoding; import flash.text.AntiAliasType; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.utils.Timer; import jaris.animation.Animation; import jaris.display.Loader; import jaris.events.PlayerEvents; import jaris.player.controls.AspectRatioIcon; import jaris.player.controls.FullscreenIcon; import jaris.player.controls.PauseIcon; import jaris.player.controls.PlayIcon; import jaris.player.controls.VolumeIcon; import jaris.player.Player; import flash.display.Sprite; import flash.display.Stage; import jaris.utils.Utils; //} /** * Default controls for jaris player */ class JsApi extends MovieClip { //{Member Variables private var _stage:Stage; private var _movieClip:MovieClip; private var _player:Player; private var _isBuffering:Bool; private var _percentLoaded:Float; private var _externalListeners:Map; //} //{Constructor public function new(player:Player) { super(); _externalListeners = new Map(); Security.allowDomain("*"); //{Main variables // _stage = Lib.current.stage; // _movieClip = Lib.current; _player = player; _player.addEventListener(PlayerEvents.MOUSE_HIDE, onPlayerEvent); _player.addEventListener(PlayerEvents.MOUSE_SHOW, onPlayerEvent); _player.addEventListener(PlayerEvents.MEDIA_INITIALIZED, onPlayerEvent); _player.addEventListener(PlayerEvents.BUFFERING, onPlayerEvent); _player.addEventListener(PlayerEvents.NOT_BUFFERING, onPlayerEvent); _player.addEventListener(PlayerEvents.RESIZE, onPlayerEvent); _player.addEventListener(PlayerEvents.PLAY_PAUSE, onPlayerEvent); _player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayerEvent); _player.addEventListener(PlayerEvents.CONNECTION_FAILED, onPlayerEvent); _player.addEventListener(PlayerEvents.ASPECT_RATIO, onPlayerEvent); _player.addEventListener(PlayerEvents.VOLUME_UP, onPlayerEvent); _player.addEventListener(PlayerEvents.VOLUME_DOWN, onPlayerEvent); _player.addEventListener(PlayerEvents.VOLUME_CHANGE, onPlayerEvent); _player.addEventListener(PlayerEvents.MUTE, onPlayerEvent); _player.addEventListener(PlayerEvents.TIME, onPlayerEvent); _player.addEventListener(PlayerEvents.PROGRESS, onPlayerEvent); _player.addEventListener(PlayerEvents.SEEK, onPlayerEvent); ExternalInterface.addCallback("api_get", getAttribute); ExternalInterface.addCallback("api_addlistener", addJsListener); ExternalInterface.addCallback("api_removelistener", removeJsListener); ExternalInterface.addCallback("api_play", setPlay); ExternalInterface.addCallback("api_pause", setPause); ExternalInterface.addCallback("api_seek", setSeek); ExternalInterface.addCallback("api_volume", setVolume); ExternalInterface.addCallback("api_loadVideo", loadVideo); } public function getAttribute(attribute:String):Float { switch (attribute) { case 'isBuffering': return (_isBuffering) ? 1 : 0; case 'isPlaying': return (_player.isPlaying()) ? 1 : 0; case 'time': return Math.round(_player.getCurrentTime() * 10) / 10; case 'loaded': return _player.getBytesLoaded(); case 'volume': return (_player.getMute()==true) ? 0 : _player.getVolume(); } return 0; } public function addJsListener(attribute:String, parameter:String):Void { _externalListeners.set(attribute.toLowerCase(), parameter); } public function removeJsListener(attribute:String):Void { if (attribute == '*') { _externalListeners = new Map(); return; } _externalListeners.remove(attribute.toLowerCase()); } public function onPlayerEvent(event:PlayerEvents):Void { var jsFunction = ''; var data = { duration: event.duration, fullscreen: event.fullscreen, mute: event.mute, volume: event.volume, position: event.time, type: event.name, loaded: _player.getBytesLoaded(), total: _player.getBytesTotal() }; if (_externalListeners.exists(event.name.toLowerCase())) { ExternalInterface.call(_externalListeners.get(event.name.toLowerCase()), data); } if (_externalListeners.exists('on*')) { ExternalInterface.call(_externalListeners.get('on*'), data); } } /** * Toggles pause or play */ private function setPlay():Void { if (_player.isPlaying()!=true) { _player.togglePlay(); } } /** * Toggles play or pause */ private function setPause():Void { if (_player.isPlaying()==true) { _player.togglePlay(); } } /** * Set Seek */ private function setSeek(pos:Float):Void { _player.seek(pos); } /** * Set Volume */ private function setVolume(vol:Float):Void { if (vol <= 0 && _player.getMute()!=true) { _player.toggleMute(); _player.setVolume(0); return; } if (_player.getMute() == true) { _player.toggleMute(); } if (vol >= 1) { _player.setVolume(1); return; } _player.setVolume(vol); } /** * Loads another video */ private function loadVideo(source:String, type:String="video", streamType:String="file", server:String=""):Void { if (_player.isPlaying()==true) { _player.togglePlay(); } _player.load(source, type, streamType, server); } } v2.0.17~dfsg/src/jaris/player/controls/0000755000000000000000000000000012625374554016604 5ustar rootrootv2.0.17~dfsg/src/jaris/player/controls/AspectRatioIcon.hx0000644000000000000000000000615212625374554022200 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.controls; import flash.display.Sprite; import flash.events.MouseEvent; class AspectRatioIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(2, color); graphics.drawRect(0, 0, _width, _height); var innerWidth:Float = (60 / 100) * width; var innerHeight:Float = (60 / 100) * height; var innerX:Float = (width / 2) - (innerWidth / 2) - 1; var innerY:Float = (height / 2) - (innerHeight / 2) - 1; graphics.lineStyle(); graphics.beginFill(color, 1); graphics.drawRect(innerX, innerY, innerWidth, innerHeight); graphics.endFill(); graphics.lineStyle(); graphics.beginFill(0, 0); graphics.drawRect(0, 0, width, height); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/controls/PauseIcon.hx0000644000000000000000000000562212625374554021040 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.controls; import flash.display.Sprite; import flash.events.MouseEvent; class PauseIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(); graphics.beginFill(color); graphics.drawRoundRect(0, 0, (33 / 100) * _width, _height, 6, 6); graphics.drawRoundRect(_width - ((33 / 100) * _width), 0, (33 / 100) * _width, _height, 6, 6); graphics.endFill(); graphics.lineStyle(); graphics.beginFill(color, 0); graphics.drawRect(0, 0, _width, _height); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/controls/VolumeIcon.hx0000644000000000000000000000563112625374554021232 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.controls; import flash.display.Sprite; import flash.events.MouseEvent; class VolumeIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(); graphics.beginFill(color, 1); graphics.drawRect(0, ((50 / 100) * _height) / 2, _width / 2, ((50 / 100) * _height)); graphics.moveTo(_width / 2, ((50 / 100) * _height)/2); graphics.lineTo(_width, 0); graphics.lineTo(_width, _height); graphics.lineTo(_width / 2, ((50 / 100) * _height) + (((50 / 100) * _height) / 2)); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/controls/Controls.hx0000644000000000000000000007363512625374554020766 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.controls; //{Libraries import flash.display.GradientType; import flash.events.Event; import flash.events.TimerEvent; import flash.geom.Matrix; import flash.Lib; import flash.events.MouseEvent; import flash.display.MovieClip; import flash.net.NetStream; import flash.geom.Rectangle; import flash.text.AntiAliasType; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.utils.Timer; import jaris.animation.Animation; import jaris.display.Loader; import jaris.events.PlayerEvents; import jaris.player.controls.AspectRatioIcon; import jaris.player.controls.FullscreenIcon; import jaris.player.controls.PauseIcon; import jaris.player.controls.PlayIcon; import jaris.player.controls.VolumeIcon; import jaris.player.Player; import flash.display.Sprite; import flash.display.Stage; import jaris.utils.Utils; //} /** * Default controls for jaris player */ class Controls extends MovieClip { //{Member Variables private var _thumb:Sprite; private var _track:Sprite; private var _trackDownloaded:Sprite; private var _scrubbing:Bool; private var _stage:Stage; private var _movieClip:MovieClip; private var _player:Player; private var _darkColor:UInt; private var _brightColor:UInt; private var _controlColor:UInt; private var _hoverColor:UInt; private var _hideControlsTimer:Timer; private var _hideAspectRatioLabelTimer:Timer; private var _currentPlayTimeLabel:TextField; private var _totalPlayTimeLabel:TextField; private var _seekPlayTimeLabel:TextField; private var _percentLoaded:Float; private var _controlsVisible:Bool; private var _seekBar:Sprite; private var _controlsBar:Sprite; private var _playControl:PlayIcon; private var _pauseControl:PauseIcon; private var _aspectRatioControl:AspectRatioIcon; private var _fullscreenControl:FullscreenIcon; private var _volumeIcon:VolumeIcon; private var _volumeTrack:Sprite; private var _volumeSlider:Sprite; private var _loader:Loader; private var _aspectRatioLabelContainer:Sprite; private var _aspectRatioLabel:TextField; private var _textFormat:TextFormat; //} //{Constructor public function new(player:Player) { super(); //{Main variables _stage = Lib.current.stage; _movieClip = Lib.current; _player = player; _darkColor = 0x000000; _brightColor = 0x4c4c4c; _controlColor = 0xFFFFFF; _hoverColor = 0x67A8C1; _percentLoaded = 0.0; _hideControlsTimer = new Timer(500); _hideAspectRatioLabelTimer = new Timer(500); _controlsVisible = false; _textFormat = new TextFormat(); _textFormat.font = "arial"; _textFormat.color = _controlColor; _textFormat.size = 14; //} //{Seeking Controls initialization _seekBar = new Sprite(); addChild(_seekBar); _trackDownloaded = new Sprite( ); _trackDownloaded.tabEnabled = false; _seekBar.addChild(_trackDownloaded); _track = new Sprite( ); _track.tabEnabled = false; _track.buttonMode = true; _track.useHandCursor = true; _seekBar.addChild(_track); _thumb = new Sprite( ); _thumb.buttonMode = true; _thumb.useHandCursor = true; _thumb.tabEnabled = false; _seekBar.addChild(_thumb); _currentPlayTimeLabel = new TextField(); _currentPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT; _currentPlayTimeLabel.text = "00:00:00"; _currentPlayTimeLabel.tabEnabled = false; _currentPlayTimeLabel.setTextFormat(_textFormat); _seekBar.addChild(_currentPlayTimeLabel); _totalPlayTimeLabel = new TextField(); _totalPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT; _totalPlayTimeLabel.text = "00:00:00"; _totalPlayTimeLabel.tabEnabled = false; _totalPlayTimeLabel.setTextFormat(_textFormat); _seekBar.addChild(_totalPlayTimeLabel); _seekPlayTimeLabel = new TextField(); _seekPlayTimeLabel.visible = false; _seekPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT; _seekPlayTimeLabel.text = "00:00:00"; _seekPlayTimeLabel.tabEnabled = false; _seekPlayTimeLabel.setTextFormat(_textFormat); addChild(_seekPlayTimeLabel); //} //{Playing controls initialization _controlsBar = new Sprite(); _controlsBar.visible = true; addChild(_controlsBar); _playControl = new PlayIcon(0, 0, 0, 0, _controlColor, _hoverColor); _controlsBar.addChild(_playControl); _pauseControl = new PauseIcon(0, 0, 0, 0, _controlColor, _hoverColor); _pauseControl.visible = false; _controlsBar.addChild(_pauseControl); _aspectRatioControl = new AspectRatioIcon(0, 0, 0, 0, _controlColor, _hoverColor); _controlsBar.addChild(_aspectRatioControl); _fullscreenControl = new FullscreenIcon(0, 0, 0, 0, _controlColor, _hoverColor); _controlsBar.addChild(_fullscreenControl); _volumeIcon = new VolumeIcon(0, 0, 0, 0, _controlColor, _hoverColor); _controlsBar.addChild(_volumeIcon); _volumeSlider = new Sprite(); _controlsBar.addChild(_volumeSlider); _volumeTrack = new Sprite(); _volumeTrack.buttonMode = true; _volumeTrack.useHandCursor = true; _volumeTrack.tabEnabled = false; _controlsBar.addChild(_volumeTrack); //} //{Aspect ratio label _aspectRatioLabelContainer = new Sprite(); addChild(_aspectRatioLabelContainer); _aspectRatioLabel = new TextField(); _aspectRatioLabel.autoSize = TextFieldAutoSize.CENTER; _aspectRatioLabel.text = "original"; _aspectRatioLabel.tabEnabled = false; _aspectRatioLabelContainer.addChild(_aspectRatioLabel); //} redrawControls(); //{Loader bar _loader = new Loader(); _loader.hide(); var loaderColors:Array = ["", "", "", ""]; loaderColors[0] = Std.string(_brightColor); loaderColors[1] = Std.string(_controlColor); _loader.setColors(loaderColors); addChild(_loader); //} //{event Listeners _movieClip.addEventListener(Event.ENTER_FRAME, onEnterFrame); _thumb.addEventListener(MouseEvent.MOUSE_DOWN, onThumbMouseDown); _thumb.addEventListener(MouseEvent.MOUSE_UP, onThumbMouseUp); _thumb.addEventListener(MouseEvent.MOUSE_OVER, onThumbHover); _thumb.addEventListener(MouseEvent.MOUSE_OUT, onThumbMouseOut); _thumb.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMouseMove); _thumb.addEventListener(MouseEvent.MOUSE_OUT, onTrackMouseOut); _track.addEventListener(MouseEvent.CLICK, onTrackClick); _track.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMouseMove); _track.addEventListener(MouseEvent.MOUSE_OUT, onTrackMouseOut); _playControl.addEventListener(MouseEvent.CLICK, onPlayClick); _pauseControl.addEventListener(MouseEvent.CLICK, onPauseClick); _aspectRatioControl.addEventListener(MouseEvent.CLICK, onAspectRatioClick); _fullscreenControl.addEventListener(MouseEvent.CLICK, onFullscreenClick); _volumeIcon.addEventListener(MouseEvent.CLICK, onVolumeIconClick); _volumeTrack.addEventListener(MouseEvent.CLICK, onVolumeTrackClick); _player.addEventListener(PlayerEvents.MOUSE_HIDE, onPlayerMouseHide); _player.addEventListener(PlayerEvents.MOUSE_SHOW, onPlayerMouseShow); _player.addEventListener(PlayerEvents.MEDIA_INITIALIZED, onPlayerMediaInitialized); _player.addEventListener(PlayerEvents.BUFFERING, onPlayerBuffering); _player.addEventListener(PlayerEvents.NOT_BUFFERING, onPlayerNotBuffering); _player.addEventListener(PlayerEvents.RESIZE, onPlayerResize); _player.addEventListener(PlayerEvents.PLAY_PAUSE, onPlayerPlayPause); _player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayerPlaybackFinished); _player.addEventListener(PlayerEvents.CONNECTION_FAILED, onPlayerStreamNotFound); _player.addEventListener(PlayerEvents.ASPECT_RATIO, onPlayerAspectRatio); _stage.addEventListener(MouseEvent.MOUSE_UP, onThumbMouseUp); _stage.addEventListener(MouseEvent.MOUSE_OUT, onThumbMouseUp); _stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); _stage.addEventListener(Event.RESIZE, onStageResize); _hideControlsTimer.addEventListener(TimerEvent.TIMER, hideControlsTimer); _hideAspectRatioLabelTimer.addEventListener(TimerEvent.TIMER, hideAspectRatioLabelTimer); _hideControlsTimer.start(); //} } //} //{Timers /** * Hides the playing controls when not moving mouse. * @param event The timer event associated */ private function hideControlsTimer(event:TimerEvent):Void { if (_player.isPlaying()) { if (_controlsVisible) { if (_stage.mouseX < _controlsBar.x || _stage.mouseX >= _stage.stageWidth - 1 || _stage.mouseY >= _stage.stageHeight - 1 || _stage.mouseY <= 1 ) { _controlsVisible = false; } } else { hideControls(); _hideControlsTimer.stop(); } } } /** * Hides aspect ratio label * @param event */ private function hideAspectRatioLabelTimer(event:TimerEvent):Void { //wait till fade in effect finish if (_aspectRatioLabelContainer.alpha >= 1) { Animation.fadeOut(_aspectRatioLabelContainer, 300); _hideAspectRatioLabelTimer.stop(); } } //} //{Events /** * Keeps syncronized various elements of the controls like the thumb and download track bar * @param event */ private function onEnterFrame(event:Event):Void { if(_player.getDuration() > 0) { if (_scrubbing) { _player.seek(((_thumb.x - _track.x) / _track.width) * _player.getDuration()); } else { _currentPlayTimeLabel.text = Utils.formatTime(_player.getCurrentTime()); _currentPlayTimeLabel.setTextFormat(_textFormat); _thumb.x = _player.getCurrentTime() / _player.getDuration() * (_track.width-_thumb.width) + _track.x; } } _volumeSlider.height = _volumeTrack.height * (_player.getVolume() / 1.0); _volumeSlider.y = (_volumeTrack.y + _volumeTrack.height) - _volumeSlider.height; drawDownloadProgress(); } /** * Show playing controls on mouse movement. * @param event */ private function onMouseMove(event:MouseEvent):Void { if (_stage.mouseX >= _controlsBar.x) { if (!_hideControlsTimer.running) { _hideControlsTimer.start(); } _controlsVisible = true; showControls(); } } /** * Function fired by a stage resize eventthat redraws the player controls * @param event */ private function onStageResize(event:Event):Void { redrawControls(); } /** * Toggles pause or play * @param event */ private function onPlayClick(event:MouseEvent):Void { _player.togglePlay(); _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); } /** * Toggles pause or play * @param event */ private function onPauseClick(event:MouseEvent):Void { _player.togglePlay(); _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); } /** * Toggles betewen aspect ratios * @param event */ private function onAspectRatioClick(event:MouseEvent):Void { _player.toggleAspectRatio(); } /** * Toggles between window and fullscreen mode * @param event */ private function onFullscreenClick(event:MouseEvent):Void { _player.toggleFullscreen(); } /** * Toggles between mute and unmute * @param event */ private function onVolumeIconClick(event: MouseEvent):Void { _player.toggleMute(); } /** * Detect user click on volume track control and change volume according * @param event */ private function onVolumeTrackClick(event:MouseEvent):Void { var percent:Float = _volumeTrack.height - _volumeTrack.mouseY; var volume:Float = 1.0 * (percent / _volumeTrack.height); _player.setVolume(volume); } /** * Display not found message * @param event */ private function onPlayerStreamNotFound(event:PlayerEvents):Void { //todo: to work on this } /** * Shows the loader bar when buffering * @param event */ private function onPlayerBuffering(event:PlayerEvents):Void { _loader.show(); } /** * Hides loader bar when not buffering * @param event */ private function onPlayerNotBuffering(event:PlayerEvents):Void { _loader.hide(); } /** * Show the selected aspect ratio * @param event */ private function onPlayerAspectRatio(event:PlayerEvents):Void { _hideAspectRatioLabelTimer.stop(); _aspectRatioLabel.text = _player.getAspectRatioString(); drawAspectRatioLabel(); while (_aspectRatioLabelContainer.visible) { //wait till fade out finishes } Animation.fadeIn(_aspectRatioLabelContainer, 300); _hideAspectRatioLabelTimer.start(); } /** * Monitors playbeack when finishes tu update controls * @param event */ private function onPlayerPlaybackFinished(event:PlayerEvents):Void { _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); showControls(); } /** * Monitors keyboard play pause actions to update icons * @param event */ private function onPlayerPlayPause(event:PlayerEvents):Void { _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); } /** * Resizes the video player on windowed mode substracting the seekbar height * @param event */ private function onPlayerResize(event:PlayerEvents):Void { if (!_player.isFullscreen()) { if (_player.getVideo().y + _player.getVideo().height >= _stage.stageHeight) { _player.getVideo().height = _stage.stageHeight - _seekBar.height; _player.getVideo().width = _player.getVideo().height * _player.getAspectRatio(); _player.getVideo().x = (_stage.stageWidth / 2) - (_player.getVideo().width / 2); } } } /** * Updates media total time duration. * @param event */ private function onPlayerMediaInitialized(event:PlayerEvents):Void { _totalPlayTimeLabel.text = Utils.formatTime(event.duration); _totalPlayTimeLabel.setTextFormat(_textFormat); _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); } /** * Hides seekbar if on fullscreen. * @param event */ private function onPlayerMouseHide(event:PlayerEvents):Void { if (_seekBar.visible && _player.isFullscreen()) { Animation.slideOut(_seekBar, "bottom", 1000); } } /** * Shows seekbar * @param event */ private function onPlayerMouseShow(event:PlayerEvents):Void { //Only use slidein effect on fullscreen since switching to windowed mode on //hardware scaling causes a bug by a slow response on stage height changes if (_player.isFullscreen() && !_seekBar.visible) { Animation.slideIn(_seekBar, "bottom",1000); } else { _seekBar.visible = true; } } /** * Translates a user click in to time and seeks to it * @param event */ private function onTrackClick(event:MouseEvent):Void { var clickPosition:Float = _track.mouseX; _player.seek(_player.getDuration() * (clickPosition / _track.width)); } /** * Shows a small tooltip showing the time calculated by mouse position * @param event */ private function onTrackMouseMove(event:MouseEvent):Void { var clickPosition:Float = _track.mouseX; _seekPlayTimeLabel.text = Utils.formatTime(_player.getDuration() * (clickPosition / _track.width)); _seekPlayTimeLabel.setTextFormat(_textFormat); _seekPlayTimeLabel.y = _stage.stageHeight - _seekBar.height - _seekPlayTimeLabel.height - 1; _seekPlayTimeLabel.x = clickPosition + (_seekPlayTimeLabel.width / 2); _seekPlayTimeLabel.backgroundColor = _brightColor; _seekPlayTimeLabel.background = true; _seekPlayTimeLabel.textColor = _controlColor; _seekPlayTimeLabel.borderColor = _darkColor; _seekPlayTimeLabel.border = true; if (!_seekPlayTimeLabel.visible) { Animation.fadeIn(_seekPlayTimeLabel, 300); } } /** * Hides the tooltip that shows the time calculated by mouse position * @param event */ private function onTrackMouseOut(event:MouseEvent):Void { Animation.fadeOut(_seekPlayTimeLabel, 300); } /** * Enables dragging of thumb for seeking media * @param event */ private function onThumbMouseDown(event:MouseEvent):Void { _scrubbing = true; var rectangle:Rectangle = new Rectangle(_track.x, _track.y, _track.width-_thumb.width, 0); _thumb.startDrag(false, rectangle); } /** * Changes thumb seek control to hover color * @param event */ private function onThumbHover(event:MouseEvent):Void { _thumb.graphics.lineStyle(); _thumb.graphics.beginFill(_hoverColor); _thumb.graphics.drawRect(0, (_seekBar.height/2)-(10/2), 10, 10); _thumb.graphics.endFill(); } /** * Changes thumb seek control to control color * @param event */ private function onThumbMouseOut(event:MouseEvent):Void { _thumb.graphics.lineStyle(); _thumb.graphics.beginFill(_controlColor); _thumb.graphics.drawRect(0, (_seekBar.height/2)-(10/2), 10, 10); _thumb.graphics.endFill(); } /** * Disables dragging of thumb * @param event */ private function onThumbMouseUp(event:MouseEvent):Void { _scrubbing = false; _thumb.stopDrag( ); } //} //{Drawing functions /** * Clears all current graphics a draw new ones */ private function redrawControls():Void { drawSeekControls(); drawPlayingControls(); drawAspectRatioLabel(); } /** * Draws the download progress track bar */ private function drawDownloadProgress():Void { if (_player.getBytesTotal() > 0) { var bytesLoaded:Float = _player.getBytesLoaded(); var bytesTotal:Float = _player.getBytesTotal(); _percentLoaded = bytesLoaded / bytesTotal; } var position:Float = _player.getStartTime() / _player.getDuration(); //var startPosition:Float = (position * _track.width) + _track.x; //Old way var startPosition:Float = (position > 0?(position * _track.width):0) + _track.x; _trackDownloaded.graphics.clear(); _trackDownloaded.graphics.lineStyle(); _trackDownloaded.x = startPosition; _trackDownloaded.graphics.beginFill(_brightColor, 0xFFFFFF); _trackDownloaded.graphics.drawRect(0, (_seekBar.height / 2) - (10 / 2), ((_track.width + _track.x) - _trackDownloaded.x) * _percentLoaded, 10); _trackDownloaded.graphics.endFill(); } /** * Draws all seekbar controls */ private function drawSeekControls() { //Reset sprites for redraw _seekBar.graphics.clear(); _track.graphics.clear(); _thumb.graphics.clear(); //Draw seek bar var _seekBarWidth:UInt = _stage.stageWidth; var _seekBarHeight:UInt = 25; _seekBar.x = 0; _seekBar.y = _stage.stageHeight - _seekBarHeight; var matrix:Matrix = new Matrix( ); matrix.createGradientBox(_seekBarWidth, _seekBarHeight, Utils.degreesToRadians(90), 0, 0); var colors:Array = [_brightColor, _darkColor]; var alphas:Array = [1, 1]; var ratios:Array = [0, 255]; _seekBar.graphics.lineStyle(); _seekBar.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); _seekBar.graphics.drawRect(0, 0, _seekBarWidth, _seekBarHeight); _seekBar.graphics.endFill(); _textFormat.color = _controlColor; //Draw current play time label _currentPlayTimeLabel.y = _seekBarHeight - (_seekBarHeight / 2) - (_currentPlayTimeLabel.height / 2); _currentPlayTimeLabel.antiAliasType = AntiAliasType.ADVANCED; _currentPlayTimeLabel.setTextFormat(_textFormat); //Draw total play time label _totalPlayTimeLabel.x = _seekBarWidth - _totalPlayTimeLabel.width; _totalPlayTimeLabel.y = _seekBarHeight - (_seekBarHeight / 2) - (_totalPlayTimeLabel.height / 2); _totalPlayTimeLabel.antiAliasType = AntiAliasType.ADVANCED; _totalPlayTimeLabel.setTextFormat(_textFormat); //Draw download progress drawDownloadProgress(); //Draw track place holder for drag _track.x = _currentPlayTimeLabel.width; _track.graphics.lineStyle(1, _controlColor); _track.graphics.beginFill(_darkColor, 0); _track.graphics.drawRect(0, (_seekBarHeight / 2) - (10 / 2), _seekBarWidth - _currentPlayTimeLabel.width - _totalPlayTimeLabel.width, 10); _track.graphics.endFill(); //Draw thumb _thumb.x = _currentPlayTimeLabel.width; _thumb.graphics.lineStyle(); _thumb.graphics.beginFill(_controlColor); _thumb.graphics.drawRect(0, (_seekBarHeight/2)-(10/2), 10, 10); _thumb.graphics.endFill(); } /** * Draws control bar player controls */ private function drawPlayingControls():Void { //Reset sprites for redraw _controlsBar.graphics.clear(); _volumeTrack.graphics.clear(); _volumeSlider.graphics.clear(); //Draw controls bar var barMargin = _stage.stageHeight < 330 ? 5 : 25; var barHeight = _stage.stageHeight - _seekBar.height - (barMargin * 2); var barWidth = _stage.stageHeight < 330 ? 45 : 60; _controlsBar.x = (_stage.stageWidth - barWidth) + 20; _controlsBar.y = barMargin; var matrix:Matrix = new Matrix( ); matrix.createGradientBox(barWidth, barHeight, Utils.degreesToRadians(0), 0, barHeight); var colors:Array = [_brightColor, _darkColor]; var alphas:Array = [0.75, 0.75]; var ratios:Array = [0, 255]; _controlsBar.graphics.lineStyle(); _controlsBar.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); _controlsBar.graphics.drawRoundRect(0, 0, barWidth, barHeight, 20, 20); _controlsBar.graphics.endFill(); var topMargin:Float = _stage.stageHeight < 330 ? 5 : 10; var barCenter:Float = (barWidth - 20) / 2; var buttonSize:Float = ((80 / 100) * (barWidth - 20)); var buttonX:Float = buttonSize / 2; //Draw playbutton _playControl.setNormalColor(_controlColor); _playControl.setHoverColor(_hoverColor); _playControl.setPosition(barCenter - buttonX, topMargin); _playControl.setSize(buttonSize, buttonSize); //Draw pausebutton _pauseControl.setNormalColor(_controlColor); _pauseControl.setHoverColor(_hoverColor); _pauseControl.setPosition(_playControl.x, topMargin); _pauseControl.setSize(buttonSize, buttonSize); //Draw aspec ratio button _aspectRatioControl.setNormalColor(_controlColor); _aspectRatioControl.setHoverColor(_hoverColor); _aspectRatioControl.setPosition(_playControl.x, (_playControl.y + buttonSize) + topMargin); _aspectRatioControl.setSize(buttonSize, buttonSize); //Draw fullscreen button _fullscreenControl.setNormalColor(_controlColor); _fullscreenControl.setHoverColor(_hoverColor); _fullscreenControl.setPosition(_playControl.x, (_aspectRatioControl.y + _aspectRatioControl.height) + topMargin); _fullscreenControl.setSize(buttonSize, buttonSize); //Draw volume icon _volumeIcon.setNormalColor(_controlColor); _volumeIcon.setHoverColor(_hoverColor); _volumeIcon.setPosition(_playControl.x, barHeight - _playControl.height - topMargin); _volumeIcon.setSize(buttonSize, buttonSize); //Draw volume track _volumeTrack.x = _playControl.x; _volumeTrack.y = (_fullscreenControl.y + _fullscreenControl.height) + topMargin; _volumeTrack.graphics.lineStyle(1, _controlColor); _volumeTrack.graphics.beginFill(0x000000, 0); _volumeTrack.graphics.drawRect(0, 0, _playControl.width / 2, _volumeIcon.y - (_fullscreenControl.y + _fullscreenControl.height) - (topMargin*2)); _volumeTrack.graphics.endFill(); _volumeTrack.x = barCenter - (_volumeTrack.width / 2); //Draw volume slider _volumeSlider.x = _volumeTrack.x; _volumeSlider.y = _volumeTrack.y; _volumeSlider.graphics.lineStyle(); _volumeSlider.graphics.beginFill(_controlColor, 1); _volumeSlider.graphics.drawRect(0, 0, _volumeTrack.width, _volumeTrack.height); _volumeSlider.graphics.endFill(); } private function drawAspectRatioLabel():Void { _aspectRatioLabelContainer.graphics.clear(); _aspectRatioLabelContainer.visible = false; //Update aspect ratio label var textFormat:TextFormat = new TextFormat(); textFormat.font = "arial"; textFormat.bold = true; textFormat.size = 40; textFormat.color = _controlColor; _aspectRatioLabel.setTextFormat(textFormat); _aspectRatioLabel.x = (_stage.stageWidth / 2) - (_aspectRatioLabel.width / 2); _aspectRatioLabel.y = (_stage.stageHeight / 2) - (_aspectRatioLabel.height / 2); //Draw aspect ratio label container _aspectRatioLabelContainer.x = _aspectRatioLabel.x - 10; _aspectRatioLabelContainer.y = _aspectRatioLabel.y - 10; _aspectRatioLabelContainer.graphics.lineStyle(3, _controlColor); _aspectRatioLabelContainer.graphics.beginFill(_brightColor, 1); _aspectRatioLabelContainer.graphics.drawRoundRect(0, 0, _aspectRatioLabel.width + 20, _aspectRatioLabel.height + 20, 15, 15); _aspectRatioLabelContainer.graphics.endFill(); _aspectRatioLabel.x = 10; _aspectRatioLabel.y = 10; } //} //{Private Methods /** * Hide the play controls bar */ private function hideControls():Void { if(_controlsBar.visible) { drawPlayingControls(); Animation.slideOut(_controlsBar, "right", 800); } } /** * Shows play controls bar */ private function showControls():Void { if(!_controlsBar.visible) { drawPlayingControls(); Animation.slideIn(_controlsBar, "right", 800); } } //} //{Setters /** * Sets the player colors and redraw them * @param colors Array of colors in the following order: darkColor, brightColor, controlColor, hoverColor */ public function setControlColors(colors:Array):Void { _darkColor = colors[0].length > 0? Std.parseInt("0x" + colors[0]) : 0x000000; _brightColor = colors[1].length > 0? Std.parseInt("0x" + colors[1]) : 0x4c4c4c; _controlColor = colors[2].length > 0? Std.parseInt("0x" + colors[2]) : 0xFFFFFF; _hoverColor = colors[3].length > 0? Std.parseInt("0x" + colors[3]) : 0x67A8C1; var loaderColors:Array = ["", ""]; loaderColors[0] = colors[1]; loaderColors[1] = colors[2]; _loader.setColors(loaderColors); redrawControls(); } /** * To set the duration label when autostart parameter is false * @param duration in seconds or formatted string in format hh:mm:ss */ public function setDurationLabel(duration:String):Void { //Person passed time already formatted if (duration.indexOf(":") != -1) { _totalPlayTimeLabel.text = duration; } //Time passed in seconds else { _totalPlayTimeLabel.text = Std.string(Utils.formatTime(Std.parseFloat(duration))); } _totalPlayTimeLabel.setTextFormat(_textFormat); } //} } v2.0.17~dfsg/src/jaris/player/controls/FullscreenIcon.hx0000644000000000000000000000575112625374554022070 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.controls; import flash.display.Sprite; import flash.events.MouseEvent; class FullscreenIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(2, color); graphics.beginFill(0x000000, 0); graphics.drawRoundRect(0, 0, _width, _height, 6, 6); graphics.endFill(); graphics.lineStyle(); graphics.beginFill(color, 1); graphics.drawRoundRect(3, 3, 4, 4, 2, 2); graphics.drawRoundRect(width - 9, 3, 4, 4, 2, 2); graphics.drawRoundRect(3, height - 9, 4, 4, 2, 2); graphics.drawRoundRect(width - 9, height - 9, 4, 4, 2, 2); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/controls/PlayIcon.hx0000644000000000000000000000527612625374554020675 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.controls; import flash.display.Sprite; import flash.events.MouseEvent; class PlayIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(); graphics.beginFill(color); graphics.lineTo(0, _height); graphics.lineTo(_width, _height / 2); graphics.lineTo(0, 0); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/Loop.hx0000755000000000000000000000260412625374554016220 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player; //{Libraries import jaris.events.PlayerEvents; //} /** * Implements a loop mechanism on the player */ class Loop { private var _player:Player; public function new(player:Player) { _player = player; _player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayerStop); } /** * Everytime the player stops, the playback is restarted * @param event */ private function onPlayerStop(event:PlayerEvents):Void { _player.togglePlay(); } } v2.0.17~dfsg/src/jaris/player/StreamType.hx0000644000000000000000000000220012625374554017371 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player; /** * Some constants for the stream types */ class StreamType { public static var FILE:String = "file"; public static var PSEUDOSTREAM:String = "http"; public static var RTMP:String = "rtmp"; public static var YOUTUBE = "youtube"; } v2.0.17~dfsg/src/jaris/player/newcontrols/0000755000000000000000000000000012625374554017316 5ustar rootrootv2.0.17~dfsg/src/jaris/player/newcontrols/AspectRatioIcon.hx0000755000000000000000000000726412625374554022722 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.newcontrols; import flash.display.Sprite; import flash.events.MouseEvent; import flash.geom.Matrix; import jaris.utils.Utils; import flash.display.GradientType; class AspectRatioIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(0, color, 0.0); graphics.beginFill(color, 0); graphics.drawRect(0, 0, _width, _height); graphics.endFill(); var matrix:Matrix = new Matrix( ); matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0); var colors:Array = [color, color]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; var innerWidth:Float = (70 / 100) * width; var innerHeight:Float = (40 / 100) * height; var innerX:Float = (width / 2) - (innerWidth / 2) + 1 ; var innerY:Float = (height / 2) - (innerHeight / 2) + 1; graphics.lineStyle(); graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); //graphics.beginFill(color, 1); graphics.drawRect(0, 0, 1, _height+1); graphics.drawRect(0, 0, _width+1, 1); graphics.drawRect(_width+1, 0, 1, _height+1); graphics.drawRect(0, _height+1, _width+1, 1); graphics.drawRect(innerX, innerY, innerWidth, innerHeight); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/newcontrols/PauseIcon.hx0000755000000000000000000000677012625374554021562 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.newcontrols; import flash.display.Sprite; import flash.events.MouseEvent; import flash.geom.Matrix; import jaris.utils.Utils; import flash.display.GradientType; class PauseIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(0, color, 0.0); graphics.beginFill(color, 0); graphics.drawRect(0, 0, _width, _height); graphics.endFill(); var matrix:Matrix = new Matrix( ); matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0); var colors:Array = [color, color]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; graphics.lineStyle(); graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); //graphics.beginFill(color); graphics.drawRoundRect(0, 0, (33 / 100) * _width, _height, 6, 6); graphics.drawRoundRect(_width - ((33 / 100) * _width), 0, (33 / 100) * _width, _height, 6, 6); graphics.endFill(); graphics.lineStyle(); graphics.beginFill(color, 0); graphics.drawRect(0, 0, _width, _height); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/newcontrols/VolumeIcon.hx0000755000000000000000000000701712625374554021747 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.newcontrols; import flash.display.Sprite; import flash.events.MouseEvent; import flash.geom.Matrix; import jaris.utils.Utils; import flash.display.GradientType; class VolumeIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(0, color, 0.0); graphics.beginFill(color, 0); graphics.drawRect(0, 0, _width, _height); graphics.endFill(); var matrix:Matrix = new Matrix( ); matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0); var colors:Array = [color, color]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; graphics.lineStyle(); graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); //graphics.beginFill(color, 1); graphics.drawRect(0, ((50 / 100) * _height) / 2+1, _width / 2-1, ((50 / 100) * _height)); graphics.moveTo(_width / 2 -1, ((50 / 100) * _height)/2+1); graphics.lineTo(_width, 0); graphics.lineTo(_width, _height+2); graphics.lineTo(_width / 2 -1, ((50 / 100) * _height) + (((50 / 100) * _height) / 2)+1); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/newcontrols/NewControls.hx0000755000000000000000000007660612625374554022156 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.newcontrols; //{Libraries import flash.display.GradientType; import flash.events.Event; import flash.events.TimerEvent; import flash.geom.Matrix; import flash.Lib; import flash.events.MouseEvent; import flash.display.MovieClip; import flash.net.NetStream; import flash.geom.Rectangle; import flash.text.AntiAliasType; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.utils.Timer; import jaris.animation.Animation; import jaris.events.PlayerEvents; import jaris.player.newcontrols.Loader; import jaris.player.newcontrols.AspectRatioIcon; import jaris.player.newcontrols.FullscreenIcon; import jaris.player.newcontrols.PauseIcon; import jaris.player.newcontrols.PlayIcon; import jaris.player.newcontrols.VolumeIcon; import jaris.player.Player; import flash.display.Sprite; import flash.display.Stage; import jaris.utils.Utils; //} /** * Default controls for jaris player */ class NewControls extends MovieClip { //{Member Variables private var _thumb:Sprite; private var _track:Sprite; private var _trackDownloaded:Sprite; private var _scrubbing:Bool; private var _stage:Stage; private var _movieClip:MovieClip; private var _player:Player; private var _darkColor:UInt; private var _brightColor:UInt; private var _seekColor:UInt; private var _controlColor:UInt; private var _controlSize:Int; private var _hoverColor:UInt; private var _hideControlsTimer:Timer; private var _hideAspectRatioLabelTimer:Timer; private var _currentPlayTimeLabel:TextField; private var _totalPlayTimeLabel:TextField; private var _seekPlayTimeLabel:TextField; private var _percentLoaded:Float; private var _controlsVisible:Bool; private var _seekBar:Sprite; private var _controlsBar:Sprite; private var _playControl:PlayIcon; private var _pauseControl:PauseIcon; private var _aspectRatioControl:AspectRatioIcon; private var _fullscreenControl:FullscreenIcon; private var _volumeIcon:VolumeIcon; private var _volumeTrack:Sprite; private var _volumeSlider:Sprite; private var _loader:Loader; private var _aspectRatioLabelContainer:Sprite; private var _aspectRatioLabel:TextField; private var _textFormat:TextFormat; //} //{Constructor public function new(player:Player) { super(); //{Main variables _stage = Lib.current.stage; _movieClip = Lib.current; _player = player; _darkColor = 0x000000; _brightColor = 0x4c4c4c; _controlColor = 0xFFFFFF; _hoverColor = 0x67A8C1; _seekColor = 0x7c7c7c; _controlSize = 40; _percentLoaded = 0.0; _hideControlsTimer = new Timer(500); _hideAspectRatioLabelTimer = new Timer(500); _controlsVisible = false; _textFormat = new TextFormat(); _textFormat.font = "arial"; _textFormat.color = _controlColor; _textFormat.size = 14; //} //{Playing controls initialization _controlsBar = new Sprite(); _controlsBar.visible = true; addChild(_controlsBar); _playControl = new PlayIcon(0, 0, 0, 0, _controlColor, _hoverColor); _controlsBar.addChild(_playControl); _pauseControl = new PauseIcon(0, 0, 0, 0, _controlColor, _hoverColor); _pauseControl.visible = false; _controlsBar.addChild(_pauseControl); _aspectRatioControl = new AspectRatioIcon(0, 0, 0, 0, _controlColor, _hoverColor); _controlsBar.addChild(_aspectRatioControl); _fullscreenControl = new FullscreenIcon(0, 0, 0, 0, _controlColor, _hoverColor); _controlsBar.addChild(_fullscreenControl); _volumeIcon = new VolumeIcon(0, 0, 0, 0, _controlColor, _hoverColor); _controlsBar.addChild(_volumeIcon); _volumeSlider = new Sprite(); _volumeSlider.visible = false; _controlsBar.addChild(_volumeSlider); _volumeTrack = new Sprite(); _volumeTrack.visible = false; _volumeTrack.buttonMode = true; _volumeTrack.useHandCursor = true; _volumeTrack.tabEnabled = false; _controlsBar.addChild(_volumeTrack); //} //{Seeking Controls initialization _seekBar = new Sprite(); _controlsBar.addChild(_seekBar); _trackDownloaded = new Sprite( ); _trackDownloaded.tabEnabled = false; _seekBar.addChild(_trackDownloaded); _track = new Sprite( ); _track.tabEnabled = false; _track.buttonMode = true; _track.useHandCursor = true; _seekBar.addChild(_track); _thumb = new Sprite( ); _thumb.buttonMode = true; _thumb.useHandCursor = true; _thumb.tabEnabled = false; _seekBar.addChild(_thumb); _currentPlayTimeLabel = new TextField(); _currentPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT; _currentPlayTimeLabel.text = "00:00:00"; _currentPlayTimeLabel.tabEnabled = false; _currentPlayTimeLabel.setTextFormat(_textFormat); _seekBar.addChild(_currentPlayTimeLabel); _totalPlayTimeLabel = new TextField(); _totalPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT; _totalPlayTimeLabel.text = "00:00:00"; _totalPlayTimeLabel.tabEnabled = false; _totalPlayTimeLabel.setTextFormat(_textFormat); _seekBar.addChild(_totalPlayTimeLabel); _seekPlayTimeLabel = new TextField(); _seekPlayTimeLabel.visible = false; _seekPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT; _seekPlayTimeLabel.text = "00:00:00"; _seekPlayTimeLabel.tabEnabled = false; _seekPlayTimeLabel.setTextFormat(_textFormat); addChild(_seekPlayTimeLabel); //} //{Aspect ratio label _aspectRatioLabelContainer = new Sprite(); addChild(_aspectRatioLabelContainer); _aspectRatioLabel = new TextField(); _aspectRatioLabel.autoSize = TextFieldAutoSize.CENTER; _aspectRatioLabel.text = "original"; _aspectRatioLabel.tabEnabled = false; _aspectRatioLabelContainer.addChild(_aspectRatioLabel); //} redrawControls(); //{Loader bar _loader = new Loader(); _loader.hide(); var loaderColors:Array = ["", "", "", ""]; loaderColors[0] = Std.string(_darkColor); loaderColors[1] = Std.string(_controlColor); loaderColors[2] = Std.string(_seekColor); _loader.setColors(loaderColors); addChild(_loader); //} //{event Listeners _movieClip.addEventListener(Event.ENTER_FRAME, onEnterFrame); _thumb.addEventListener(MouseEvent.MOUSE_DOWN, onThumbMouseDown); _thumb.addEventListener(MouseEvent.MOUSE_UP, onThumbMouseUp); _thumb.addEventListener(MouseEvent.MOUSE_OVER, onThumbHover); _thumb.addEventListener(MouseEvent.MOUSE_OUT, onThumbMouseOut); _thumb.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMouseMove); _thumb.addEventListener(MouseEvent.MOUSE_OUT, onTrackMouseOut); _track.addEventListener(MouseEvent.CLICK, onTrackClick); _track.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMouseMove); _track.addEventListener(MouseEvent.MOUSE_OUT, onTrackMouseOut); _playControl.addEventListener(MouseEvent.CLICK, onPlayClick); _pauseControl.addEventListener(MouseEvent.CLICK, onPauseClick); _aspectRatioControl.addEventListener(MouseEvent.CLICK, onAspectRatioClick); _fullscreenControl.addEventListener(MouseEvent.CLICK, onFullscreenClick); _volumeIcon.addEventListener(MouseEvent.CLICK, onVolumeIconClick); _volumeTrack.addEventListener(MouseEvent.CLICK, onVolumeTrackClick); _player.addEventListener(PlayerEvents.MOUSE_HIDE, onPlayerMouseHide); _player.addEventListener(PlayerEvents.MOUSE_SHOW, onPlayerMouseShow); _player.addEventListener(PlayerEvents.MEDIA_INITIALIZED, onPlayerMediaInitialized); _player.addEventListener(PlayerEvents.BUFFERING, onPlayerBuffering); _player.addEventListener(PlayerEvents.NOT_BUFFERING, onPlayerNotBuffering); _player.addEventListener(PlayerEvents.RESIZE, onPlayerResize); _player.addEventListener(PlayerEvents.PLAY_PAUSE, onPlayerPlayPause); _player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayerPlaybackFinished); _player.addEventListener(PlayerEvents.CONNECTION_FAILED, onPlayerStreamNotFound); _player.addEventListener(PlayerEvents.ASPECT_RATIO, onPlayerAspectRatio); _stage.addEventListener(MouseEvent.MOUSE_UP, onThumbMouseUp); _stage.addEventListener(MouseEvent.MOUSE_OUT, onThumbMouseUp); _stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); _stage.addEventListener(Event.RESIZE, onStageResize); _hideControlsTimer.addEventListener(TimerEvent.TIMER, hideControlsTimer); _hideAspectRatioLabelTimer.addEventListener(TimerEvent.TIMER, hideAspectRatioLabelTimer); _hideControlsTimer.start(); //} } //} //{Timers /** * Hides the playing controls when not moving mouse. * @param event The timer event associated */ private function hideControlsTimer(event:TimerEvent):Void { if (_player.isPlaying()) { if (_controlsVisible) { if (_stage.mouseX <= 1 || _stage.mouseX >= _stage.stageWidth - 1 || _stage.mouseY >= _stage.stageHeight - 1 || _stage.mouseY < _controlsBar.y ) { _controlsVisible = false; } } else { hideControls(); _hideControlsTimer.stop(); } } } /** * Hides aspect ratio label * @param event */ private function hideAspectRatioLabelTimer(event:TimerEvent):Void { //wait till fade in effect finish if (_aspectRatioLabelContainer.alpha >= 1) { Animation.fadeOut(_aspectRatioLabelContainer, 300); _hideAspectRatioLabelTimer.stop(); } } //} //{Events /** * Keeps syncronized various elements of the controls like the thumb and download track bar * @param event */ private function onEnterFrame(event:Event):Void { if(_player.getDuration() > 0) { if (_scrubbing) { _player.seek(((_thumb.x - _track.x) / _track.width) * _player.getDuration()); } else { _currentPlayTimeLabel.text = Utils.formatTime(_player.getCurrentTime()); _currentPlayTimeLabel.setTextFormat(_textFormat); _thumb.x = _player.getCurrentTime() / _player.getDuration() * (_track.width-_thumb.width) + _track.x; } } _volumeSlider.height = _volumeTrack.height * (_player.getVolume() / 1.0); _volumeSlider.y = (_volumeTrack.y + _volumeTrack.height) - _volumeSlider.height; drawDownloadProgress(); } /** * Show playing controls on mouse movement. * @param event */ private function onMouseMove(event:MouseEvent):Void { if (_stage.mouseY >= _controlsBar.y) { if (!_hideControlsTimer.running) { _hideControlsTimer.start(); } _controlsVisible = true; showControls(); } } /** * Function fired by a stage resize eventthat redraws the player controls * @param event */ private function onStageResize(event:Event):Void { redrawControls(); } /** * Toggles pause or play * @param event */ private function onPlayClick(event:MouseEvent):Void { _player.togglePlay(); _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); } /** * Toggles pause or play * @param event */ private function onPauseClick(event:MouseEvent):Void { _player.togglePlay(); _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); } /** * Toggles betewen aspect ratios * @param event */ private function onAspectRatioClick(event:MouseEvent):Void { _player.toggleAspectRatio(); } /** * Toggles between window and fullscreen mode * @param event */ private function onFullscreenClick(event:MouseEvent):Void { _player.toggleFullscreen(); } /** * Toggles between mute and unmute * @param event */ private function onVolumeIconClick(event: MouseEvent):Void { if (_volumeSlider.visible) { _volumeSlider.visible = false; _volumeTrack.visible = false; } else { _volumeSlider.visible = true; _volumeTrack.visible = true; } } /** * Detect user click on volume track control and change volume according * @param event */ private function onVolumeTrackClick(event:MouseEvent):Void { var percent:Float = _volumeTrack.height - _volumeTrack.mouseY; var volume:Float = 1.0 * (percent / _volumeTrack.height); _player.setVolume(volume); } /** * Display not found message * @param event */ private function onPlayerStreamNotFound(event:PlayerEvents):Void { //todo: to work on this } /** * Shows the loader bar when buffering * @param event */ private function onPlayerBuffering(event:PlayerEvents):Void { _loader.show(); } /** * Hides loader bar when not buffering * @param event */ private function onPlayerNotBuffering(event:PlayerEvents):Void { _loader.hide(); } /** * Show the selected aspect ratio * @param event */ private function onPlayerAspectRatio(event:PlayerEvents):Void { _hideAspectRatioLabelTimer.stop(); _aspectRatioLabel.text = _player.getAspectRatioString(); drawAspectRatioLabel(); while (_aspectRatioLabelContainer.visible) { //wait till fade out finishes } Animation.fadeIn(_aspectRatioLabelContainer, 1); _hideAspectRatioLabelTimer.start(); } /** * Monitors playbeack when finishes tu update controls * @param event */ private function onPlayerPlaybackFinished(event:PlayerEvents):Void { _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); showControls(); } /** * Monitors keyboard play pause actions to update icons * @param event */ private function onPlayerPlayPause(event:PlayerEvents):Void { _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); } /** * Resizes the video player on windowed mode substracting the seekbar height * @param event */ private function onPlayerResize(event:PlayerEvents):Void { } /** * Updates media total time duration. * @param event */ private function onPlayerMediaInitialized(event:PlayerEvents):Void { _totalPlayTimeLabel.text = Utils.formatTime(event.duration); _totalPlayTimeLabel.setTextFormat(_textFormat); _playControl.visible = !_player.isPlaying(); _pauseControl.visible = _player.isPlaying(); } /** * Hides seekbar if on fullscreen. * @param event */ private function onPlayerMouseHide(event:PlayerEvents):Void { if (_controlsBar.visible && _player.isFullscreen()) { hideControls(); } } /** * Shows seekbar * @param event */ private function onPlayerMouseShow(event:PlayerEvents):Void { //Only use slidein effect on fullscreen since switching to windowed mode on //hardware scaling causes a bug by a slow response on stage height changes if (_player.isFullscreen() && !_controlsBar.visible) { _controlsBar.visible = true; } else if (!_controlsBar.visible) { _controlsBar.visible = true; } } /** * Translates a user click in to time and seeks to it * @param event */ private function onTrackClick(event:MouseEvent):Void { var clickPosition:Float = _track.mouseX; _player.seek(_player.getDuration() * (clickPosition / _track.width)); } /** * Shows a small tooltip showing the time calculated by mouse position * @param event */ private function onTrackMouseMove(event:MouseEvent):Void { var clickPosition:Float = _track.mouseX; _seekPlayTimeLabel.text = Utils.formatTime(_player.getDuration() * (clickPosition / _track.width)); _seekPlayTimeLabel.setTextFormat(_textFormat); _seekPlayTimeLabel.y = _stage.stageHeight - _seekBar.height - _seekPlayTimeLabel.height - 1; _seekPlayTimeLabel.x = clickPosition + (_seekPlayTimeLabel.width / 2) + (_playControl.width + 10) * 2; _seekPlayTimeLabel.backgroundColor = _darkColor; _seekPlayTimeLabel.background = true; _seekPlayTimeLabel.textColor = _controlColor; _seekPlayTimeLabel.borderColor = _darkColor; _seekPlayTimeLabel.border = true; if (!_seekPlayTimeLabel.visible) { _seekPlayTimeLabel.visible = true; } } /** * Hides the tooltip that shows the time calculated by mouse position * @param event */ private function onTrackMouseOut(event:MouseEvent):Void { _seekPlayTimeLabel.visible = false; } /** * Enables dragging of thumb for seeking media * @param event */ private function onThumbMouseDown(event:MouseEvent):Void { _scrubbing = true; var rectangle:Rectangle = new Rectangle(_track.x, _track.y, _track.width-_thumb.width, 0); _thumb.startDrag(false, rectangle); } /** * Changes thumb seek control to hover color * @param event */ private function onThumbHover(event:MouseEvent):Void { _thumb.graphics.lineStyle(); _thumb.graphics.beginFill(_hoverColor); _thumb.graphics.drawRoundRect(0, (_seekBar.height/2)-(11/2), 11, 11, 10, 10); _thumb.graphics.endFill(); } /** * Changes thumb seek control to control color * @param event */ private function onThumbMouseOut(event:MouseEvent):Void { var matrix:Matrix = new Matrix( ); matrix.createGradientBox(11, 11, Utils.degreesToRadians(-90), 11, 0); var colors:Array = [_controlColor, _controlColor]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; _thumb.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); _thumb.graphics.drawRoundRect(0, (_seekBar.height / 2) - (11 / 2), 11, 11, 10, 10); _thumb.graphics.endFill(); } /** * Disables dragging of thumb * @param event */ private function onThumbMouseUp(event:MouseEvent):Void { _scrubbing = false; _thumb.stopDrag( ); } //} //{Drawing functions /** * Clears all current graphics a draw new ones */ private function redrawControls():Void { drawControls(); drawAspectRatioLabel(); } /** * Draws the download progress track bar */ private function drawDownloadProgress():Void { if (_player.getBytesTotal() > 0) { var bytesLoaded:Float = _player.getBytesLoaded(); var bytesTotal:Float = _player.getBytesTotal(); _percentLoaded = bytesLoaded / bytesTotal; } var position:Float = _player.getStartTime() / _player.getDuration(); var startPosition:Float = (position > 0?(position * _track.width):0) + _track.x; _trackDownloaded.graphics.clear(); _trackDownloaded.graphics.lineStyle(); _trackDownloaded.x = startPosition; _trackDownloaded.graphics.beginFill(_seekColor, 0.5); _trackDownloaded.graphics.drawRoundRect(0, (_seekBar.height / 2) - (5 / 2), ((_track.width + _track.x) - _trackDownloaded.x) * _percentLoaded, 5, 3, 3); _trackDownloaded.graphics.endFill(); } /** * Draws NEW control bar player/seek controls */ private function drawControls():Void { //Reset sprites for redraw _controlsBar.graphics.clear(); _volumeTrack.graphics.clear(); _volumeSlider.graphics.clear(); _volumeSlider.visible = false; _volumeTrack.visible = false; //Reset sprites for redraw _seekBar.graphics.clear(); _track.graphics.clear(); _thumb.graphics.clear(); //Draw controls bar var barMargin = 10; var barWidth = _stage.stageWidth; var barHeight = _controlSize; var barCenter = barWidth / 2; var buttonSize = Std.int(((80 / 100) * (barHeight - (barMargin*2)))); _controlsBar.x = 0; _controlsBar.y = (_stage.stageHeight - barHeight); var matrix:Matrix = new Matrix( ); matrix.createGradientBox(barWidth, barHeight, Utils.degreesToRadians(-90), barWidth, 0); var colors:Array = [_brightColor, _darkColor]; var alphas:Array = [1.0, 1]; var ratios:Array = [0, 255]; _controlsBar.graphics.lineStyle(); _controlsBar.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); _controlsBar.graphics.drawRect(0, 2, barWidth, barHeight-2); _controlsBar.graphics.endFill(); _controlsBar.graphics.beginFill(_darkColor, 1); _controlsBar.graphics.drawRect(0, 0, barWidth, 1); _controlsBar.graphics.endFill(); _controlsBar.graphics.beginFill(_brightColor, 1); _controlsBar.graphics.drawRect(0, 1, barWidth, 1); _controlsBar.graphics.endFill(); //Draw seek bar var _seekBarWidth = barWidth - (buttonSize+barMargin)*3 - (_playControl.x + _playControl.width + barMargin) - barMargin; var _seekBarHeight = barHeight; _seekBar.x = _playControl.x + _playControl.width + barMargin; _seekBar.y = 0; _seekBar.graphics.lineStyle(); _seekBar.graphics.beginFill(_darkColor, 0); _seekBar.graphics.drawRect(0, 0, _seekBarWidth, _seekBarHeight); _seekBar.graphics.endFill(); //Draw playbutton _playControl.setNormalColor(_controlColor); _playControl.setHoverColor(_hoverColor); _playControl.setPosition(barMargin, barMargin); _playControl.setSize(buttonSize+5, buttonSize+5); //Draw pausebutton _pauseControl.setNormalColor(_controlColor); _pauseControl.setHoverColor(_hoverColor); _pauseControl.setPosition(_playControl.x, _playControl.y); _pauseControl.setSize(buttonSize+5, buttonSize+5); //Draw current play time label _textFormat.color = _seekColor; _currentPlayTimeLabel.x = 0; _currentPlayTimeLabel.y = _seekBarHeight - (_seekBarHeight / 2) - (_currentPlayTimeLabel.height / 2); _currentPlayTimeLabel.antiAliasType = AntiAliasType.ADVANCED; _currentPlayTimeLabel.setTextFormat(_textFormat); //Draw total play time label _totalPlayTimeLabel.x = _seekBarWidth - _totalPlayTimeLabel.width; _totalPlayTimeLabel.y = _seekBarHeight - (_seekBarHeight / 2) - (_totalPlayTimeLabel.height / 2); _totalPlayTimeLabel.antiAliasType = AntiAliasType.ADVANCED; _totalPlayTimeLabel.setTextFormat(_textFormat); //Draw download progress drawDownloadProgress(); //Draw track place holder for drag _track.x = _currentPlayTimeLabel.x + _currentPlayTimeLabel.width + barMargin; _track.graphics.lineStyle(); _track.graphics.beginFill(_seekColor, 0); _track.graphics.drawRect(0, (_seekBarHeight / 2) - ((buttonSize+barMargin) / 2), _totalPlayTimeLabel.x - _totalPlayTimeLabel.width - barMargin - barMargin, buttonSize + barMargin); _track.graphics.endFill(); _track.graphics.lineStyle(); _track.graphics.beginFill(_seekColor, 0.3); _track.graphics.drawRoundRect(0, (_seekBarHeight / 2) - (5 / 2), _totalPlayTimeLabel.x - _totalPlayTimeLabel.width - barMargin - barMargin, 5, 3, 3); _track.graphics.endFill(); //Draw thumb var matrix:Matrix = new Matrix( ); matrix.createGradientBox(11, 11, Utils.degreesToRadians(-90), 11, 0); var colors:Array = [_controlColor, _controlColor]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; _thumb.x = _currentPlayTimeLabel.width + _currentPlayTimeLabel.x + barMargin; _thumb.graphics.lineStyle(); _thumb.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); //_thumb.graphics.beginFill(_controlColor); _thumb.graphics.drawRoundRect(0, (_seekBarHeight/2)-(11/2), 11, 11, 10, 10); _thumb.graphics.endFill(); //Draw volume icon _volumeIcon.setNormalColor(_controlColor); _volumeIcon.setHoverColor(_hoverColor); _volumeIcon.setPosition(_seekBar.x + _seekBar.width + barMargin, _playControl.y+1); _volumeIcon.setSize(buttonSize, buttonSize); //Draw aspec ratio button _aspectRatioControl.setNormalColor(_controlColor); _aspectRatioControl.setHoverColor(_hoverColor); _aspectRatioControl.setPosition(_volumeIcon.x + _volumeIcon.width + barMargin, _playControl.y+1); _aspectRatioControl.setSize(buttonSize, buttonSize); //Draw fullscreen button _fullscreenControl.setNormalColor(_controlColor); _fullscreenControl.setHoverColor(_hoverColor); _fullscreenControl.setPosition(_aspectRatioControl.x + _aspectRatioControl.width + barMargin, _playControl.y+1); _fullscreenControl.setSize(buttonSize, buttonSize); //Draw volume track _volumeTrack.x = _controlsBar.width-(buttonSize+barMargin)*3; _volumeTrack.y = -_controlsBar.height-2; _volumeTrack.graphics.lineStyle(1, _controlColor); _volumeTrack.graphics.beginFill(0x000000, 0); _volumeTrack.graphics.drawRect(0, 0, buttonSize, _controlsBar.height); _volumeTrack.graphics.endFill(); //Draw volume slider var matrix:Matrix = new Matrix( ); matrix.createGradientBox(_volumeTrack.width, _volumeTrack.height, Utils.degreesToRadians(-90), _volumeTrack.width, 0); var colors:Array = [_hoverColor, _hoverColor]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; _volumeSlider.x = _volumeTrack.x; _volumeSlider.y = _volumeTrack.y; _volumeSlider.graphics.lineStyle(); _volumeSlider.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); //_volumeSlider.graphics.beginFill(_hoverColor, 1); _volumeSlider.graphics.drawRect(0, 0, _volumeTrack.width, _volumeTrack.height); _volumeSlider.graphics.endFill(); } private function drawAspectRatioLabel():Void { _aspectRatioLabelContainer.graphics.clear(); _aspectRatioLabelContainer.visible = false; //Update aspect ratio label var textFormat:TextFormat = new TextFormat(); textFormat.font = "arial"; textFormat.bold = true; textFormat.size = 40; textFormat.color = _controlColor; _aspectRatioLabel.setTextFormat(textFormat); _aspectRatioLabel.x = (_stage.stageWidth / 2) - (_aspectRatioLabel.width / 2); _aspectRatioLabel.y = (_stage.stageHeight / 2) - (_aspectRatioLabel.height / 2); //Draw aspect ratio label container _aspectRatioLabelContainer.x = _aspectRatioLabel.x - 10; _aspectRatioLabelContainer.y = _aspectRatioLabel.y - 10; _aspectRatioLabelContainer.graphics.lineStyle(0, _darkColor); _aspectRatioLabelContainer.graphics.beginFill(_darkColor, 1); _aspectRatioLabelContainer.graphics.drawRoundRect(0, 0, _aspectRatioLabel.width + 20, _aspectRatioLabel.height + 20, 15, 15); _aspectRatioLabelContainer.graphics.endFill(); _aspectRatioLabel.x = 10; _aspectRatioLabel.y = 10; } //} //{Private Methods /** * Hide the play controls bar */ private function hideControls():Void { if(_controlsBar.visible) { drawControls(); Animation.slideOut(_controlsBar, "bottom", 800); } } /** * Shows play controls bar */ private function showControls():Void { if(!_controlsBar.visible) { drawControls(); _controlsBar.visible = true; } } //} //{Setters /** * Sets the player colors and redraw them * @param colors Array of colors in the following order: darkColor, brightColor, controlColor, hoverColor */ public function setControlColors(colors:Array):Void { _darkColor = colors[0].length > 0? Std.parseInt("0x" + colors[0]) : 0x000000; _brightColor = colors[1].length > 0? Std.parseInt("0x" + colors[1]) : 0x4c4c4c; _controlColor = colors[2].length > 0? Std.parseInt("0x" + colors[2]) : 0xFFFFFF; _hoverColor = colors[3].length > 0? Std.parseInt("0x" + colors[3]) : 0x67A8C1; _seekColor = colors[4].length > 0? Std.parseInt("0x" + colors[4]) : 0x7c7c7c; var loaderColors:Array = ["", ""]; loaderColors[0] = colors[0]; loaderColors[1] = colors[2]; loaderColors[2] = colors[4]; _loader.setColors(loaderColors); redrawControls(); } /** * Sets the player controls size (height) * @param size int: for e.g. 50 */ public function setControlSize(size:Int):Void { if (size == 0) return; _controlSize = size; redrawControls(); } /** * To set the duration label when autostart parameter is false * @param duration in seconds or formatted string in format hh:mm:ss */ public function setDurationLabel(duration:String):Void { //Person passed time already formatted if (duration.indexOf(":") != -1) { _totalPlayTimeLabel.text = duration; } //Time passed in seconds else { _totalPlayTimeLabel.text = Std.string(Utils.formatTime(Std.parseFloat(duration))); } _totalPlayTimeLabel.setTextFormat(_textFormat); } //} } v2.0.17~dfsg/src/jaris/player/newcontrols/FullscreenIcon.hx0000755000000000000000000000735612625374554022610 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.newcontrols; import flash.display.Sprite; import flash.events.MouseEvent; import flash.geom.Matrix; import jaris.utils.Utils; import flash.display.GradientType; class FullscreenIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(0, color, 0.0); graphics.beginFill(color, 0); graphics.drawRect(0, 0, _width, _height); graphics.endFill(); var arrowWidth = Std.int(_width / 2 * 0.8); var matrix:Matrix = new Matrix( ); matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0); var colors:Array = [color, color]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; graphics.lineStyle(0, color, 0, true); graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); //graphics.beginFill(color, 0); graphics.drawRect(0, 0, arrowWidth, 2); graphics.drawRect(0, 2, 2, arrowWidth-2); graphics.drawRect(_width-arrowWidth+1, 0, arrowWidth, 2); graphics.drawRect(_width-1, 2, 2, arrowWidth-2); graphics.drawRect(0, _height-arrowWidth+2, 2, arrowWidth); graphics.drawRect(2, _height, arrowWidth-2, 2); graphics.drawRect(_width-1, _height-arrowWidth+2, 2, arrowWidth-2); graphics.drawRect(_width-arrowWidth+1, _height, arrowWidth, 2); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/newcontrols/Loader.hx0000755000000000000000000001317512625374554021077 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.newcontrols; import flash.display.MovieClip; import flash.display.Sprite; import flash.display.Stage; import flash.events.Event; import flash.Lib; import flash.geom.Matrix; import jaris.utils.Utils; import flash.display.GradientType; /** * Draws a loading bar */ class Loader extends Sprite { private var _stage:Stage; private var _movieClip:MovieClip; private var _background:Sprite; private var _loaderTrack:Sprite; private var _loaderThumb:Sprite; private var _visible:Bool; private var _darkColor:UInt; private var _controlColor:UInt; private var _seekColor:UInt; private var _forward:Bool; public function new() { super(); _stage = Lib.current.stage; _movieClip = Lib.current; _background = new Sprite(); addChild(_background); _loaderTrack = new Sprite(); addChild(_loaderTrack); _loaderThumb = new Sprite(); addChild(_loaderThumb); _darkColor = 0x000000; _controlColor = 0xFFFFFF; _seekColor = 0x747474; _forward = true; _visible = true; addEventListener(Event.ENTER_FRAME, onEnterFrame); _stage.addEventListener(Event.RESIZE, onResize); drawLoader(); } /** * Animation of a thumb moving on the track * @param event */ private function onEnterFrame(event:Event):Void { if (_visible) { if (_forward) { if ((_loaderThumb.x + _loaderThumb.width) >= (_loaderTrack.x + _loaderTrack.width)) { _forward = false; } else { _loaderThumb.x += 10; } } else { if (_loaderThumb.x <= _loaderTrack.x) { _forward = true; } else { _loaderThumb.x -= 10; } } } } /** * Redraws the loader to match new stage size * @param event */ private function onResize(event:Event):Void { drawLoader(); } /** * Draw loader graphics */ private function drawLoader():Void { //Clear graphics _background.graphics.clear(); _loaderTrack.graphics.clear(); _loaderThumb.graphics.clear(); //Draw background var backgroundWidth:Float = (65 / 100) * _stage.stageWidth; var backgroundHeight:Float = 30; _background.x = (_stage.stageWidth / 2) - (backgroundWidth / 2); _background.y = (_stage.stageHeight / 2) - (backgroundHeight / 2); _background.graphics.lineStyle(); _background.graphics.beginFill(_darkColor, 0.75); _background.graphics.drawRoundRect(0, 0, backgroundWidth, backgroundHeight, 6, 6); _background.graphics.endFill(); //Draw track var trackWidth:Float = (50 / 100) * _stage.stageWidth; var trackHeight:Float = 11; _loaderTrack.x = (_stage.stageWidth / 2) - (trackWidth / 2); _loaderTrack.y = (_stage.stageHeight / 2) - (trackHeight / 2); _loaderTrack.graphics.lineStyle(); _loaderTrack.graphics.beginFill(_seekColor, 0.3); _loaderTrack.graphics.drawRoundRect(0, trackHeight/2/2, trackWidth, trackHeight/2, 5, 5); //Draw thumb var matrix:Matrix = new Matrix( ); matrix.createGradientBox(trackHeight*3, trackHeight, Utils.degreesToRadians(-90), trackHeight*3, 0); var colors:Array = [_controlColor, _controlColor]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; _loaderThumb.x = _loaderTrack.x; _loaderThumb.y = _loaderTrack.y; _loaderThumb.graphics.lineStyle(); _loaderThumb.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); //_loaderThumb.graphics.beginFill(_controlColor, 1); _loaderThumb.graphics.drawRoundRect(0, 0, trackHeight*3, trackHeight, 10, 10); } /** * Stops drawing the loader */ public function hide():Void { this.visible = false; _visible = false; } /** * Starts drawing the loader */ public function show():Void { this.visible = true; _visible = true; } /** * Set loader colors * @param colors */ public function setColors(colors:Array):Void { _darkColor = colors[0].length > 0? Std.parseInt("0x" + colors[0]) : 0x000000; _controlColor = colors[1].length > 0? Std.parseInt("0x" + colors[1]) : 0xFFFFFF; _seekColor = colors[2].length > 0? Std.parseInt("0x" + colors[2]) : 0x747474; drawLoader(); } } v2.0.17~dfsg/src/jaris/player/newcontrols/PlayIcon.hx0000755000000000000000000000644412625374554021410 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player.newcontrols; import flash.display.Sprite; import flash.events.MouseEvent; import flash.geom.Matrix; import jaris.utils.Utils; import flash.display.GradientType; class PlayIcon extends Sprite { private var _width:Float; private var _height:Float; private var _normalColor:UInt; private var _hoverColor:UInt; public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt) { super(); this.x = x; this.y = y; this.buttonMode = true; this.useHandCursor = true; this.tabEnabled = false; _width = width; _height = height; _normalColor = normalColor; _hoverColor = hoverColor; addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); draw(_normalColor); } private function onMouseOver(event:MouseEvent):Void { draw(_hoverColor); } private function onMouseOut(event:MouseEvent):Void { draw(_normalColor); } //{Private Methods private function draw(color:UInt):Void { graphics.clear(); graphics.lineStyle(0, color, 0.0); graphics.beginFill(color, 0); graphics.drawRect(0, 0, _width, _height); graphics.endFill(); var matrix:Matrix = new Matrix( ); matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0); var colors:Array = [color, color]; var alphas:Array = [0.75, 1]; var ratios:Array = [0, 255]; graphics.lineStyle(); graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); //graphics.beginFill(color); graphics.lineTo(0, _height); graphics.lineTo(_width, _height / 2); graphics.lineTo(0, 0); graphics.endFill(); } //} //{Setters public function setNormalColor(color:UInt):Void { _normalColor = color; draw(_normalColor); } public function setHoverColor(color:UInt):Void { _hoverColor = color; draw(_hoverColor); } public function setPosition(x:Float, y:Float):Void { this.x = x; this.y = y; draw(_normalColor); } public function setSize(width:Float, height:Float):Void { _width = width; _height = height; draw(_normalColor); } //} } v2.0.17~dfsg/src/jaris/player/InputType.hx0000644000000000000000000000203712625374554017245 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris.player; /** * Stores the identifiers for loaded media type */ class InputType { public static var AUDIO = "audio"; public static var VIDEO = "video"; } v2.0.17~dfsg/src/jaris/Main.hx0000644000000000000000000002007312625374554014674 0ustar rootroot/** * @author Jefferson González * @copyright 2010 Jefferson González * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ package jaris; import flash.display.MovieClip; import flash.display.Stage; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.Lib; import flash.system.Capabilities; import jaris.display.Logo; import jaris.display.Menu; import jaris.display.Poster; import jaris.player.controls.Controls; import jaris.player.newcontrols.NewControls; import jaris.player.JsApi; import jaris.player.InputType; import jaris.player.Player; import jaris.player.StreamType; import jaris.player.AspectRatio; import jaris.player.UserSettings; import jaris.player.Loop; /** * Main jaris player starting point */ class Main { static var stage:Stage; static var movieClip:MovieClip; static function main():Void { //Initialize stage and main movie clip stage = Lib.current.stage; movieClip = Lib.current; stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; //Retrieve user settings var userSettings:UserSettings = new UserSettings(); //Reads flash vars var parameters:Dynamic = flash.Lib.current.loaderInfo.parameters; //Initialize and draw player object var player:Player = new Player(); if (Capabilities.playerType == "PlugIn" || Capabilities.playerType == "ActiveX") { var autoStart:Bool = parameters.autostart == "true" || parameters.autostart == "" || parameters.autostart == null? true: false; var type:String = parameters.type != "" && parameters.type != null? parameters.type : InputType.VIDEO; var streamType:String = parameters.streamtype != "" && parameters.streamtype != null? parameters.streamtype : StreamType.FILE; var server:String = parameters.server != "" && parameters.server != null? parameters.server : ""; var aspectRatio:String = parameters.aspectratio != "" && parameters.aspectratio != null? parameters.aspectratio : ""; var bufferTime:Float = parameters.buffertime != "" && parameters.buffertime != null? Std.parseFloat(parameters.buffertime) : 0; if (aspectRatio != "" && !userSettings.isSet("aspectratio")) { switch(aspectRatio) { case "1:1": player.setAspectRatio(AspectRatio._1_1); case "3:2": player.setAspectRatio(AspectRatio._3_2); case "4:3": player.setAspectRatio(AspectRatio._4_3); case "5:4": player.setAspectRatio(AspectRatio._5_4); case "14:9": player.setAspectRatio(AspectRatio._14_9); case "14:10": player.setAspectRatio(AspectRatio._14_10); case "16:9": player.setAspectRatio(AspectRatio._16_9); case "16:10": player.setAspectRatio(AspectRatio._16_10); } } else if(userSettings.isSet("aspectratio")) { player.setAspectRatio(userSettings.getAspectRatio()); } player.setType(type); player.setStreamType(streamType); player.setServer(server); player.setVolume(userSettings.getVolume()); player.setBufferTime(bufferTime); if (autoStart) { player.load(parameters.source, type, streamType, server); } else { player.setSource(parameters.source); } player.setHardwareScaling(parameters.hardwarescaling=="true"?true:false); } else { //For development purposes if(userSettings.isSet("aspectratio")) { player.setAspectRatio(userSettings.getAspectRatio()); } player.setVolume(userSettings.getVolume()); player.load("http://jaris.sourceforge.net/files/jaris-intro.flv", InputType.VIDEO, StreamType.FILE); //player.load("http://jaris.sourceforge.net/files/audio.mp3", InputType.AUDIO, StreamType.FILE); } //Draw preview image if (parameters.poster != null) { var poster:String = parameters.poster; var posterImage = new Poster(poster); posterImage.setPlayer(player); movieClip.addChild(posterImage); } //Modify Context Menu var menu:Menu = new Menu(player); //Draw logo if (parameters.logo!=null) { var logoSource:String = parameters.logo != null ? parameters.logo : "logo.png"; var logoPosition:String = parameters.logoposition != null ? parameters.logoposition : "top left"; var logoAlpha:Float = parameters.logoalpha != null ? Std.parseFloat(parameters.logoalpha) / 100 : 0.3; var logoWidth:Float = parameters.logowidth != null ? Std.parseFloat(parameters.logowidth) : 130; var logoLink:String = parameters.logolink != null ? parameters.logolink : "http://jaris.sourceforge.net"; var logo:Logo = new Logo(logoSource, logoPosition, logoAlpha, logoWidth); logo.setLink(logoLink); movieClip.addChild(logo); } //Draw Controls if (parameters.controls != "false") { var duration:String = parameters.duration != "" && parameters.duration != null? parameters.duration : "0"; var controlType:Int = parameters.controltype != "" && parameters.controltype != null? Std.parseInt(parameters.controltype) : 0; var controlSize:Int = parameters.controlsize != "" && parameters.controlsize != null? Std.parseInt(parameters.controlsize) : 0; var controlColors:Array = ["", "", "", "", ""]; controlColors[0] = parameters.darkcolor != null ? parameters.darkcolor : ""; controlColors[1] = parameters.brightcolor != null ? parameters.brightcolor : ""; controlColors[2] = parameters.controlcolor != null ? parameters.controlcolor : ""; controlColors[3] = parameters.hovercolor != null ? parameters.hovercolor : ""; controlColors[4] = parameters.seekcolor != null ? parameters.seekcolor : ""; if (controlType == 1) { var controls:NewControls = new NewControls(player); controls.setDurationLabel(duration); controls.setControlColors(controlColors); controls.setControlSize(controlSize); movieClip.addChild(controls); } else { var controls:Controls = new Controls(player); controls.setDurationLabel(duration); controls.setControlColors(controlColors); movieClip.addChild(controls); } } //Loop the video if (parameters.loop != null) { var loop:Loop = new Loop(player); } //Expose events to javascript functions and enable controlling the player from the outside if (parameters.jsapi != null) { var jsAPI:JsApi = new JsApi(player); movieClip.addChild(jsAPI); } } } v2.0.17~dfsg/changes.txt0000644000000000000000000001150612625374554013722 0ustar rootrootJaris FLV Player v2.0.17 - 22/11/2015 * Disabled second parameter when calling play() on a rtmp source. * Disabled rtmpSourceParser() because it is causing issues. * Added rtmp notes to documentation.txt * fix new control do not autohide bug thanks to Michelangelo * fix new control vertical check thanks to Michelangelo Jaris FLV Player v2.0.16 - 11/09/2014 * Fixes in order to compile with new haxe v3 thanks to jonassmedegaard * Fix the AsyncErrorEvent exception thrown by player thanks to lcb931023 * Added loadVideo() JsAPI call, call from JS new video thanks to Spiritdude * Added build.hxml Jaris FLV Player v2.0.15 beta - 27/08/2011 * New player controls * New flashvar controltype (0=old, 1=new) to indicate the which controls to use * New flashvar controlsize for new controls only * New flashvar seekcolor for new controls only * New flashvar buffertime to change the default 10 seconds buffer time for local/pseudo streaming * Bugfix on loader bar * All this changes thanks to Istvan Petres from http://jcore.net Jaris FLV Player v2.0.14 beta - 20/05/2011 * Removed some trace calls on youtube playback. Jaris FLV Player v2.0.13 beta - 6/03/2011 * Implemented loop class * Added loop functionality by passing loop=true or loop=1 as parameter * Fixed reported bug "slider will show wrong position" on pseudostreaming seek (Thanks to Adam) Jaris FLV Player v2.0.12 beta - 06/11/2010 * Java Script Api to listen for events and control the player. * More player events added to use on JSApi. * All this changes thanks to Sascha Kluger from http://projekktor.com Jaris FLV Player v2.0.11 beta - 03/10/2010 * Removed togglePlay of onFullscreen event since it seems that new flash versions doesnt emits the space keydown anymore that affected playback on fullcreen switching. * Added class to store user settings as volume and aspect ratio to load them next time player is load. Jaris FLV Player v2.0.10 beta - 29/09/2010 * Added flashvar aspectratio option to initially tell on wich aspect ratio to play the video Jaris FLV Player v2.0.9 beta - 26/05/2010 * Improved poster to keep aspect ratio and display back when playback finishes Jaris FLV Player v2.0.8 beta - 14/05/2010 * Fixed bug on formatTime function calculating hours as minutes Jaris FLV Player v2.0.7 beta - 03/19/2010 * Fixed youtube security bug Jaris FLV Player v2.0.6 beta - 03/13/2010 * Added: display current aspect ratio label on aspect ratio toggle * Improved readability of text * only attach netstream to video object if input type is video * remove poster from player code Jaris FLV Player v2.0.5 beta - 03/12/2010 * Improved aspect ratio toogle when video aspect ratio is already on the aspect ratios list * Fixed context menu aspect ratio rotation Jaris FLV Player v2.0.4 beta - 03/11/2010 * Fixed a drawing issue where seek bar after fullscreen stayed long * Documented other parts of the code Jaris FLV Player v2.0.3 beta - 03/10/2010 * Support for rtmp streaming * support for youtube * better support for http streaming like lighttpd * Fixed calculation of width on original aspect ratio larger than stage * And many hours of improvements Jaris FLV Player v2.0.2 beta - 03/09/2010 * Implement EventDispatcher on Player class instead of using custom event mechanism * Fixed not getting initial stage widht and height on IE when using swfobjects * Some more improvements to controls on short heights * Other improvements and code refactoring * added id3 info to player events Jaris FLV Player v2.0.1 beta - 03/08/2010 * Toggle Quality on Context Menu * Introduction of type parameter * Initial mp3 support * Loader fixes * Controls fixes * Other refinements and fixes * Duration parameter to indicate how much total time takes input media Jaris FLV Player v2.0.0 beta - 03/05/2010 * Moved from swishmax 2 to haxe and flashdevelop * New GUI completely written in haxe (AS3) * Hide controls on fullscreen * Recalculate aspect ratio on fullscreen. * Redraw controls on fullscreen and normal switching. * Initial pseudo streaming support * Compiled to flash 10 * Now uses as3 libraries * Optional Hardware scaling * Video smoothing enabled by default * Added custom context menu * Other refinements and fixes Jaris FLV Player v1.0 - 05/21/2008 * Calculates video aspect ratio on player load. * Support Flash 9 Stage.displayState (Fullscreen mode). * Support for preview image of the video. * Display buffering message. * Internal volume control. * Back and forward control. * Display the actual playing time and total time. * Support for logo image on the fly. * Flag to autostart the video on player load. v2.0.17~dfsg/README.md0000644000000000000000000000327512625374554013034 0ustar rootroot#Jaris FLV Player A flash flv/mp4 player made using haxe and flash develop that can be embedded into any website for free or commercial use. With support for rtmp, youtube, http streaming and many more features. Open for improvements by you! Web Page: http://jarisflvplayer.org/ Project Page: https://sourceforge.net/projects/jaris/ ##Be Free! Searching for an flv player that could be used freely in all aspects and open source was a hard job. So I just decided to work on a basic player that had the most important features found in others players. Thats the story of how Jaris was born. ##Features * Aspect ratio switcher * Fullscreen support * Http pseudostreaming support * Basic RTMP streaming support * Poster image * Volume control * Seek control * Display time * Use your own logo * Add a link to your logo * Change position of logo * Hide controls on fullscreen * Custom control colors * Hardware scaling * Keyboard shortcuts * Mp3 support ##License Jaris is licensed under GPL and LGPL, meaning that you could use it commercially. What we ask for is that any improvements made to the player should be taken back to jaris flv website so that any one could enjoy the new improvements or features also. In this way everyone could help to maintain an up to date tool that adapts to todays multimedia demands. Using github you can fork the project, work on your changes, and send a pull request. Enjoy a totally free player ;-) ##Compiling from source Install [haxe](http://haxe.org/) change to the directory where jaris sources reside and run: haxe build.xml JarisFLVPlayer.swf will be generated on the **bin** directory which you can embed in your web sites as integrate as part of other projects. v2.0.17~dfsg/bin/0000755000000000000000000000000012626407204012304 5ustar rootrootv2.0.17~dfsg/bin/js/0000755000000000000000000000000012626407204012720 5ustar rootrootv2.0.17~dfsg/bin/js/jarisflvplayer.js0000644000000000000000000000640212625374554016327 0ustar rootroot/** * @author Jefferson Gonzalez * @copyright 2010 Jefferson Gonzalez * * @license * This file is part of Jaris FLV Player. * * Jaris FLV Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License or GNU LESSER GENERAL * PUBLIC LICENSE as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * Jaris FLV Player 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 and * GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not, * see . */ /** *Interface for the JarisFLVPlayer JavaScript API implemented *by Sascha from http://projekktor.com/ *@param id The id of the flash object */ function JarisFLVPlayer(id){ this.playerId = id; //Stores the id of the player this.player = null; //Object that points to the player } //Event constants JarisFLVPlayer.event = { MOUSE_HIDE: "onMouseHide", MOUSE_SHOW: "onMouseShow", MEDIA_INITIALIZED: "onDataInitialized", BUFFERING: "onBuffering", NOT_BUFFERING: "onNotBuffering", RESIZE: "onResize", PLAY_PAUSE: "onPlayPause", PLAYBACK_FINISHED: "onPlaybackFinished", CONNECTION_FAILED: "onConnectionFailed", ASPECT_RATIO: "onAspectRatio", VOLUME_UP: "onVolumeUp", VOLUME_DOWN: "onVolumeDown", VOLUME_CHANGE: "onVolumeChange", MUTE: "onMute", TIME: "onTimeUpdate", PROGRESS: "onProgress", SEEK: "onSeek", ON_ALL: "on*" }; JarisFLVPlayer.prototype.isBuffering = function(){ this.setPlayer(); return this.player.api_get("isBuffering"); } JarisFLVPlayer.prototype.isPlaying = function(){ this.setPlayer(); return this.player.api_get("isPlaying"); } JarisFLVPlayer.prototype.getCurrentTime = function(){ this.setPlayer(); return this.player.api_get("time"); } JarisFLVPlayer.prototype.getBytesLoaded = function(){ this.setPlayer(); return this.player.api_get("loaded"); } JarisFLVPlayer.prototype.getVolume = function(){ this.setPlayer(); return this.player.api_get("volume"); } JarisFLVPlayer.prototype.addListener = function(event, listener){ this.setPlayer(); this.player.api_addlistener(event, listener); } JarisFLVPlayer.prototype.removeListener = function(event){ this.setPlayer(); this.player.api_removelistener(event); } JarisFLVPlayer.prototype.play = function(){ this.setPlayer(); this.player.api_play(); } JarisFLVPlayer.prototype.pause = function(){ this.setPlayer(); this.player.api_pause(); } JarisFLVPlayer.prototype.seek = function(seconds){ this.setPlayer(); this.player.api_seek(seconds); } JarisFLVPlayer.prototype.volume = function(value){ this.setPlayer(); this.player.api_volume(value); } JarisFLVPlayer.prototype.loadVideo = function(url,type,streamType,server){ this.setPlayer(); this.player.api_loadVideo(url,type,streamType,server); } JarisFLVPlayer.prototype.setPlayer = function(){ this.player = document.getElementById(this.playerId); } v2.0.17~dfsg/bin/poster.png0000644000000000000000000025604112625374554014350 0ustar rootrootPNG  IHDR J"/sRGBbKGD pHYs  tIME-/ IDATx]wJҬUd>77g۽m*3 A}YE9-$@T 3+qI(+^5=?WYkWTvf"AA4{ݛEI$M#.;FnߛfQ@I$IE5AZjSթva&@?$YX Z-OEyZ%I$I KD3D1Z1#Fo(jS-`h$D R;I$IXJ BncJ'1g[Ƒ+$4$I$AJ-6U+D1veFIEWTkq(3AFJb25$I$"X9 z i"l B٫{m I`/~! yN%I$I Kq2BSHҶ4'!,k)i,-PƐa$I$I.W`A@,>XZC=!hWثQ%HGYXI$IҴ$ ɛ7ܛkd!)&Cњ/.EO%I$I2UCŗ-jMB.SB5b*"(P|h7lX\zV$I$ V=a7Kn g;<h#EO= SCA1I$I[-$`,~h\=uEDЗ>؊ ?a9peu{$I$.HXac 47?\P9!_C0-f-39\K%#&I$IrKRU mA[t7A7nhK̡BйSowWci`HA1BW[biX8̱uXtfy QJ$ID'w!᮶h}xU|o ŊDC9,ݍ!dU={ K\hi>~|h?q3ǡt9!0K$I$&w-MK2k> js+ŌdžDPzW OqpZR0lָ,:|^_ߴXsV*PD$I|HeRyul'AVj 0Y +QH@DzӺ5EV DZ8,,o7}ۍc0gAjXI$ID$Z$ S)@j)$Y7[҉n#3FٖGEW~߾-ƿķ[0;=A#U$I$*RD,R T@I-܌h.օR ͱ?f}|cW;,Bd4C7IKwEk_$IR`NifR@э=# (@ ?J.w.Kq7}ow&}|hM_XwFOSOI$穗"y6cxb׎eUE-A@s9n8ƿ?oѴn~/7?4,KArx;|XZ~Vl39I $D,%gA(̳ؕk}\M; ïK B-G %7?oD*[~8?OgɲUI\ $3C ~RY[[U,]_/>&y@)T G[_c9ˡXtX|᪗Xk5V;s`$c_Ɉ0324kȊks~ⓡ7*H M Bˬy,~piH@@vJ9G$D?*IX#9 jcihj©VtvQ#CxP}X/q/dNɯ)/>{AVIC!I&Gsc*3e$'Xv1cqNn9Y.ǹw[MKb9mkkȖVxNϝO ?=g̹𩮒;%]]RK)h43Xnwã[qzZ%EZGm{ =oP$).ypcZSɋ}NɻVJA3+F+Ŧ]N )NݵRFyX!kݎ>,qm$I>>ᕎ\_dq9:~+?>w#9Zn}d2Y)ԝ,fhԩdVHm/W+J×Yrhh2GkXU%Odl~k: ;"$I Vl"AQУ7U޳*2;ǩC)>fPU\*j+ӎegZ^Iq;yC-ͦ/Mޭq6nõ=uU,t8[]cM xΧg/;2Npu9^^4*x-ONsqD^sn UWьZk\_۱ԺR2jt]J=hAB86/殫|>2|D[K R$"ݺ'W۷!ⶆz0w$IO. F^?Y`H>KYtQcfV uWiM?85ȺBbf 7½)nY! ?bG-HwxnRLNED 4cH%I⯋.*04AfB\(^w$Ir1m'(I#k)uRNW__X&W,JE) tkǾYzyq(e5Zۅ+Z[+Cij^ Q @tC3P2W]AYa@IFKpk zPi^($c֣Ǟ{o%rē?^Њԩԫ+lWפYƓ~gnfa@ݗ{_8UυVj2P$ 2df(']m띵:h _0W0M8d>I?F`-Kx({eՇ3 L_x.c ӴӮzR]BjGwтϿFB:1+pjiMVj"Xf+0V``]T=dE )oAY|8;$"xKfg=!kt}mƙGyOOozFԹ+ZJݕi:J݁UYVIK3i-J8dʫM]]ٲ7vU^`F@0`iX 2:6nDP64Wƥ}>,ګ0I xՙvxUz9ɝQz^w|"h(cdUH(+{W YCFփyȗ3ﴌiH5e4Y$VY)e*deTK۵M Ws N&Vv+&Iŀ᫷(D/n ,H@",IL<)?u}|O=  kK)h0AB`\C4`)u?Bo3ND!P0)8QBtVa: Ƹ<=aX!"$IQ&v펣ocI|^uJ}\GZ4Lnb{;)g _?ɫ-BÄ[rJRh4+4[T㉷`(1?Y^hYRXHZH\ *D (( F ['̢hQ7bPA!aMI$gX=[uF5SםOEɾ=4Q0XZ2` h4 &X‡K z !P4(FhAֲ$IO)"%P Kֻ,@ 5L8vIxC"iif]ҕZ5/BYP&VV 1"X2@y\ T} +&QV, D/ފ"CI|n-MHW7'~V[U2{i<XaW_7ץbVk8r2bk"-}X-"h E}=-Hc KV+/IkfG%@0~mo;J-EE=Z[>FRzgA"""zEVZ0q$]WFp.ѭHmXm[$.ּwNՕ$oԍE^꽎*g[L!nlEIå0,6|Q#(3\Tj2ь\ѱLϠ$ɯX7R{y[܊"'V3tΝdߎ !ԇB!!Ȓ{ኞՄYYFZk=ژG!O$IR`%IrlGrrא[{CC)K祰Ь 19L;6~#rS؍kj(-+fPL04AzShSx_-xQ^$gX$9'FqzˊF YOSGk,͗YPr+0A hxkr˪Ϻ#a*6H0o(;z|iz*j^:I ›y/Nw›ٴVHPDw:HQΟQo@4XnnԚGX+ V6a2l Y/.ȮB1L'$Sֹݺ~t!A%I֋Yaʲ-q煟Пngz7\a}b/].oD _H#Mzm)cS-7@4Hrwo͗%Z>3Z o3 Q`8%ӱVS! GRAhH[Bx$IO&^%6GOu}|6Y$u.8TUyq[_Fe/VtjgaEwH 5__f}n⾴P(Ђ Ax@4$W=GOBHA8(ʅ cc8+ V$IO.r~>K>.=BG6OED4 VgX6χXRTH>Z=Sz/;'"㻃/jMDr3nvima%(1bH*zT d@KTֵ'I+I-$5E32׳/[X$Ej-<-;+MW> Sz5 w(mŲļ_?;;~P=5xU_H#`+ 7,X!T@IFv7-D"H$!"$IXIgEզ kibnorPX$9zݷdժ/s9}J9Xc1[@'( ,͏viKu`cQ4WRDa MM!5tĈ c{$IR`rèwZJ_Z6s;hn. BԻzo!-F֓m@f0mM#F%>nc%IKO D&.wUzl]'3㺠ݚWe}4 һRx4 R"h¡fӕ|Z8, !_w->)"{[њsrыͳE/Ao(8H%4 G1Z@ 'X$y&I颤65g'}TQ3Zc $h]V[%kBq"HeO!L,v@GBa쮯իiC*N@] IDATH{J/"|im<{[?c|oޖĊf$T7UC>I 67# BqE\Ý W-{ !K$k#%jTWIiwc5 SP6T$zwiffٺffE#p!(9{tO.ҝҍFV#-J;-ZkfLC.ek #-G,hs[f&oZD; /]G5 (T V6tF+Q}!kA3D(&IV_Wg ϙ)Y~֦%ޣk̻~.v?&=3}>a=#/Sz;@al>!Rʦ+ 0M}B'BTVQ$ =4(,}PåhFDVvhHh.@守h˲̾Wo}Y>7+ D/kV2` &ա"bǞJb e@3* IO.Uμ_ܣϑks1)u3Dh[:pղţ:>bs.voLZ (z=ǮF{%H ff 0+@mHⳭŒ$I.R`4>@$j9W[?ifb{q|0 4CG=LcQoN7uxONJ.4h$--33c)Ye['BM"Ӏ``qwYGP/aJr]n&wW,%@+DkK7;Psȗv7~eg>}iw_W]DDP$@1AC/o{ڸ6*TX:m`_Hrt\]a2̕$ɥ ,=Psqn:\Ojݶ[X_U$Iiֹyè`k)ޫ0Jb3Vj)֩VS${=#0>9[Dbbֺ{{u(p}f]!$%  DjWyUs) j]5Q6n϶U?[J~7 j(2ٱ6wt}&>%6_=Y$Iz<-I.<Ϊ+{X wibfnl^USW*ZJ)Ee}yas/W/lJ$ZAp+2 R"2 10!"I'_<<ǭB`4icIVOӗNܼ9oI od5C/ <9wDJLdU[C+Hu`DbhNإI+d/ޫSl&Ii"-J1)Ө{0I2Mr>˓;X_^b o^*AH(!-QrmόS::bEOzsFi$I"XoLsO3soug_+ ze$F #bVX+|w9]Aad#ur$DWJO$k?SoZs"n)1%'r.X©_#L]_;˗ )5K$I $lzcZ(5w̢["ݕJ2殓w Gz?BFҥ|$IM`e9EGy?{~Z}ҷmQM hᅰ #l 'pݵ]{4 A.:*閰ՈaP~s[s>?/_5h^$yOuh_E%72Fhi
QS>~b d!!Kۓ$IR`%IaJXm&giۚ*9~$IѷUYCbl՟IJ>\F99LQԗ862%tҨZ7mq-h?!NY\Vi|7}R$Wu ;)D" IIq> ~E=ԭˎGmo#ȠOrfcWѮYM/(P52jm(B{|Rt_a (uG9J۳S+c7<Hu$,=\稜3n=g>u I`Om}4ׁA!n ΫbLuTpW=0'9;sҭcS=ҾgkI$.j [AM&r[˵ӌ@$ڝ_9R|J8*D&I֯L fSyQ7GDG8,E6I y~M]{oc{W3K$Ir+/L|o-rk$IaVʩ]śA$I $I$IXI$I$)$I$IR`%I$I$)$I$IR`%I$I|Vrzһ,ם(#r['~o;C*1JͤOOwͨ<two$ItoZ&nDtH홥q-ݹ~Ẓ dXWho|?v1%!oӡ\lj{Ny@ؐNnomir['_S3:n}q"o:IwXcSE%dk$_7r\?Jg^56rkMw"'~WN<&$&nv[\$W*y0y?04<:ۑEP?_.7ɇ伿͇oTN$ykuuz['8|/=_=n4eW}^a4 7)^vg_A{Tf?ȕ#v|yk;[>LI\z mo ]vra{i(cOݚm7Y*^} o4x?CAy#{E|K$"S1P9o&t_!xkƺ耞5үPtowt]ܽ$XI/8]{95f  iI—yNjv5!IX9ԏ$WϽLe1W$ɧ ܓ}EJ$IXɳJŇ:(9I$tSЇ"27 fq,~}  t M YU'vg#un |yϵr_$I>!87=);8ŧH&IJQWv"rnN$IQ]%ګM$I &#XɻH D%I$):`}m)O$IR`%'Foqn^]oMUޢON*$I.X`%,gws/9L/k}ΦI|$GFE%P$40I>8Y!$I>X)d'[$gSG^wx/93|yXߗ^,EI1WZz_{$I.L`ޅX~n5#g=?{Eѯg2$Ʌ Ou_7uW'W`C$I$W`].* 'zROX.'I$o6 %I$oDU䙈g|dW%I$I 椺H$IR%&_&TxAǚ׶Ѓ;_X$%=8 %<$t}YOsQsO3;\%%I?T`oP'-s}.ֲ+cz#M{=I$J#'턴S:%B+I$(d+z R`%I|4t39_.~$r/'hPm?S'I+ɻj<ϖew^=r $V\Gdnӻ/I$_`E0I -T}_U<_`gգ/dX]l䁣%O,!өn^[$V:Y/j\g A) t=%@Bb͈nN$IXI|\¥sK(&t%!b"TZ]5A4]{p+I sNT'zJ1mS6V?}Vxo)nDH"|aB 4j) AVa/{otj;:Axϱ]B=VSIrceYf\&G0KOz >T IDATg EXJqGVZiutlGV.NQiuRi :rk_OhfA܃YṄCOr8>OMOOJɺS B`mpVZiXr`IքqxB*KH0X~wz[??0ɔl (rOsgμ؇?2XTCA XJ+%tmGV.cglJ8:j^x}~^8rؒ _bS|!!Hh0=?~5L4+8еJ+V.OeU(b{k^J2&"@͌􌺘)$ǒK@Qylj'Ϟ|$X C|lQV+ʳX6|5[jC*VZ0evT"L^׿MoxbaF@x)T )ИI#3 ;~]w>/|S$@a-T ZiVm2iWa,3iVvW&/”*aA ᵷv[wϞ-:Ms 3BV 032HnfڿߡW~򓟮@<ɂh4.+VZiVzHj\<$f.4l!V+OdBq+t[ZX`N%hR , Nr8ѽAY 3P젒(;~Í_}X bϚ1VZi9 I f #?dY0cb^`qX^, w莻w"HsPdP߼ݏ|c<0B`FI6`| `%,0{駾G;\ fFMpF5-jVZ٪X:eSESf,nJ+EXWz /k^*$YJ `aa:rűwz:5DVxˆ$%aCu;^+y ݽvoVZ u6;uBBe`D0hyնup<<;{p:Tiv9Ѱ7 ;nYnm{tpoMo\}Zo-֡= Þ *j_SRPGO ѥ-)h{`=lYr <\zvg8$\ff-$ 1I*ҪPX`7q[^z uU"$CHF(Ov%7 ;C ]?];/b뛔݋:|] Ҟz5?S^XnEa*чh`R\i1A{ɵ5Vb,^jswUp&0LrK`C`Pqp;wOԯw/U+4~ E;~^IT<;/IR>bR[Y^"{^`" +ǠIҢΦzWjLaK!p7v91Z/r9!k,0i;N.D ઄Xx<o5w ?t}_yp{`9AU1%ѹ!7C t+`ZGfkt]6M%]ц ޮV`MOɽ)B`aE@Y.PŰvD$cJigpZoUs=H.ezos'X|}w5m+ȝu1Ͱ6&<4bT*ot:SsS&V YFO&(N=>xͷqzPXN:)):@Qngl"Xp+z 'Cݽ66 k'wxoeTX@r1,ET', c !CIc;Aֵ1&V)1n%y{VUO޲a;>wЍZap+:; :(,w T1"KFt*}/y8-@1N9Meb+ɅO 2'V렺LJc,4Mלȝ:䌒p\بbEN2,2`i\TY`ENID5+Q@nVAly9>ΖhK\/>LJM r.BG}-e K19.'t & q;& gQ>moo=sf%;ݛ8kOt58/z=GN RYdf0JLjԍ24Q'ò\CV]1noeg/3e))CYg:A$AyMl^jQkB\(k~\L7F 61/ZeC:]X뚅 \ɵI'HiPַٿ{~+k:dX*YݷtJBH w?W7)/gn]oSč{m?XZ  9R=Ex20k;Oj<6[]qVrg!ʕ B;t;yvLʠus֧ (WY D9Ӱt:'UGؙT  Nhl˵}\6+ƗެSܝgfwk\HzyU ,kQT+;EYYZN:!eM5lbןy]MnU4RRFdi.ݺ\EW\|krZN Rz^yLѝ7jX6Y`bwfe TW3n 1tIun9Hݪ:S_:3?˳Ǯ~^˺cU!-UCgQ1U~0Ӹ#t;;J+`iXC(HyenTL˷b%ko%<&y);sToP#aLZ $<9Iy‡E8a(?}{Ô@ovfiRi7n+_]XZCP~"QNǢ^S%^'ȫVkPvY,hq76g+4ʹ@fDC(SJ!O? b Z*r{9E& dwPv%˟^t[̬XP`qtW" (3v֢eGmv)KWk=6sPJ^`E2P e>i=!r|*;ыk{lP͙/1F|"m=8Xd]qvkn/[$<Ғ AGw~-:n .OPp&G.14)Kezms 1ya 0[zql"OA4Q͌ż%:Ηy69oig{ouܗ+kק R#{1[_;cǹ[3Pn^%1 +0!iĉa7Ȱ{Hf58kcTJ|F]k> lCm-}+9Oğog&n0\K{fwEt8 fFܙS'6(BJ!R(jr?$!e7/>n+f2El2|O?dE-@yvjoR˜\_żiƉ^a[6U1ύ>eƭ<׶Ż}O];J[V&#ɷm><{̊e^ݲ1%MTN-YnRCf[nZ46v/sjnr;;~:#BfÏ]+1C0swA 's 9pP.%/}G , a _ yʯ3  =ec]XVfpH6vr/;l/b%'gy0t;EB LJ[^{Me)KB?{yI33hrB=9PPzDLi>#|n=| e:bEƆ$+{ 'm~IB3Y,>oVZi2Xksn)SSST"+ L{g~6/jV.%ɱu b棏>gnhzu3H*uo{?O>;} YTUpZFhbT 0wN/ʮ.`)۬{ZiV BV4h Uuወ-jX_qc{etփ%$tpKBC_N:o +Ad(*\.,?] CʉjJ+ZcD֌e4 aT,&]LD뭴rNIuC}o;Gh>n+1R81co/{[ݝEn!$(zݟ_PXp¸h+J+`K2c0&NYBu$n+uCBw7; H!`r_Sg7c^" ^դu@0e7x/OEinHaPۊVZie F+B(hьBn4(TZՅ[%a&\Vv]w]$Bf2t{ݩB`#ҜN@AF+J!3C׿ؕq`eOsN%8/|wmS^r TD bSHT86艱k>e+Vr%ŷoY71zd*VuGWrLӀRb1_# [}Jg_c+-B\~mmIjVzKT7T°*a?w*>Ut{)%H3 wuW Db΂,I8c?#`W- j̽iJ]fC,rͮ VLV^b;F8OUK.0raSҠ_aJ1+6R\3+VC84YH5;e ϴ*Sm}GcI=TsP)a/>6;] 5]R` `"EǤtDDz?cP(ӾG*hd23蒣lKgQqr [R$&G[1M0y{=޼lb5~.֭ZLmNY @LsA MHyo,٩k9v7x׾պ?~Ͽ,,5a=ej!ɇt3'"d!Ue~S"^X?/PN@'p]9BRLO)?mΖ7e֜j s`* FV';@BA!{$8-Lr6FX_R0y1D)nm~z۱vZ:w΋3^K%0:'ђ'1J Hmͦ MLve>͉t^r{s,Yoi_/>2eEz?z;]ox]~/}ɠF=Lb)@?|/OGXʺg<zK 2P Xwmv`T3, VQn-s$*8@ ))U2Mk'\)ϐ23L HSID'dTP &Wlp$"HB H3CnNnpj\ ںhikum ֬gIɑ]%ĭ2xrBIL H7Ìl8-](~KWKwOm@~b舉k.,C,"q>{u-N(eFi\xˏNjv{j6j7H(\ѽ}Hֵo GS7X,CMM# \r,+2 <}a09Ξ+oYr'R . sgj^QNA;k@s8D0%@Tt.&OvǪ=aZ3`Gu|B[XF{\{Lc]Q`Ԅ$%bRUX+F9@WQ\wy2L1ɛh& vgɌpݳg}Q }뙂#cfuYeΘm{@r6\mk%*0v ?vM_y ONW^ }ks?Q}C_ңA]JWW uL鼸lw3H-$n}9k"##Ղ]XjV.+FkZvo(9 IDATݪgQ\+cU!ݚKrmFVym1!<ya 3\}4mL 'O>կHjC9xо9`PBg:s6ŕQڞ?lg)NŴ5DF+:FҫKO--/q{L'BttpaH-y\,ݡhfpDA*i)%-²M5!A"Bp1]b¤4R!`:0Bgz߱~g5?G?v;#f`PH,2E]v'ip^(kTD.@.~)RRUr2kl8r{usҁ6s9 Cӂь0BTݙ}Gn94k y$]Rf !-aRR|2ә[<ɏ2dPh"K+;Š,ܮq1Xp¤Աj_kn n=~k?:% ᑢ<ՠQ q ̣JݓKV4;;$@%1cmI"tUw[[,;%nXϛcE igaE8O-)=Ӎ-y5~5S';~ėo;UTPH6+s ^hHčrv ]aeuN@\!:Nuɱc&v=E `&0o `:j 6HC&&K2X.04l2%8&T8gF&S 2ۮy^{Jv:CKqtA'"*r2jc˵̮0f;ń f+oR}Ӈ5MqaX zAùxdcO-,o>57:S f "MVgQ`~v{v8~P09|#3pg-b)`/rn~]}oS##N$]lD;;p""Rlu`+vIV.Rګaá?)A7e|IؾV.E̚>%NrGg@FJci%ӚzjؚF2L~),sVvڱFe;.9Cxx>2^|ËlCiUy"C8,Hw5u'R!#?H`R)tqL 'V{K'?_8yJ_|̩9R ѧӝ+m 7$nƥ@̊!$J\0"]*0åWgo~޻;ӱ†@V?~ﭺW=Աm>v$,BeINmmy8 fAU؏* PNHOhVvًwC@r\N!*q6P&GCBN`jQ;,\q߹Q=]LaРST]q}y5O"I⛨*0)AIR#&?bCFp S{7O//=c'pn{Qq, 'lh!ɣ%vܝ4HkWQNS&qx!TDFgPOqN?8|\3YU۫o鞕ϕ/Ї#?c˾၎ v$Ba"D~onKp2&%R=7_-,g*N[oVZL{mcwNBӭYbnԙi0{ +r 0:E搲_Pj O^wo%w^yաWzUY@ep2ɣfB@9R=E Ϻ(zȇ.ѭYW?O~'\- Kg vY( ѲW A &գab6Y`n QpS4C@wPu_[ F3xfW~_S W^5F 18f(cٸIuȹȵy˃v_<+\ZLK"BQГ ;?P{y]ywxf{)3}g~/ꡈj0Wwe&jz`V.]5 0HhQ9=uX tv~4HUb\JCsT=rh*B`sT) CXǻEʖaFnK1`9N}!&ا5I0qdfw|/[#'9Iv,-u܁ӷ(uGO"ͅ0( ,$k2aD!jr RʿB YT%Y;|G>><97hH6fהaɉ=Ʀ29/$vYՏIYwt+v ?c/(#Ӣwd3s=^Kl1QG+Z`@q=Fm2+{q42Gb&NB$ FF~1߫mrYpJ^^̭7˴X,A0Br.frD9*d%c#`iRMamܶKփ{^ĄBL֪c - R J-%ŌFֱo{Ĩ#sZ?޶̹0ذgddUI:0 Nrl1Y=mN4֣0_+N7>85:MR$%7qsy>GXӓPB@ы6!\?|>O ~5=)wF4'* Ʀ5|p\=ep‚ 'UcpZ9WG _vj6;UO~?ržOp0(Rx7O:a :3 2W]Nd6L$pJiX1J.QIYQa }iØ)jNO<\RV؊noͺ׽̠ևc*]Eڌs܈G#.;SyUwzgsB=Vf{]!np䶟Hš2u+&R4ʄHwB%Yhhi.g^p׿x,ᗊ ܀:;ALB ^F2QY G2'#_{9].KءK\pwث;:\ۧ\96y㬫J~i63ި5mۡSTp?Ou/_bO;};@hFM;ISQW&avv Jls]cdֵSvtOJə}TaدsqՈ=&oNڔUW\:7j#rc[1H}$dd&g#|/?RMA;eRLwp3kQ(6GӌK tF %p٨pk@sW6{fIFT¾7̾k_vKt1x:4b{dI"HL8n3tO|O=4jIfE*􉳙{˫V/ 8q_iNښ\F_P)Oz_qLP/zK)CI-ld QAK^L.eiwbcM&f\مJ@J>1kqXUDS3#RX6^'t(sQ_he+P`E!4l^r\ yN;I]m%u6ls'| \BJ̤:Z'Olmt%Ѱ@10L5cj?}K1ߘŮ K$"rWEG;Fy=9LjfY`bǭ7s'~>Ϝ1Վ'0boN՜Qj3mjl75r`4{9um2.Yѓ]2랔+"}a*ݍd[jsy%}܊T@17ue}=e})H$!ˬW9I'$@ug+ }f~k߽Oy}0YBnY9{+̇ #ew\,䀅BCRZ. ŤFyDtn37UϗZ -(C?=Tㆢ  2AcY J): j½&=QNOTw`[;uS5-CvsiQ@[Xg:kybt%E1j).pXɽ-]x ν&0+ЄBˉrQ %-8@LȡDGq'ӫOSGzgy>7{)P[Mw?xj8KOwCCE ξӁ"XHcG떈J:Ba*J3}~߇zcl5ք[`yIqL_c9 ܹՎ`~h1u<'' p98l cK\rs A-i5d:1lƓB 45\@}g<@D:L |KdzƱў䘡uŶ4n.7oq=|UljPppNLda VPF&BMId:db&ň!`u0Sr %f.I+[Xz2M*}Y4ݼyׇ^f^ؙy=цy6cLGY R,ɂ,h`󮌝ssw*)Ԯ"{$="5D>i =Sc2ݢh `Bi=4Ȏ䦾l,Q j)\KyjSZ$3b;)VͳgwŸ4S.U`-EAIM0YqHFp0+{*|𧟞?<K7Tpʽj`(rڈ}T+;2Zx=Mt -04`!4.0S"]oi`E 4f69He ?*() ^B4n2px6Z-hWYfy~߿Pէl6M6q)Ɍ%epF%@1r 7B|7` lNJ!;lӲDD6՜z`U]ө:k_kScWu7E,PUNyVDU}X߂,FOL:V媵"=hY 6BNh  JԜ-h2R:S&ze(d9iXwAh` `d,1ƹ~ȜwS‖uZ(Q,AlrLн=[M7f$*d亳&y9%YI4ƈ7NPV B ꬆakjЂ " ^U]#ƫ- Hynom!^g۠ F SقIh mbHck2Ջ'M, {aAeq$U2hRntCW58r9sVo;$~OI*V A0ޭWړ'>{}ԚƭDKg^c]h`Q7&(9OsS`0j{k]ˡ$2rᇴm-2ي?^{dr$0,L< 1vsR`0 1,B`“_M8pp r,yV%7 IDAT1>p~yW56+-f g'7:`sO] 2 D'сP?۲כ&ߌ&#^X13TU\BTH\]_T U7 nkx;v:ѳ+!8i}ͩnp 6DkM-%5:&pcJA 2"K{wFRQuo- >H;\޶MiLo܂|?VՃ# 3Eiq\xUuk5jR+6V&"q~S͎m"0"d::.D014]L~;Yfh-GjGC;nE_-SC*t@=%!#WěJ tw3'57Փbn0eC@ JRzTDhE]c 79T)HArrVC=QE7\#&)Eӭ,%BddF$ DqQ֝[7ܶnߐv{58 $Q9Xa ._5S@)j*/;ouvGӷ)sׯ.!04wCk}B`3)mO` њ% 浂eh9`ևRG%i(d(Y! )흙뿣fWf_À]Z4@8f5j"KChC[I.l:t-_"C8հK/}ⱏ?yGw&ZRi5g($P*;E~KK_֫?yw(9XLmu v9t4Q& Iv@)eA޲ovsYeHlp&O.2)5$R* !lhK@eM-sB@\QTT,5S&AyyT>:3CwتƄiE}bil$(!0̿j4iMVŅCRF.$)IA !8⒘Ym,HRQHeEdmyEz'F]5Ho=~!GSaST:ב!~DHZRB*VJDRā tyg;ro?n{uSzKN`ɐvΏBd&b(i~6 ^A2q1pPXВ`f=%oRE5.r؇?UЛ͔U K@}ְ\yǎӋ\|YY,פˆpp T*[ ϼ ;?Nb&i)%lAY 7`PF+\U E\C{KH$0-nV2r)loV]\9wgr~⽱$'s7! E=e˽LR%'77SMd_lb/@RDmyi)ƖO^Rl}gy.eJg-B-hH p,ʺNo'73%t9j* ?mE-~+At}+)|aF6]ϭ|4. l ,G;m`x0j#iyo?Fa =˦w|f`KP%&<+\KO(f2S4հ<[ܤo>dqp2YW%ym uPv ÝM㊐k<"T QUJPaG;`A :QH* fk@9"^4(Fߍ|bۭms$!Ԛ5„hP__X[МJUrՙ/^9Ƞ;S38%L% HRP*ZM.MqI:1%c26f'19K1p!p0?Q|]cgvdUڸՊ` 8,)WU(˳w͉xi~K|fَd;OƽӍWi10Ҁ4h"YzB)ñQ,Uu}O'a5&KDZ JE;܏;:!cbc>OffsmJO'07P%IÎ:ؠN6ȵ:e^@JQ]2Iڪ?X񔤛%G8Ĕ`,nwڽt"2E [6Z<62 9LUYײEJf2kRG|ڗmyio&"m?OOXhD4B J e V]4YhEI9ZuEIʨ30otp" !5x֑IR%}eVdA5{U0 TJ,eF"d2V`~>VY ub\WWr `R׭r*- R;Ϣ%7,'4[W"53("*,5>V&B%Mng^tWИ/t5ERN9{:1^3vci% ۀ7R\G! 3sKL)F q7Xs jƘS],}=( ^ڳvQf?m{̌ÐYa8S魟^W;bˢ#Ee UakV](t gw_~a##ًcy @xZ aMÝ`o aBB Q-Sc&UCѮrtebCKDljGA#6^ 2"hn2٨:Z|Uͤ$ W*P@3h3ZK&%G#"hĦ"i*! #} -S0 &rm]`7sT WL)Y] Ƭ"6 q%*ȳ uk;}{y[y{ZMH hHš҈PEDhzLh׶ٽٽ0ZӃ=pÏꯝ5He@8Oݽ_}B aF3MIw[fy "&{;_ziT 㱶0L+P۵Lg)÷$zxtsc=qя]dʮXC@J}?n &CR.t_ޠg&虌ަjf/5(V0amDVe08?ⱍ;ۂXpџۻEJ&v v\W_E@ ]){PWU20X荱=>iE4xKOn7nK%֞ݝ+_"ɛ.@!;*"DGmxÅo}ģX 5&UWnftG%/U dS.F!m9T-{܅%^}"-:F?/NE(4r kBdjr9, N!b# b\fRoCM%2<u+XoѹvtTin=7`F;nZabHQwN|֯||aV$ YK 3 Q䑭=?y_7~qډc]dY`1KH Mԥv )9 Dx$Sͨp?#>]!U/H c˗iZy(ڡ0D$ D8 (E0ԐE]L*zݝEse_;+}d3lNCTv⍥0RѦ.lM%og&?G>J!8ĨN t'>`(d1 bX.x3R C{uvf}GA7.ۍ A[%ЅazCݡq]B %J]4!bF w @k%;y}xs& JU5 /_ P%(-4gw_fj/:WJa@-cw]?-wiсGVCR0 )^[OumulկL,BtX ( _%SjmxY=)5 ԶډG,ImPƒ+-(̛=)gvSVzq@r=Ӻbc Sk*UjUga?I{mc5ZB1>x=Q~aLJUϘs!PwHnUax%9Tp!jJapUa rFAcPRT]Mkxf(Y]ʊ-Aj:U14PaXcE J¬Jv/Eb_X46b2ì3d?¹o=ӻ(5) J+:Bj!Ģ4oUF&L1EWcw};<Dy{@J(!|x*)A&RX+/cR~{X/z>lwIɘ֗ˋ>獓 TJ.LZ}$LR| }l&@4!;Qk~dVuMr?nlԖY,5)r<˥r#pHm}Cg}|TCj9l^l#oeU"'!0&lijRW֛Ia&Eh8}Qz쾽;nye'[klZݬR@_VqJ䜻1BCtu.~<c |IáԭBcdR愄)LɡD+?kӘDH==v[RIK`*Vͅ<|/a"##d*M\6ۖR!9#qa'ݪN;H)L&DPHfe(Ј[O 'mr& ʣzאJAfPK}t|/ϜYxC8\<]¡)Mh/D9)jCEavttʣan s_J`dT`g(axEX#˲yu0/MB,G"#ylo|n~:KBb`J5ұv͜hvj>XU4UP˴ Y1 0 -w-)+*zb f\I4 beaaY{N}=k MRkݥkm|mMdjE0?*XwZ?y @ ""1LWk谾ǵuTXP7, 5H %E5ʡH}Бݛz8Pd6%&5KPi%x@ P z|~إʧᤴΔ [Q^soX=kKf( #\y܋^ⱝ,;aơl\cZ3Sluniwk쏾6nro% O]JT7 [b7wM@IE2s{9y:Jٍ*ֵ>֯+>E- 30\ƕKSYSv>tղY0G^'R }/xf;^4Vghdn jH9n9ϛ4=cm!&XK0XQ S"%7=5>u4@U!,DmFyL:j%JͳacGNx[>z~(s]{/?lCɨd0wNH!oC*h$pW TTFʝn35׎4l%lLd JUQ\~QX; TB !`QF԰)2]2B@2<:Qu궣UlT%i6PLő'{bBsiQih5 Ls;lrzIam .EXDSeOֆ +4*b{=7dpAU;DYogKк;pVӹi̷=^GFx~zrXcUcȁt|/V,Ts$qFR(Jf22YSۙ=o,9nڗu3Ϫh[H(m<.$Am)Blʗu?Hs)uz HNCJwb!Z%<pABiO=>~_/tCt1Iob^*;.Z!ŠEnuttm(8Tوhd5e5a#i,Gլ[en5E*Pm(R%NXnZTN@.ZU3Vfm[3'c&U^p=#r"t-3 -s7_b`"*Tw0D =QTq ͙cܿ4_[;}fF3 W'%hkd9jCf&J m2npEL#40&Y0¬DMnFZfTݹH@W-A1YCd۱f\E\X}m/PZ@B5 >aJuװnmf0đv/y@Ddt.Rg:,AA`L ,myŸ'fƍ$,#r;~b~ڻb8bE5Y%]N-n#Ӕ&7CҘ<2c3T&ʹ{B(: *J.%(ƪWͣ)w`<:n7I:lNBʀXM~5 .U 0dDB("*FF* '=(͕a^ьŠV9/7um+~q:_qBD $愮F{9daIޢ: D=oNlz? ^(e!:{Vu*CY,jk2Aਵ֎׵FCNRORr'מ׮:qgQիJ,v^O,W}9m.Z+"hcDp1^nt/ 0 "MJ/J}N4@][;-8ʝZԄͤ{Ṅ0 -#|WDCvh93$Gb "`Y2V3$CN0 >iʆwyc&C/8~i^Y 9ji?Ɉ8c!*^"^e/̪ڪ!=,mhN=@++&Ѵe̼XD c-CDcfTAkJsW_œCkjAݧfeZx? A hw1}?{uP mo D[!isY *!+Fw?uLQXr2unww4t. *Pf~_JnEHh«kb,˼CKVqVoXf\*"T}Q@~ GL)F`3:T@aI&9`fYRe/0B(\Խvf;"s}[D]_J6֘b-p-4Y`~y%YY%ַ#9wȩ2F(J'%Jk73kl݊ү ZehAnimAD@A*j'"ǎ8ܛT5ߩe=܈o-XɳreYm.!qI%Lw &ߓ zâTP-O"GEK(!kO|adKP@mX3 0jצ2Li֥E*Bivxj4f>*; ǡŕ?GV_v]96bQyZo|g[/Cd\"ʭ"jQT2 489gG!` HEN1(YwӅ}OVJ=GbV.Sj9rӭCQ+Օ! q1Bߌf0+Јk#rCtTcsk^a7w5:'Yԙڥ͊%cVo}+tujLf*.K9#C k4p)Fk4:B"+jO?{`uyʣ zqK!2f)"XlBzfЪ_V89.Osmۭt4G=K>" J3inf.XúQ&6n)*I[aztJ4z2N) $b 2ZTkBX2N fPߨ,%D,KCKȒ^0:hĎDNȋ l!T6k8 ]73&tsD 8ǿ}[P=ʢ*HL}|?7FP,ZÁKB=n˛ӞiLȵ"W'IHԵ92#:HQ7FXP+1*`<`IM%M&-w}WrBe4(sE\%M F!20A1H9nuSjlbЋrPŶ}_-]n/JfT6n\Q$<u6FQ# XdņplJk!hDSHE,b(I[zNb*bd1u T0 vԧݶe`|YtѸRVB@0e6V0Tdk@zعڦ[hܴqtY.ĬZݒ +&hgɓȀSTSY߲kcQL({?^KA.O\5ʕ"%q5ܞfb}K*8TVV+.C6KG,ʣ`fypC@Ra`TIHU"BT JReVˎd#J9ѲdC/C欷 @AYV0يŴH){QD)e1J(s 7#+Y%)} v:ӂX05Ry0ugUCRve|Zz- QYdFTR^fؐCj4ZӮvvj@w<ի"'7vn]u v.Er*3L ө;4/}K2Ox(w4#9t,̡W3fEL ]RE< cd2)4X֤ƿ? IDATh"ZUx),mJKڔrU$c}Jw熗 ^sڏά T᭳I2m󡫮:etU >N$iXEM dLkGӟż2 ١\ 'K ˴HCPy (ϢFp+|Ayr >f}r[$0t ^+&om7~TjZ_* ]\Ye* BJQ a0I QQ9ΛMq4YM0r(Nb;sID%g:O;>"h٣p'+nvWwE{_xsKEvFV\:_*rrh5~̭]|[F[NɘU[bٶ92U ,fK D4F}Si,u߁$j]F;n/ԎJKwƁnWIe YPD w{&\m3ɈSD+ֳg"3 r"MY9}S즈~p&#pUsF!#bFUJǏYTU/vbpQz0`P=; )荟moGnqe}Z_H{ȢN17L[3"@ *gcQUR}M@+Dyպ7mLOnλBm5O>ugŝm;O9Q]羉p9hC-ഢû99iԑ4 " ^v.cP UgT2J-1ULR\WPGtPW QV8BA/?[MY;D8ŗzT)[)sЧ~x4>KV9"ֱXyV]q*Inͫ Gㅖ̬23NݾPt2:neaak9`4#UTB) EiYN26+zۄ 1 L#7Z6cpX"Y PdURUj4J0TI4* :Hu2<]΃sqz >Չ)^}6A蜹ۧ\y@(+P`&Ek63' WyF{S+Yi6UV'UFrȑC.EVvSƣ]uYٽ YWI] 빩Ā=(r$B#Kp"SHS;[䉗e.Tr*rXL0PWkY*e5TY:qlRq?d{aWUDAX4("FWYd$RBna}:"HP uTs;2;N'DuB`20) .O`%RE Ԗ džu{XaKVE冬^ܯƊL" glc #ۣ|>sy-AjlECo>xl)_#usEoK+t|޳ؑ0g V=Pؤ=M;Ȟ쮈`:T\%Zm!2 ;3Uِ*J 9,*U)GG.ЪX.nJn2.<ɩΈxkz3);~nB֫n2]zlfr:5ibst!*:;AQ c'"Qa`"LlC Y\`Pdauİ;>EL"BT W_\\J*){I&שE>p⣾%8Gȃb5=.\Sqpʶ&,>SUSQ`+zFRY}WJ""o;=ᬾU$,z8[o&̳ "Yj*6z$#eg(iؼϨSS/<;D~tgEa.T2PS;L H,9 tD tX5]\uG[G"#u"6Yjd"B>Ģ0 {h{@kߨ]& 7{Q)6,i1/AGX# dQLvB*-P–Oo-=_zZwHߨkD E}'_6&3A>Qɒzщl2zO{#(=ЉOsa=[rwO3YM?qr'!y]TivBePlȰ> N-Á s5Gs>lrk*,_U"yY7nJcO} >5uR C OFc5 ~CߨΒ#'@ʽw)i!z ܶ`g<Ɓ%IAr(+TP 4X *q3=y78"͑m J{56 ioGT`4(C;Z{Պ)0 u?A qV6Z DdX 4l̠!lQU=zِq2$ځQךB ,,`v7W/1y<7K,R֔ВK.46Eь2 &-I`ʨ|'?2վ+ʴL V)@XrN4w^E*"mjnR࠶_}u{N*7ݹ>bCɴ =/9M_Dp遆݊Bi<˄#d=Q^ Qpz_Mņ \Š|qmA,TG`h%)% ƢR=ݸ@аw {y&9R3̾wZ$Iŭ؇2kEG+脎 m2V.[8":AO"t5|q,:7$CabBnlH]l b/3͢wMKv<6 8JDHT㮽! \(=WEI5JTGd[-j_b:RJ-xJ* 6WJӛ"2Z<,iϙ &!k[i9g)R\gF3Tz;!A,bC_F%drb6%/:EH[dh,^l`.KFJS 2 GQi.hD$FaCLT8*U]7 QisVdoLTf*#5͑ ]*1#bpf@9&p6D5~,,}l7?1w'=+icTҝ&$f]4CYR`ig$`mb+@+8褣]Ѩ rs;يoS3өYi1OGc- &f:o^~IImO&}zǐJq EXUg׭>hO;rc)R8,jPTa7my ;",]uXTPT8DS9 U98 9{0hNvbGe04b!j9pΓ 6[ KQ^s'ݲT-M/sdsy>˪n&8a}$ <'?pqy,zM e 9rt;>{GlX$8tWSxziACeɀ3ǟt[r +BF}ܓ|W_Oc3K@s5x3p:uQuؑs/]gOzDzus䗞  {iM&αw7^z,]ЗگZ+ {+XT=bʹeP_|'?g;~'# Yz|8>ʿz``J ]yNx=ٟ\oUmJ)<_ź޿Z_]YWHX4 RUgo7MiHfɸ3hpCJM;S~X|xEߴǗ֎웬 f0UrҞ~#._cΎ.{uKKIDX2  SA]tmXR„Q#IťQZW uvڭ_Tpk*[ƣ|ƏNViY~C)Oztޮ?GFä4fR׎%45+呺=#`^X˯׽ѽ{_|ږ [3 +|8|`C_ ݔ+|+~5NFDΦr׾/tiOneD.ü]W../G B=NW`񣷇w񽓤fKcè8m&[{gď'o^^F,8A~s}>m`4"- dB,$.lC`;1 86P?K>_,]0 ;m{+neٞɝ=ts yt*{|A'g0ֺYOڨ~Ua_veuISFfCۦmD"?x<~#^ړ.ȩx<:|xmBq'eO^m<'ѣ_MFxPcPF3}Z(/+##*&=?x:<ɏ{;aI v춛3?~iJ}VZF:} KJ)-,.5R܌(U^qW C{/?#?bpCW-n2[4kb y }7=$Ɍ&E}þ/o{_'oMGOPuy~?e~v[GZ]^_GgQh1ѐJN`7[?OσI]ٻዮxq߾oko1Mm#w̄F *qRo47Svd| Ƭ%'Мv=|ݢWOOҾȹZ[^TEMDK$mi҈91O]z @Hx%|k˛!i[JNigNY_} 9H[8h*gai&Qs=ʣI1^T73K;]`5YŅO12YJ4D$)3.?2D$("&d娗8S-/_P/Wt˞,-O䱏}Bߏ _b|R]a}s~۵奥KĤp@ IL& .faP@Q[H$oC;?SD2^3"Q2I*<ɾb'Tz+lynVMr'fRڡpMùOBUmdݏ‡GUY0 T%&Ɵw⅌\=$ƣ~W-ܡu=YTVU6Vp=npD`=)\(oI<UC~詿Q/.9Wx\t/xtz>{#GYt!YG!7t^?cqEċ3~=|k+_v};䗾RihXvmWS_ڏӟ_Ly#~ ?IK,v5W#%/~iHi"@w"Ջ//{Cr?۞ַpŗ|WUnd" [O?_<֫$DkmAnL{bd1aLss|u F)A_w3u5v/TssIs;Tsm2Z4;g;Ĺ:)ў;nm9`sYڕN9wVŎת!K@B ;@ҤO9oCw=*wZ6m& vO>9$d ʁë2m@փ@a8sy!mkl<0Tu5h<u ztfLP@=x {/ӽa^K1@C eJi~կ{L/*eC?rk6ymkЇ~{Cxn*Fnͣ&_ˏ'kA'a{̷ =i,=x|uZ*@1\OoF=KP }~hmJVowB5 u' VgJy΁YNo) U{KeX;ꋽXڇG95ken;0=3^,xK%ÿT[Ws_\Y¨>Df咠wL&! =m#JJzb_q7M94J*$ [l]!0_O|%}E<瞵>u䃿%ubz6'9<yD~x|RWE 90a7 f>]]={+{|m ځ{mwz#/z4bXy^܍^Gk^{Nj"{VБӧa3fAȒ4/j5fLYE}o5w0s$ ];0䙄~.,l>j牀bv_Ǧ| 7âYTvV8=N\@ lюaf[Nf%@mv]ɆCR FtB0h2mףE! J{2Ld/yf0!F33{ͫ׎W^rnh4= YfO!tsGkmyScY`Re&`6uFD&~]w_x~饯H!*_7_?ZRGZ/PɟZ=$$IB(h$xP QGvJ%6^WÇDW<_?+#֚سwO!|3#ЗV7B HT_K(}a|564LdfɌZXع@ <(V&@4JB)wyۮқne&̪t,zd^Pr׻75ȱ_zыhI;7"F׻êvB& K^ HjWɪt*/"0[XxΤ? <;/_>]Q}/OIAXjDT] M΅!"TekVn]?r(TՋYJkGʬ3y= _yo>g~_=q+Ǐc4^{)*rmզ5A: /{wR8ͨp}u܄]۝h :gb3`Q,Dݯ2))ZfR=7 z/x7]AJ K? AH'黕PuP-XWUbn byeuv2A Et׽nial~gbf۲s/{>1 Y\$(2yx<AZUꯪUQ޻e1c~'ⰊNsk,Ʀr`ُķ~7|~~<0b(0ɎI:ֵׂc)]Qؿ*?G:Qb,F!*(+B_ȟ _n_+ҿGW5l9WZIG9 [vq3^36_b#逯{Ѽx\Ch\B;UUq' I׿*۞BI=4Au]ސQ* q#";po[o?|Z汢=TQ46,I0u lp]42I $bpW2W?CidlA>7{?o?-x:j(" q4h"l_XJPv,(WwwwQ@80ꊁd c=w~?O^O ?XҸMq 2]Ɣ5DmMT2B\^a!)VQ'˜_T}V|Wl5Z^i7;=Lnr7ڏ?_w}ftSԉ셿w//{^IQ]h$,Ip*: '???joiKDX(_?|e_N ^(?_k{ۛ^ÃPC x<*G_߼~BR*O{Ug/?>\~S%L?5o|볢y$)?M9 )11 ޏ?14CceQ{?#x",3^|ʭYB$=?;یu`0zK۟Oٙs嵼,ee*McizЋSFÒ>}w}mTG,evGfvʞ&1 V)pcp(*P#yuQU^ wӼQKE=bAww, zSI%=DIN4.!FB2 /4<B3uX{eҠ_c>GEz#21!Umt@"0˲PZFcߋdxN=2uOqdSf6%>׿=Y(zP-Tp=Qwr0QRѨLB%trP)H%aV\"<DջJ'u<={0 `V Fh(&9q%o&-TVaT#褥 "ነHc}ȓ*))上B`ݓHBSB5Ǣ[< =9"P@{dU4 jn!qN塜qr򿳩ըs _M2["vA:8BNۜF!ID=WmS5,IEPA=é t`Ĝ8ZJ -HLKMᱤ<ߜ= _ :E""MHl&,n22N`edxWy&jvŒT~˿wMs3Qׇm*7A?*>^s'(䆶`A9$=}f> O_*ξ m-##c#uyCVƅdYř DlV +~ܯ/׏~QwsM\H.e#?gB36#XܫM @V3Oq8I^-XfI'ĔE^Gh7~Wݧ^YH%?c*< /[H]A<5~ͱNB;Iv?S!8C|ױ?~W/m"ʼ̗\T-btjy7jZRZc=ׇ#5m6K!XOgo'P3Q Qby(լFТnouw^Zm4!"hyEz#hҏ׾_JRrm9SbZ&[;昇CCqk)Z=w=.϶ ONҗ<ϡ)}W\Ȱ7:IFozvs%XVyM^,|~WU&!ƝiD@_dLO-0wNQ leOu{6Ǟe~%.̄~_ͯ~l3B yt1] ^?sK\w3N`-J[2\0-Cx^JI[۬ieHzB!Wk0A#I#Uҁ&B3{kCcRA*3і3IE?EB1x\E]տo}kûʗ>ƷcTudEf 7m| f=}' lzL,c} rߞ~DYBcź;߹a<ף>z\cOPM87LY臐߼w}no$XJ %B"~Y~x~4|淾u*q{|گ7UƱV̩֟A-֛} /Y\]Z9_/{=VU5zbtwKٗf7HPZs](, wZ.ت u @03P#iU5Zh8|Fc:ֱ (Ҥ(QUA嗜Ar02B/͛e;̘xD.\ i e!hMLn\Jsv=qD\ po藖&D6"O_GJ1.|sҶkWwyXl/2R)6!XdX1jzq:M"p4{»qQlϏow2g5_1ʵc;n}K"yd(<1nw3{02d䉸yPu(n>!ѨoºԦ>)=wU^h˲C,NɻѸ~`vãn>_[)c}PGIFF~2^Ui(##.̒sYaSXF{x1C<,v&$ P7io @RϠ]$udFF&Xo>nz C:'%|qI]pcHHIK- Pa-ܽkrBp@"^k?vzJ{eEq_`%} 8,d$}_g`2H3,P !( u^x=k \sglIZ~#ZϞ^0## F`6:JPD6!2j"ߔ5 eEh !eifDww1VPjTcc:!zT }5Q\4NV'gd$XM]|ew\0ٌmB?K $hYP +BW77A( DPlBYѣ+ƺ1Xױw*Vժ#v/`uNOAt^?TdduqGsǃ?WO9=9y׹g!ÅnFznnm/B^/VzBDk81^j\naKF$rA.Zщfl͎N;Q337v\Gw Z.}s|eϩ5f߱]aeS4GF`0۫OzP^](1XPw@x j4q<]\FwݏG1)-~?MB6ua1})_w:alk'H,yW7 {νߌ4Xaտzssǟ+K+^Qf &@Du]=V3 `8{wcاݍGNMÌY VFFFNke3BMyzp{uћ>q?߾]~#){VDtate+KIV\Fq $h bK2222ȸ ?_o> W\^YI!A?2I (Vhʢ?ˇ =5zreL222.^ƫ7WWoW7| n\r%aIcI2D,HS=ҞE}5 1qE)*'dddlɭq^({u{>ys棛rPZ(1'ޞ:AbJ`zXuk ȩ' G222N` Y/\|OћO޼mXauapM%XKDϳaƦkSP>AqiLݹ헱"h"X~]}{{fp/Jc)7JUf?2)>w[,jT o*kuQjS؞SbO\E: r7#2g}lrӶCQ۷W׃>z7AQ1%V Hd7pU>Q:;^c: 3c!W8!>Ny$u2ӞgW_!  nnn?סޡ! K zvV8j8ǕݕyE2<Ar:7p}{ݿe1PtR{hI!zu/zh8RM9MWflHB2.vÅ!E_X臲_XW=p]{_Kh1DJu? 3Œ'X|{_;{6vFŮLLP(P~_zW$!x:D$Dp (豺_E=I&^=,^EAU`Fƙ53ɂW ^/G1x Ap!` B(̈(}|W_G%XyA'v*^W؎[=HW51OVvךzɉ9sw$'h.2;! ֜8ys[h|6ä7r@<6 {[m{ՅW;B({eQfff B0QGN$ı|ڀktc<Úڇ,, Xv{S`W7]m4=^F2.D:}5k31e,-B YP[p 䒻 G?1!jV][c?+##+ӂ)!Bѩ;I`ѣ` %\>c=ʣ)j:2@oc]W^תk몖{7].Cs.&Ac9{K֙2vpas^ o$|XN~1 sO$fSvXaV# bר+(GO7˫&jIsm>~K6iKm+ ۔IKG2f (c&٩賷gQBN')@"ݘ6:xtmaZ1U]e\p$-uLc'{qUWx4.E k9cCX%H-]ѫ:V1kOIu>&IEÉ5eQcNöR'@cϵz25l/l<q @[>lp1|B]xq5_5һ\ECM5.mܳL/cY-v[r9"Fh8npN12| }!$KQqXqx8z:ƺ&-aP?ŵ_ͷYp4+m[}ܘxsC-R"X/D)^1p'ܼʢ0Ҿ$$AGxT=|>jT{%hn4َn\Ůx-&'28_(rGuU?e9꛹js$ܛP}P wQFjq\22Xlx?|xW|+zeoP #ND&jjr-5[󒉱w?=⸆Zޏg~ٷݰL^NO8㤑#X'3Mv ^j{v_ ({^(im \hIp3 ꪪFq8~xp~pX k}®ahnL222ΖfMQWQكY Z#VbDNjETzP}x|هƏ]JJk, VFFYFf$TQɇIGk :irD׊cޏ?ûonT*%6 y>sgdqәw.FeY#nT^YS@L uS%Cj^g>pGj$Hfe VFF9EʇUS1ztW~p@>PQI5S$kFaxݧ?܍ޏq'bM6zlKՐ+###cMF`^#O 05pCDJ BF8.:Qa5VwG㇇O~QT[YLbb>FqdU}no,wkXE pm{X\T25.]ѫaU݇^9(cn~}=ze/u!čjTյWhǪգqd@}\lD^ʢµZxzT[wl+E}n̓{$RGs޻ωeK&SզS; Y {UUpzh8~ ?z%wӏF1FýQkyMhv7IX W(x~ut檵̮3kE}Qbߠijk≻uf<.6zfh~m~Z{1#\o>8A+ySv[WEUU[x\pBQe n4@WUTT5>UUUuTtՒ-ꎅ&mO5Z.aُdic?#^<7yAn5S%ͣ5f>:.ڗvw>+k>a&;fp#ӻ0Z7.1 !CY aeuc1SpWQ. |j.&w;RX'oVϼu 6Ȯc?A'ynTu\V %tk̛xg 9/KeEMq_јF]q#[,rY'\_Th_3s wW5$:#iF󃄅АwAclh6$I;fE'GgEލh3H:12sȼp̛^0|ܦ&ڌ !aKHK>X eE:.H>}L2222.=ii u'!5##%a 22226A+####8c$Qx: 4ۣLc"{?'y4[z8Yїs,K*zb>fs=>uIRDKkfy?}*[/[6*ڱCsA0;LJA%1`'F%FE$9o$P[. j lЄ:⦶uϦpկaRC;}W=M $5O7}ezLDm2U!EC$F(w66PEN3&?-f'x"~Qvve}W{HGiN6ry 'ҧYDXhL1M=m9DŔ042ߡtțq8Wy7qY$v7#cGhvInFR)Zv7"$`ML@.B tA M&:Ak zwhtF5zƮLr4N3!D D'cCRVQ4R.IuRDIrό,|_lFS3s6yT5RZ 2A l8)KTKJS,KTN7yVȬ(###K\*().{ ߢHBEHB:QG25JͶb322222ʸ FQaFA[uJM1 A~b]6r4L,g VSH IDAT.'*6:!BL;xFR:0hh2h9h4\I#A=^ VYC`9M%:*ޘ R a@##ҡ$NPc0DۜzOua222222ʸL$ Ԩf2+d`GZIӡ)LI%@4`J$E6͎8-~E 322285)($A@RtGP@0߰)HI4e; Dw$ʠ Ĭpjjfdd}Mzy)<{\f 3Y'ب[II4aI!*i8h0IL `1U;oſ,ўv-iɒOX,ߚLQͻSA6WlyּEQ7ǐ\XUƻݿ1mn9$2؝0M$db 2g05;YlNdFIrH404X09aT0I&a,"l'C2Owvև[xV^/=7]@7U"\Bi_nl@TP[]$i0&3#E#4B ℄LL.&2pM JC,s*f~l"OXn_H2$tL*?ueKC~}k4NkK\gF1 Jr)JRTJR 8ȌhTM$LR;c f),l Lk~8(ٞ-l,no⻖9R sM2 =5d@f>s=ddd`mHWl)fGuScu49 I3B \э0 8KiJ ' gJ\tAN䉮@CN:ݫ„HS T!cA@xA)`̇LBM ɘR)&42AlBX?sti[H+툵o7=SwYh4$lQ'6x%o;OjvZ:M %+Mْ$x3RK'1/B[4KALj&D%i bԣA )D t!.Ԅ# 12*O;2j chĒ~%u2L2&'άQJq9<t!ҧRr{J3jTSR17%vO'P2x^=z)W 9܄&7NLaBRvLm!>mg2WsFї)YBl >]Q+gIzNSq rR$h u46{@Mf>IZ8աviFRui~X} <)jys2pfН4 (:p +biڂKh+OS\Kww.a֫]dI8=sC(&!/nMt$_ӖxN IoX Tl_Lf]f!V`$ )$I!iGڸEsMv{]ɃbA/QX=/P WAh68-ٓhft+ *͌ Bh$1,m1`Zı|^T)y 4]PXǥ{yJʆ tjᴆoFsNia:"黣}aI4Mv٬ i Fw[I BLi`IcE5a%BmFYȖRڻ7Մs?ęeDX}==pdM `yn5FJ2MNLɞ2\D5zrfլq~S--~-{gۋP37AXNƎG)3Z$ =o8"6i\2K&MR;hS9%Oҝ uf6IRds@1iS1 !sYϙhuykGE/ }yhJN-aȉrEɤ[Гh"0wXBP*g]JOΏxӹSPn%w%lW<:YM[:N =[˷U{#-ʭ8Э3ln'$'jMBn aF wr ;@-YCGY $f2T]!%T@j3@Z&H:l4QvGN p1mi߹x㹿sns@Z[̗*'晧S&}ya4I!O|,b :qa7J΃ix f Xϊ5baɒ h+KW[5)-s* LEaF$馃MX9b0թ F kL"&+IoB ޡ畑%(}XR1\94[|6?IP`cY+ ?ѐ*$YwC돈]'fxS?V_`ɣDNfѭ%Es'_d0!~YcGj1'6NGmR#MmKdƕ6|^3U3[\JX>SL2IN l;OR42aR$j:wz(`rBksV鲤+H*)fv?jsA$ڝ %2@kfIMa.v,6sm7ՍEq'ҵ |}QwtGs+J^i*Ø0Bp)EI;Lf<˱FߔoP#-)3Gc뤚XsLLZ9RH%FJJ|jӿ{RPjnHҝtapg`r c(UMX&&1$ɛR'),٩7kQzʳmx)m`7 $NS1@4J\el \Q3̂@R N5'5-xHZ]W/_q<1=~f9dđρަsV{}YR^j-kR)!} J)Y9؆BU~CZILmrMiI(hU\$)B4 ŔN+lm'b3<2 (֚^q3S'vW,I4yDH Vr7(OY"[*I2tтڌ@;x$A5,0DA›g&\wpsFkC\3p>u"Aۇ4|5wOCn볓:Zj"[y4Pnf&{f3,f9O_ H"",g x-AjJ<%繱0 ӓءAfw1Q0YHi-! )܄d:!l:Y3d |ny]v._H7]+~uX;˺xS<'L0՜&)ZUc<<6??z.ؤɍ%񿱏iJib 4wdM9.{P*H%6]1@X">62d2^uJ{=}}] vݽ<5e+ۦoѽβ_3[aܨԎ/ń6Hرwh3ؓOEgW֖6ݑnj v鬦nN,94y kf ^;=kVGđP%`1 b(`1PX~G~o +Ryͤi -##DYs3ݛ]#<2BSlNh.k I+{4FՇX_^"<(7{̥đRr+&|w~v=6XJYV+##ur,Ekc$̚S,rQfrUB$pR==9.|=s+gտ]Me6jA52x(3*Upu}拿[_+~?{_?r/ I0Pg##~?[!##Uܑ PЪZؽn K@Eb1F#oK$9}2 @4HHdz`KG):`2]uzKYkV䋈oo GS(˛{e̠\%K8Y03bVR]K!a ?>`oXCn8o X ՃUQQ@2\57po[-ȐIKq*gN: Jvß<>=`< 5'JWءȑ$@D{-~W!f?yVLUT<7Sn8>يʳE+ Lqb39q-$-Ù:QQF!H\8V F=kAIp]懒5vӿ%۽"ū4?CЦfݣ?ᯱӴ/>{{E397؞鹅m.K73<󔻯zgOA}Q==94`"iMdMjC+uq5zdC ё#8Ji8GUS4,%a;O^WZlLtWE8"})w/sEEu-,J_krKևY~@nJPXg&34N?[RHכG߲۴ 5 ve7[o8,ʴb̎hK)qa6wkh?ԽvP2aDX(M"ֺ }կwBB\ &p]}U~x_{oI*4ɳկׯe9Al"7%.Z 5zܸn 27XfjiLJ'.^l=ļzqIC2<Òcr SY< M7' 38m &GcZdn癒@@b{_6Kp;v׌o$sE vG?z~}'/)Υ7 6ALi< dY[ρwTWŭ`<:yZ1h4—bn>pg8V'<+pŘ,h:odqo'tFu`li|{|" cUy+|uux4kR5wc}C]SQ6r, \8 4(<w%9i}Wheؐ򊩦Xk$IW2BH$bbHŠ1 b}fYgL;''^eϮ0VFٱ,`O:X O_WTTUQqAw,ӱH n}e nL,JZќ9ҤpBIA`ɂ`ILI\22ͯdxlGFs,?S.YQQQ VŻ5~&ɲSTr[};7ɶC a]Lk]y)03 irhʞ,8+ %[s) T[~4ri6u,g#}upWcMy>y 4?86h5mZRdkK%щTs FQ01ʩ5l)#dICeOj*H}] A]/X#4idq/7_rl~խ[QQ VEż}hn$@#1{~ɼa D),L+rr]4(CHE2z*;!ICd6L94[H0$x3$gaFe!6pzg>/Æ ]UTTU)ҌCC2QH `rrx/p{MwYHٍt87vHs!D ְ`&\ҔtU5\  mhM`]=rx Q.Ы+kK9(T. ]@6i9Z@8: 8ᤫĒ[[ Y@+,iufu=Pi\Fj`UT2H@!iBX!ihc:ɝ;lH9e%;$YU0AVJ$FQR(Y"T \[>;b(9`1B>m+***x{QRFM4M&F !yY=g)OViBRJYɌɇUd݁TO@A'( N0/? f.m''nUD )>?ALpV'VEE%X#L[Mhuokc,-0ƶih\.ÐU44deZ ye"W)# ̩6=Mz2i;JΜ Ql&035踉:Ÿ1m^Kn2=wPb29ZhU8͢=R=Tlb?f mӶEƚn7BXƮM44+s}hEZ\%2qn2ścjocL[וqa%}csDr:p6pLҺ$~ `I+mjp2Ķ0iR`(ʴ<&ڻmƏd$ݽ27"XPGb#j}6]>tmBb x1 A0 ;a+ )ƺE^!0l+VIØcvf >NJp7~4lazjwh4 .[!2ElC }AT+bO%%9m@lBǝv]ӷcccFFu!Єa|Xe`$,!Z0`irv{֘.ŬK =4hl5h9PQQQ V[律CdhCǾn'}f}h m@4F`SFrd14ɛ؄ M!4wNYVfqUqƊmq`EQC[55;@$[LZ䜽 VX , ֚>t;q^߇;0ftzZH1{6+%ٓ(Yy ay:lAH23Bڦn!fBf)BJhDqpwWΛV]7 I;z? &5Bp*^V=?cX\'mW =;9^/F,tNmǧ6 =߳Jmw dh ].tMhvEXCY+.`F 0fv2*/W \؅E7Y2g]puPm;7{wxK|#|Q@){S P~^<0NOqgy)dIV\8y|GnНl{Vo'As(nhE?FZ̊2Ⱥv6XL h$P7]D۴ƆMsHN39ɗw[y3=K}xޕQI23qh GkжmicC0҂9SIfQ@ -6FشGz!*.-wܗ{:S $hv|/5UP ;]u"`clE+S'Dč i0,cX K!GPчaaXu)|yZEcS?D t2a=9wP HeEE%X+\F1@Ec@,Xyᶾ!C H!<ɪլYo eKć`\v8 j RQQ ViF6dDNug?6-yIh,Us6lA@3|7&%T/ZY֘`LיL̺=b%h7l ͚0}_dT~ۧ_wQ6Y k^xaVTa3:|сN.&YW>tQxl0vWchMg$(80f%,C&嗖7 ΐg!CJI9#g(32^H+ SPn,.<.<:Yu/ԛ]StF\ٹ<G)|ɳr9ir0y##Ȉлa۝gGO=HH>vUs\躒,yZ_g& l> @tlS/u·y=ق]q4Lҟn1 iRqDS`Pp f"ZeoqY:zvO/̥D8S.*"gng9'^c/'58LtrK~ ~udkwm>w5_z2%z߾N/ rQn4 \J"QЮOgaQ݊ǦwUEXCq7 &7};bQQ/LE|>^ X>]$JD#XPԻ~KC^4cΞ!a܎ݐ{hUrȱHrJ<ҥ9`XΝeAx:=<[] T]?=3QPn"z^~{VFRx+DRe#+*qG[Fߙřtɔ /^)nd#mڨ5z,耩mHbN3St[|\?\rAK{Bz${*o5 _ЅOSNarWvԉe:.q9GF/K;R{d_Ǘ_}>'noi1A J͋2;h&-As>axiOjroE/?oNG#q5GO˪͋"%^23%W?ÈLi1dcj+2`>^XC7=\Y?gl>De.71a`Qz#jőTк JstʼnCO#E.ϰ?t}4RBytBcL^ۛX(t٫Gɧǟѯ{kd3=r)YJ=K 6iM ә,xVΞYǭy]jWLڤZZ]0}S.@I?}?|/2vuiFV7>Zrdi`:}{ !4uw=){G2pYU@DDc!+GFIK<%Uiɇ,H)3~cuֿZuW Iz!B;Wz}CeY䉧|vMţW0.}ݰ8WGV>'el<뻨@CͫwEŽM`mۏ ;QTٔȊo@ dKFnrvI";J͘qF#nsv&O+_q|e&zH,0#>܈Sʞ2|*Ҡ1uImsMn-AWZ1>(CO_-jE[Bp0|P{](ff*gdp%gd,E*X]~Hncj܏Ba 1 )#4rF]gVˇYp K'WLB"Foش.Oʃp4b:\ ÐUZe^Ӑ& UV1->#wz,<&'q(F{݋ s` pٺl%T)WCp煮KJJ,L886L^*M>61+M*[$rj#+_rxF)Rìw!^rZO(S΅<,:v%am'S%lRz?mkyQ SZ`XQqG0@;R@~IENDB`v2.0.17~dfsg/bin/index.html0000644000000000000000000001133012625374554014311 0ustar rootroot Jaris FLV Player

Video Example

Jaris FLV Player

Alternative content

Get Adobe Flash player



Video Example with New Controls

Jaris FLV Player

Alternative content

Get Adobe Flash player



Audio Example

Jaris FLV Player

Alternative content

Get Adobe Flash player

v2.0.17~dfsg/bin/logo-color.png0000644000000000000000000003332712625374554015110 0ustar rootrootPNG  IHDR_Zk;sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxw|gf@B*IH )t" zDԋz"rB %lyMHl%,agΜsfw~<=PJq;bE0 Pƀ^L=a ]N:q%F{C~3SIg)ӛ 1^JY*ƓW|Vΰaٓ;tB:\0>O֩(;T.qSû{pBhZ+Œ2_Jj@xd?͂tt҉ PANzkø)huc^‡>UJ 6$HbD^>G']y*=|qw? >z׽N"Z(U>RI8,C2 VEaϏa^kyw|Q@IG *䗫_^!x3~5h57ay<2zfEȭ{:p]^^heS* ^(P! Àej F `2\{@1`%M 'ĞT4`# EuI[iWw!ߘ>m뤓Ү,@y&% *T`k-/CjL>M c^X(gf#G76<(f#9ԔF DI"E5`5wJ2(m^2 Cz7^yJS8=d%5C 9xXꤓ*H$X:5vccAa>}C<=}pJ%4uVR& ֲI']=D y ' <j6A0a2!|Tz3oL^AIY9JPx `mu҉hW IB"W(eXb l;cj ^;KBnDԸt Ы&0^WN[Nc͞LPJE@޴ e>>o^*NQ 9 85г eD29pPl^/sM;hWAz2Nrk犫xf9hjkD%ZUU䟃t!E% 00L 0F-aeb\GU1*y[#ct(+G.CR ?ajP @C󯮿N_7!N` ] L׮xwC~xMPB/K D.4\{W{ܲ"@CL.Wqe5q/X_%*PDصoq};q{ A!FY{ PH{s{kΦ%{kM @/Y^!8yVZT><1섫+PS]iET+\ Acӊh2L:J@PkމFzB&:D ٬XѢl'&BaΕ Nvnj+<+#Tܹ*x+ Ax99QI /qy;iBOALAh DNbl'L0 @ P @-Jd! yM{15:#ݦDzQTcq[ ePW/WP }- Hp%@[ccXXáVu XTW],`w+ Gʑ`P8u k6d©gp<fK}qq^:͵",E<`X"|^ɔ$C#1 E)D_Ʌ7|_zWTTF]Lo`! f}X㿚R?ϢA E8#X";)ԙOv EMHTv4_ۋ5U"r);$ YUu=8z^o% Fx XRA.`7rQI i BӬVupt-/cT~jvQ+872XSG4^D;R t/#:}8(ʋ@n`; VЍHe HA0 sXc)oz @i%Q蠨sonRՐut,FkԹ*t1RHFZAī GXJ%r !gC훓hFdXA[, 5sC-߫Ci z A% PPe@U /q@ v'1  @gl4T` !a!@!^8pZ7H|<`zw&8ovf/Hx#n^J.,?KOr 7ɷ1ׯm}]iod~((#Ky 8ba) Z9`zX`B r7IcѓIxpބʒ$ٽRݥӧeRLfTf3O 2X5"gN'dόCWMn0x4not,]:LM&x)37n _/3wn>LJpRT_O Kw8fAd/hC+d` 8@*H @F.I4qM~am:8v E@g4`6Ax<(`QC7@7` B,ixQ/0 .rw,㺂v(8Zza\oQH* ,6^ h[]g!F3 A ̂@`RRLA1byQoR ҇eJV!1"Y ]^c $>z~lV3Yu 0yD R \+@A ־\w5$np yxoB["_8 d(kH+NU)0Y;Sl&z֮VfԖ(M -K/'X- V8:6_{yUjߩ~0<<_Op ȋMEYߵֱPYp9F` ƀ nR*H\vyVxDs֩C/` N!ZVֺ-hNiŪ Af=3ZlG|n; N@p|;le:t0|ZRb=sej *Бv䅧{F`y^bA":xWgz$0VD)aydC׵S-wu(Bm~%g"^? νR-h}@:fr9`#/7Ek۰,h9eE ujC׫ EFc%pG Գq)@`AFo6m/yQDYu J55 YH)Vep2YX GJóFCu Ё$\벊b#״(kXj0iEgM" t P'öV?Q,"ª3ju98`5sa͂* JZZZ:y$CJyDC1wu_vZugͣy[ ^Spǹ 0֩p@]XAQ7X]/8܌*fyfvGm /P7ǻ|C!|/!O{A!Hipm#ZA ļvq/un/3uu :THac$/t( b@io5Y݋Rcd,3@(&ADU AaJd,S ,E] .4 )X&G2[QWPqzxY6G(8P2w9 jh JaqYsY5ZhMfS`(ELuCϪ+8^`+,"3Lg-ymQf*,cЬ*Z'+ӛ*fTZ6H` D@ = c"XɗSAia^2Rr) ˴f񔻄1d>B)wh܉Q.އ `|5f1t+U:yE]iA]|9!os (` }#Xf KNNqRjd,-ӛן)8PQhr(<,:cI `V٢q",1gt\ŠcYǡ pOϏNt>Ҙ[s[X ^c) ]p9<4]b)(>+U{#C}Y;d,tNq !+w z:dTm䥧*4 JtͻT8tmՠ{?/g%q-¡s{DQBMhg ['rU4;e#KPw9R+efw ۦخ gFܷO@00OrNP )R@o6֎U-cP]3-3:Xڄ_''[;1o>YUvM">;Rr=/lRR4T793? P=Gua[rs͐fPT76 )4aѝ"Q5& =-(ݪ /-)*H0@"v .'pP KxTjU!?V\iuWjyBLhR eYF婵4 z~l J#q-;"<|e/=d,sUP`} 2 uY#CR#`י08#ǒo^U$溲צ*6hzڎM0rIf}zC!{c꘮A qI߂egk[Hnw&DUP{$,MY;=Oz*# Hԛq(Nݍ!r9冸ްt+EG8|Ppy2)՞JD6JHIDATH3Y࡮? gx^X~D#0a>f Ru\{2is+;KaGB*'{ynF$N|rp+7M{[|qySX̜U~^6+a]ڞ#{(І^m͂< `X{EgeM;Y&]_[ h<(I[:M(Ã]L6VA<9>Wvf &Ly^ܕeq۴?% pr6n~^ -0?}ߟ6?}s^x zCө/KW [~5N퍧fN3M7B!  WX8.MOBRj-`2@4Vq[Gk!J7b7#1њ^^e1appe .+DV2K! _}bjW~Egbak9Uk]6 I%3l0^~wmUx{z`:nRB&[˖Ny8=N&*eچoژZ+p0xbOMg8F; w|%R62swshu>^EڴCiLS|z3oY9N{2C[hha& ^ryFN}J+. peY/U>ò'ws, M;HjroX*Hg)} 'Z9X֒_م&p.:h"NVA:kHYc.k25y"( vju%VxL2ɻduMMeѡN-).), {dj?+\tixuuS(ݻw?(H2PﻹpKZVT*zbw1EEEu:]ݻ;3xJKKG\JHHx N8(eYw_p!^6rܜ2̙3KFgeYC@@]pƙ2ڃ KhcM2$}@N k4y{u/>pwWӷJ3{pSK \fYUY %Fvgl!,`%,UՌQF=\~>>>7L>=+))o߾-ZVAfddzGV(RuO>dDll߿Sݿ瞑f[l|QQk'NLΝ{_\ @iӦ6lw^" ,, ={7nz3e]O*nB-! {ԺPѢg\Õ"n K*zѩ _|bF+?HЯwèwgYѷ),|dJAdtlGj5cIRa۷'M> MFj<ߦiAAA'|2s^ _JNN^8wnJJʢ;s͛}ׯ_R#!!I/^<VIHH Oj5nuNjlw쉢L?~kfΜ}…\BB§-L\M[ bQ5e"H|s?~=]&d38q8h.wWUUռb9wӖ=o`;- Gߔ{&駟jiZm[֯_yf?d+DFk gϞ]2 777dee{;99<Î;6磏>OMM]qTT֍}_W5ՀKYƍ^r+Z֮!HDXگA>CAAA6cъȖ +**JXbE7;!![&rh _R,K|sO<vUFΆZ3 Հ?p_??ցÃw;w8W<੤O;[n//'$$βq_|1~Ɯ>}zҥK)7o^ibbbͬY-[vl]2>H3fйsDEEm9r0X:N䥗^ڭ[7hӥՒ:TTwddfEw6a„g7m6OimڍxގD)ǡ\4X{1.z5:f-8xhg1_£KN/4Ŝ/οn+¤U=–-6GddIII8{,,}8бcdvKMM5?;εa&[`9sҎ9222>={v0ذaCFZZLu. 'Odojm>K|sSsj%薩 gsTd{i52X%&NEβ,nH RɏL&Qcݷ]؆Taݗ8sISSzDk3gȅ>z{3esI1СCےߡC.^8VZu!%%1˗/8zO?oʔ)1Բ~=O~z+Vܵj*7|stAAYbE^A,9/䪪&zB.]e>}jjVE^hpppF+pvo\f+؛Yw|i{p׾.>ds[y]o-~b{{i/)}n//\?ɢHSķ˗&?*&)(??(:ujO^^>J9R7lذO~= %K^SSr˦?pezzѶ@M̅ ^vD"e2.\0hu޺L+##Cz~-Yreqݲ{n.$$=܎޽{; NF:^PPԩSi|\EM'ت>PuQpJ, ͂)gm)t?6ᶡ;~?1C]\y/9ŢG9=b֭nvդI՘ےߩS/Y$RK\hѬi BBBPXX%K&%%nw(lРA-[ODҜr~=#&&fy|||u}ʫ4p>sьD p9b_Ǘ+6&U''&uwvMWnݺߵk X+u>Çg;vLAǍ 0]tivR4i̙8 oFEGG'kUd2=,[zϯmݺxcf9zʕSK .ȃ71.X,H]>(8押J*;dk%nlR|H4)$~gHZ[R^+ @o3c^ߚ늊·lٲQS{С}hXz>}< @b2ktMik֬ 3f̚#GiM[uO !,,KKKk_gX_̚5kƍ߿ Et" BǛK w۽ Gi̻??)>mӏ35Z=^[pfޱ \Q0pl۶M3?VYYɓ'W'&&.D466v… ~7/_޷K.sZј]v)v{XpaIZZ]ӿO=Cy/9sO?~Mw7ε!o$g< [(32ݨPHZM?;qpQ+SLſVi)ID+Ja͚5aaaZ9rHn͚5NOn݈\._ӳgO{ァJKKl#SL٭[AR,`CY&799a(Mz}ӦM3v5{c̨Qh4T?GYJOirl4FkUTC'Ki] %W]-ŖE3 w&8vY[!1y\T9 CvrP'H}VrNZ3 v:"H٩sJ~;t `N;Nt1\]'2a%f0;餵p_Z!!'ǭj-;FyXZuiװtUU(.@IE%oXhFkOu 5:=;/kE3r:FtbÔAIENDB`v2.0.17~dfsg/bin/logo.png0000644000000000000000000010254612625374554013774 0ustar rootrootPNG  IHDRsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwx\g?W,ɖK2cqvlB$eaG[X$ B HB6\eI-q[mIVo3;#є{H<ѝ{gfWSJ!$7NX {fRnAAD&'NӻmR * G/vÀ>AADDit:5`ׅb^DO &' FDit:37є]'v qAAqtڀe\nz{$EHMK#$2334-ZӞ@Aa$"Jy9`Xm;;:hkkc``\IOK###tG4hv޾>gpp^rrr((( Q>MAA!D&Ns3E`]6J)Z[[vA"LBIii,O.77sRSS:uj8K̩   4p:)灏k˗gL6f4Ş\.pdeeu5MvYS Aa#4xk>|?M0mtϟOzz%)hhhӧ5n/KAa\!48Sn7.EQQs%??z#хzڮ];v{E 0Q'NkǀFNn.gfƌvVj,ws& B#48Oey<: 0mT-_;w `͚7& B"bNt?w4r*++7..\`ͺMv (&#Ljj*sefIIX577KvvѦEkk+`ʔ)L ^"n,4MA$CDE8ε߁L㍗.AzZ,aa@]]V,E ={`z8Ӄn MA!(,Gϲ&H/_L{G\"RögΝTUU188h3Nff&7mbpp+Wk錾  &t:󀧁iۯ]Fee%YYxm瓒vgmdI@hƂ R444{nGH%%B  E!ZZZʢnaLp)**[naCرpzw'OLNNW_ -WYAqRq:7T M4Raի%AUWWsa¡Ds0:+»h^kAA"J.`XOG{;YY 3}򜁄e( Dii)vӦ L\.vIkkkDandeg̤5^1/ FD=R FzzzЋB@bYYYl߾e˖Bww7UUUZ %Ak..]4G6sJ)RȠ` [NgAA(5QSaHHIIu tm6F`Xz56m"##Ajjjviiitw^Aa#ΦɓC H6 4 _III*N81l>8iya4'FAAGD1==)S`L7kn7ƕ   RMNsxvVmmQ(miiaǎtwwM^^ǴP}xn&OS  BB#8d(-,* IqSN~<CFFeku+ 0Qj@4ҽ Ofx<߿SNBff&^G՟бvylA6 UJ匱 hJ)ЋhJ޶C#яRJuM)q5| ##"J n;NA`)Sp)4mbHQ0}ww7;v젥iZZ%((-) V" 1+@.<'m6S__C'^;kJ)p=ŋ;"#Xd(4i99yI&vI__jft?z^D \|9(nSBshSJM/F,V555xER~'`-[vHc"J##҂`Ohѣ>|xH*x<JB59nۏZe Bښ!.=f'2ƌ|`w HuuuhzI+.Xbi"@v{})l&O뢱 laey=<ӷTt:^3S8`8dgg0Tp e١n*{A̠]hL9S)5l*}ooѶ:ƌm"eWR5kV؉(5ӹf OJ)ǥK ';;\=׮]3}ep1cV UuX&8 N*RY@$hQ[Pc(6*v&t:+\{^nnPA~^dOMZVVU6 E0+6+х~$m"ډjY(^tzpݺu -D8_73Z)**Qx0)?[ ov(t8X'D'iZi>YiZ%p#bVDyc'8ׄ׋ uݺu +\.W1:00^@mK/9i$RCM&+3m۶QƌRU\ڰaCdߛCy= NJ;v0B"fñrXvƻ\A\v-MӴybMst69J)SVۛhH~Rb{GK;w| Ȏ񔚀 4*VU˵UU$@|deefj/Z/ǟ;vsRGcV ̴jXu:OӴ4 \=\fOmP0Nԏ_oܸ O9xn/w:' , ?/wH(gyffΜ9VZMvݷOѫB!^: X, O)Hb6x+qCV ,Rp\~%%%v: $5⋜:u*3cf΍7m6jZ̋4Y=\hOM2Od2,ȦMva""JMrWRiet~}ŧ ʎT[hٸq#6mV^p롔:p8Vi 񥱱KiI3Z捙|nӦMc2}o{KB=.F?^~@u6NƑKFAaA .d^v } ¸r5M[iZLk˔|)$|6[_~*͛7P;j<.+ PJ܈=J,--}tfn G__ ǎq̙Hʢng Wm߁C}D)0~[Rc `*ϟOGJӴ޿[ase˖Rp\Bt ֖9ӐtwwsI\/eTfL΍s搝=j`|:t {Xf͂ it Xx\Bn<=Ƒ~7l2H (5˕ xzϢҫNQ g>;::8w,=nj-%Bˋ:vCV/}#^!J!A8}ܨi*` MӲK Meo"|6FڲeDD \. xZӹx oCss3tuuvRbT6\:u*)$vwD)U5uu8Kb4_(9yd(杻ı({OJRݺuW&rN(ܶm[XuMEWz|@/K~~74 &9 xx7`[.~dۇe>|Xܯ&=J@ PWW ,4m]CbE5jDMt"i+zm@DI\^P>ژ4iҨ:^az xCyyqsN].8m{FY%`rF~@=Xp3tAHnjjjr^/&M9mFD#E&3uHtBg{۶m&rzRBAA9SJ}ntDO|.Džxn_SS|xR* ?WUE TWWO6<-R~ aأ:^3 R#{ܥ|_8*y?FUzBpzAR*x~s@V2XMRQ Џ1} (5 եR3 G]@7Rъat7n 4]g/:amkR?DB vIKKӳ@4~AH:<8s <"JGG8ƶ$+JBW,ɓ63R3M)UݿȜ4DϥY}3@DI\]': A.Tz\+**PXfxw象E 2RoA_jsovv6SLr'ǜPc xb6}^ЍDXɷd ^ arмj+,,lhhh>/bKE"J oذ}QNԑvvx/;}O͚5ڿn;(Ng&8GMv=溺=Rz iAAC1Ђ޽{5M[u/ZBRjJfMFȎ@w83p9//3h̝;*zDM6%Rm0>0^UurڔR|zv7|:R={QӞpȑo<mʔ)dgg=>w0m+*'$mD_3$1m4^6CHORjHlRsrrl ͑#GRRsJW aS .JKo>4*1lgɡ}Xn&肐4mRj=zP{։':Ч%Rw:J%l= OӴoXRnrss),,mϾ@<\ Bܹ3}Wika"ۉ8>#lN]4Hx 4xJr5+n7W\!--EMcc#׮^6##p*RS @җ?bнiii ߦ˗/=g}ԋ  +R  (v8'z@f84 YYY'XÇ(nA c+<\;FJ7tSj&=!YYYvzzzhjj&N'==Xש0~{=g#q Oir\ /<ᛒ/jqlX!y&77w0ĵ`)K.ꁯVWW@Idx Qj&/Gff&L[[P>HII!##`Y兪:$ׯ0.y饗-KD\f<PJ((( $:˖-8tP%8 }FƒŸ|馛"Jc;= pȠS̵k׆x<zzz!--mhGvvQJMqqq8]%//bi5MziC_÷EEEX$k/_+&pPvȗy) gNII ӧOv 000iaHIIڌW޷ SZZ&M"777,} 4M[*`3zu KHpOd@L8Z\\|!XbCѧ;"TF)p| ptttAgg琰^ OӴaշtMideeGff(" ڕ\B"t;05ھDTF=9{=}aڴiVr:I0n>.<yJC0i$x{ SO=U/gtHΛ7l|M*V^}j-MɄxJM$=vh8X5zAx'S5Mۈ u4=x7!%fF&0k֬YUUSӴUJ% &PP3". \Aݪ7l`i |=4Q 11}^h PD:u"JMG4mkC2R+%D7J u֝ٽ{t'޳ Lž4ܱC]{a(d~O^iv ;&%Ǹ.B_ڼy8#`&EO|2_;n6Qj&cNߛ9ne1s\.?ai^]c~(}grEt֭[]Q&d[i׮]wٔvDGXuJ}#ٷXb( btEIpځ۷A &-= @DyD\ʈh gbPpNDi|׼he}%chP`M7 ?߰i/n߾}RS:q"x۷o? P '|}NMJTy[nEJ5 D8ل_SEOS /:R-'*ͷe+a{{Cd$AEσrяl߾gA1D,%"9gV?MpݯtkD~o] vu c#\m߾@DǨ@I*)B~_i=SmO҃^Y;T|AP\DQG'`'EG{9MG6~n71=4}F^^MӖZ9v&$$}x;5# XB+DYm۶ vRDy;㼗\9M_)$ "_,M|BtByD½yC뮓V%  -;oj $fy=c_LB݀&Pz}5A!JvUSj="J7}?F&6u>ǃ -j8_4qQG4Ee677 A3_'p֭[V# R)))Fx&aM_P>{WUOӴ-$pA{p8f, ,2.[nE"J#Fh~M躑k[Hd0+>W>5 Î,^ 7+ s)m[nBX@#m걯 `(}GIӴ;m$݈-o9 Bұ{B`}9>e˖FӇRsx4zhPX0U~v-Wt%0ַvA!~܎Z-[w(5j/oXx<8884UU1֧?ٚO$!)?Uo{&LA+ u2º߲e##\qGdףdžz׻ޕw BAb_Q7o6wHDyxB4r wL)5T>}O|x7iiU,% LCH| 5{)>c7۴iӃF㏈RL2Qd~B} &~VPvE~{+ Q|(Z7M6}@{Qj!KB+6M ("ax`!N}XDϿ}PAPٳxwoڴi 4i"J#:Ħx ᚌ@1Ǐo~t16fŋx偪_CASسgO}xscӦMj8"J#hIDSøz*NJ=sLi9C|DA&Eqeƍ ƚ31шQ_dǏsi4 n\?AA,eϞ=OFqA76lR@Dǘ.["4'\. 9s&=a0,>ߒ6>5G/ gc6O-9 0u90׈tO]m+,,Wa(wc݂75hmmMLN kmDUUU>; +%' sƍ=&7 vIpVeJ&hhha5Z?{=i~TZZZЧt*ݻUe@Zl6`Q)~8/pp]%ŌAKK"sxg---3 sD\m2n#6ls RZ`'BЇ">%X^u<ƨ;mQQQe R'8T'%ܛ-1---J` w`f\J\~o>.KmذEL RSŐ& mooѣ;vn}4p{{^^,cLa?J)ELbnz7_za/j?u~ݻw&[fnU!<, Q655qaN8S}ԇOk:lϘ477oDi#fwknnԩSMrlnnN1{?-9u!ZdSN=[[NB=F>[m@455imӜU~ڴiFtԔHx?iӦ]4s0ԭX+Ҟ6m%㚚&EK9 x o߾,O0xϺu̵*2DGPWb{^twwS[[KMM c ~bxR|0!=oD1 G#nFe=piӦwSMMMDĨ(qݷo_*z1vXnOL7* DŃM񢩩C0/>= \3ѽA*@o$8YtO>8< %; +xyp߾}9IMѴ xڵkOoUt(5եOK:2l>S7wt!'?ɫ2$.]| ,. kƌN#:tR6b'ڥKg̘+^GoL3ftvKLڹVciӾ}F 7ziO]6VQjAKB:JZ)zzzttt$S>RM~Muu5/^ X+5Q "TO}3kUq…t'83@_ЌvUjII.\kĐո.\0}WRRA.\`C_|&z3ԭGc&cB)u֊qC.\x=*GPݎke|[ׂK un&Yi+1pއ05Sz<?ikk50 }ǀ>iϟ1Fr9GԄ~'ò')ڐʺܹs]H^*++dx!)--=~ܹ?S.%Q NgEࡲ]qs-/_^jUqQj!E)+H{{{>ŨIxD/7Dٳٙ0[qidֽնeP)gϞ@œe$[}={6 -WC IDAT1 9x`&N? |pժU&DBDyc+4\Emm- \1 p75Dl6RSS6/~ ]C-N4t> n`!q:+!YE3j^`gEDyyWNM]LE{\>o1') `O dcBp6ə3gn@s-V}zpADf/uECDo;i,DGPOi$".-MKKŋ3m c+kTN:d 6{j njԛf0ORj ֮ٳJxl{11^)w3?CšCDOFwIc$2RpjmmK.%Wŋ3o<ýl\zJRCo1Kh%yֽ"&}(iF 'OfaMlZc-ђDZՙW޿bŊ!1}WWPhb4VhҘ;w.K, qSzĉWn9s$ =qbbȔs̉~?'N@_* ω'&Lp̙RN {Ĝ9s..'NK 'ߌe}7sCL+VLc!<"JtѣCGBS :uT,YW4J?~|=zֻU(୕ =e#ɽ/ ~SYYeҔRV [\S,l{?ʗhCS]]nk\/^|yR|R9s… KBv9y$ &6-l̟?e˖1}t3xs|zfL/_|'2Rs :5ܹs=z1])++˗b _2HXItRJ}k`~ |bB)(pΝkҜ 6񢦡a. v_"o\+o 94ņ_;w3$ވ9(C࿗-[& (5z]3hQQ+WdѢEqcǎ!2o޼ɄK7FO${`ЯFsa2N(яh;vEW7oބSSScSJ}$7G-[_ J}}=W^5iիWs㍖{T) <0GMp^* Y9z諰͟??/G7)(U?iDGs=z0,~*F4&u%ۀk޿m[(z-b @Ӵ Jǁ.]z:v%*"JEQ1.^B¼yXzae`fP__:]ǽ ŌR |zFtT__?bD_`kOC ,8ͅ^;F&R x}Hz)c-@k~66OTK.׫1R?~rߑ#Gs .7riJo,YT΃x#`}2w %R;c s̉HIh$yRdxz-z~h"CcmEp.F [-Zmq *~C݌!:aG-ZӢ#uuu)]uIQ_8Qj?OSRr%wtƌ_x-.?.^BgOx/imm$mEq2*pŋGAmmurcn gѢE>mf1Ι <|Y/_WWQXx Q(5{l)z1UV-..fڵvs{IA O*jjj&ǿYyCCXP180jjjV./P;;zLI%m[zVjيR W/rݮx*P "@BW ) }K$M2Ǚ49gfr|t͙3'O' RjB}dɾ))&M:\}ۀlɲB5۷?_vї8q!, R~Xza=2d3gs wݟR)S p=OH TLa۶mss+MVN2e_Ŷm*K%-%K7;eʔ>WRڤnL<۶mö_ĚYm۶6eʔ{S zM8>( fˁ!GA1}t.\M'0AakyF>+!֭[Ψ`'Lcߺuk p}J_Zlʔ)۶n:;3gTغuGNz͎;`o6\r%%`&W.>y?T)u7ps;Z.""+a!N[lLkz{mmm}Гe˖"/ʀ'+kkkW{5Rj@mmm.SNܲeTv_x7hَ;VԶ+VF+Cu*Ř2e _|1hLYJl2۲$-玗+ؿƎwl:8l |t˖-_މ10LnɒԬ [B@+i|jԯ薖2yd.?{NSJN~\JӦMě7o,z^^6mKImm7oʛb'jKj Rkmm}*l9 dB⡇0hI&1i$SBpkYcf vaYVƱiF)n~ԉiӦx`YV1vY]~U{yx׀-H!Rzb{%t̙3'v~WM6]D5eu[X |sOP>4ہ%)ٴiSVu41`l%w00;n kVJ?9l41c 9'4WJ$r&Ӯ{؍3fĂ7nbSP-HO$q(vt{r' 7f̘uZ)#Ɣ*.?7oo\֬Yt+^2CϼyjE~͚5XnVR֬YSDCM 5kD͛GA)O?$QH.4bfΜIIIgs14V^=<%_?'uW^g@i+.{ՓϟT)6`xK>8+(Rft'o![R3|,Y08󩩩!yuR pG/ҼMSJHELpZeॗ^3gg->zBv?? nH}饗i키 +V܄&SR]]yKR\2/s|=瞛`s=W3%_[`=u؛0꓾ ~X1fРAL:ڣZC4$rl0yjժ ֽ.Z xs]v; ]j,e- آzIg{ͪU_>N8V]vY[k4Z)k<-;v,555Z u&gN]]]q.\=$F;p… 7~AoUV 5jĉPs=\@B .\QWWN\Z zb/D `:cr>p¿,G/{Ď!uU&:I&ƥ;O>`-Zzrʠ-Zȓ-+Wb4ٺhѢ'cʕS-Z{p {_Md\.V<'u{pE-[B)?`^u4ǀGS (d%gWJZ[[cŊ Q$'V^Ʀ.}+J̢EVX"Hk+VT|dŊ [e08(Y7^ַ50MrR?/11{ziSQX2g-M9=;[K+-< |/? ~^ ;h=],[URJ)s /^RBdRj 뜥Ǫŋ7-D_~gy9`Aزh4!`xa y~YvX^)}CݞNjyg%M>؛iPܿx₷F)5 GJVۀn=mҤ-9M~.l96ࡰŋW>Z)wmo;0 tڵ77MEU`M7t,ɐJi+`{V,YD-D$:]zC%K$FN"T[K5&s7yWJ׭[Wܝ{=-n馛8A2}+u%|&g%K|ꩧTӟhN:~x+hu^)> i{8^UI[J["S|–#O8t1nN3-ؿǯS!ˣɂVJ׭[WƎf`=ݎ Sm)=Ga )J U>ǫ*{h_yuO<*ರeh2xxUW]<>J) ºKǃ&)pKiκuЮȋRm-2 Ŀk ƚ<&ߕH= /ރ#ػ?yBPpW=Zڱ+t)믾]ኤUJ׭[W ̂[v`& R5\r㒫h+iF5D[K5}VlEԺktRJ)pE_܇xִRa [X٠Z 8xr-@&\s5u=؍@,%>;;؇5q[YO73$TZS6̟?Wa IK> Xtaˠh TJ׭[ao3x)MB^Ch4 ȒOejA1JFh4O*Mz'Wm)h4Fӓ|UJ;Ce˖=$UcJ{RFh )BX=7VJ5F)xRꨔ{>=A+}+SveYSƁĽgLR\K؊]BaE}mpWJy2t˸t9BJT\ 埥=-4Wt/v8( 7D7XJ_Tc__.{B|)'Re[?݂muR$[{8B<׵U_`tIZ* ށ]ZءCNLrjR:gΜu=B=ݘ.3Iqs)dKi~_-iTM3dY/L 3 ~8Y'L B}~ ~" [IMFp2"=+PVq\Jy=;#;e"RlR 5Nl=8 ,gWRROM:U>Bc>/w]@VEkbK&FC̡xR{I(ws5@,zeOL⑳!cǏrTJya@" >NPJy$au6]= +q\pc !D'T j\ktΜ9@PJf/_< c Ij *t}Kia0Ms-+as%eY xg;X#MdܔNK)ӺgK{֯]SJ,'>*r~M!vbw_8yMPZu;m$ɺ(..vЉNE˘t'*ˑ.SP( \(ױk:ےvnŽQ ů~GJ9?I󀯹 o!C̫;BݷU3?hΜ9Dq444&ESiii.\x@+a!ozeYpwm>i^k&EH)/>2Uι )e(^v_sՋ")[ ppn]ښj{ʰj{47230C>`. ˰-QD(.Nj@-tR,?=Cez`"NqNTi K,d?g$7}_?6/=!^=w4-h?I!DUGUyLPJ̙ӊXwK"d/4663vzxX̗yiq줧ð&= *2M5/R)eoAJ>[gδsR+&;BYN:R7skBք[ѐ@cR 0ww1K<@eUƶ֦IPR禠pkdiq/)3p_ײ, ˰u~H*X'p*HA$4ޖpA i)e/`gr+Rʫ <B64T5)򘼭S/1&bR &$vW"Rץ#RQQ$9l,|܋lfS eYm1kS^W'Mk5LB ;qOnzLH׾}n .~)Y#hR.CS 3J) !vw=),ŽStjiuCJYZOs[[gDJ\^USSݻ.xS4`Rm ̒gq˲8YXa+feYӁO 4糙=I0Rʉ'ĵ8BR~ ˲>s'L,+"NtCJ9g ޳A$7ku8 |y*%E!Rޅ]g43>-\|e.ĖHR!/ !*_Yt:C!]gx9X,ƩSPJzQJQղEBᥤ$Q?C tSq+vTu]IOMqN|4Mڒ!t x" qEJ~`˰B()姰.7I),XYu;rvy+ ݃BP6M$ھ˰%3j(FŰa8p^S\\L,cSTTzPM=4w2l&m`YV5v?h'LMsR*a3_#QpH)^|移Bl=~DaDu.C8vMH)Dͤe daDQJJJ(//gTTTG6+p˲MpPiDGJY$)֎ !:-hĽBg2k1&TH!=؊J6Ǝ#=TtRI)J) xkn Iv8ɓ`qJJO%5 %I"޴OkjȘlY?: mtT&-˚{wLܙr+U t O;d-RIg7ѭ[o-L뷤BKsάBN(5d9QJゔ;wM"}_ФA/T)E}&CohjY;~4M,h -! oRN=0v.½|_J!ĩ{ 2m~~k-\Ji+v&0M ˲0죖e=.S~|8p7mfP"GJ90B4l)Rb& t Z1Jme pi_t4WYu iRMVCJ%?KV5@Ji^r._J1..tw2(RY#\$͕?avЕRm-im=FtJˇ^vx<p-0(MԮQxun?syB?x/#.vd ]Jyb@2eQJ$ӕh7B)'NmPJ5#&L|-|4M]Vtw׾!^Žvb 4DE'jW~NHO?ny醅{RMaM`˘ !v!L{2FtSL ՊihT---477|D"&HĪ~h*Z[k/Rʩ'Փ}=>#hƽR7 I+>^? P&wO1M¶z&odٰ[˱a8G98cfi|)x"q4}_<40f`˘GB4 vlߖRBMnG^VL=#{MF)ž}<M<4 . ٰ [M,}%r>e.㐏'96u49QBR^2t uS Z:d5) #BY(K)$jj`(C=@j<0 ÇRu~)ZM˲iÖEh4MRGH&+:::xWF^{m#<2MΦw]jƅOScذa HYW0 /[?p~/Bwrx衇dRH$9=+lD"^!]vYs]]Kކ 7nܸŹiӦO0 =ca{f̘4P+–;9]OON 80u~W^D"ðQGkaǁsյ@[J5}b߾}:t(Kn>\¶ ]iyF9P{z]v +**STT*NawJv-ٹsgÅ^x?)F,{4M)R%\r8`zp}饗)&( `d[[۠'NU+^|eeefO訯]! [)uc9/3Hu֊x<^]QQQOaJÆaͧХC+ݻ'`:SNox_qN{.5mJ$oQݻ*5jTNغSVVF42{H)RK7 t<? 6 e̘1i@ɬ\OرcGyyXT8pѫMԨ_~8ÛHYYYdqs d3l2vua|wNױ\ڴ%Lu^ziaUY.xtD"2 hԁ\p "H)imM_[!mbVܹÇb@/ū@KKKC73 cɯ+Ňj6l|NȄ^2'4MC߿U)u 8:rȔ<'+W.*555q`aRE @nll N׿^RR20>~Sa.dwޘacXϿ`޽{nj[RKP&bOBWJQ__nFR);vl`!SI6ߟ: vR߀wL:ճ,X,RRDRūEJaeeeIl\0\lƸX,6ax<^_YY>z&`acR9a5bg)n7`?IRi`[ c8~IqРAK<`"8qRHniرc&L G9D&CR {;cJRˇ:g%pѡC7 48t-H$k˵@uugDyڬTw8ڿ Ј#*@?B[J5tvvr=n~|vʔ)5[ZZ0 #MMSJrnt`'-"I+ճ^+)q---UV.:ujaR~! E#Eimmm,++OXMҿ0`Yڙ`E""TR[ \v TTOĠA:O>},q$2 @ D"C i^$C18[۔Rb13O|x(4{C3mp$I9rHU<gӹݡ6lߥ{ÇWGQ$aqȐ!]_)ґayPimmVJ5 2O%z^Ǻ_[8CoǘTnNS2K'NI1f`GGGqEE3u $QFݟO5ɞOg)]TdXsSQSIWJΩS=Fmo?d6:Cݩ  H޴;)ƑHD+dwR0Sa?c:__4iR ܫ`~yxW)cxGG.F: k׮jTP1]v)k룃 ֖{:J7ӧ5F}x^6 #9c_!lӹ8sWIDAThRLp0ǻ*cz}}ҝ,&pGhØ1c2Jr CruP(1c7tLe/n4iҫAd)ͅE2W–eEKJJbME'; /p0 =1ޱcG}MM'9qm߾h0;% 'f.|𖷼]NtttL 9B}2֟u{+RTD"??c ܹsHxSH$C+;;;E]5:KUD7e#JJJ[n9ss{zVh$dQJaUJ3gN|qS߸qf&YU0 a ӧO?5ydٲeKqGG(lDȊ555)ŦiaÆQ`L{{M65L>=e̽u,e1f?ί&K˹ e&D)je4{q9CģTgs_ru cB8 ۿjjjr.g\#3}γ=/<[/_zRjoeuuuN<ٰtRfRk PJxi0 8jVJc%v* ՟R3fJ"H500.[q0I |9EEE#|q0͛Y=ў̚54իMKs֬Y30sjs4S$!Yl7 ݶ*ZJKK[M`N-)(IENDB`v2.0.17~dfsg/build.hxml0000644000000000000000000000064012625374554013537 0ustar rootroot#integrate files to classpath -cp src #this class wil be used as entry point for your app. -main jaris.Main #Flash target -swf bin/JarisFLVPlayer.swf -swf-header 800:600:30:000000 -swf-version 11.2 #Uncomment to enable debug #-debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code v2.0.17~dfsg/documentation.txt0000644000000000000000000001343512625374554015166 0ustar rootroot================== How To! ================== The above example is one of the ways to embed the player to your html files. Just copy and paste. ---------------------------------------Code------------------------------------------ --------------------------------------End-Code--------------------------------------- ================== RTMP Playback ================== In order to play from RTMP servers set the following parameters as follow: streamtype=rtmp server=rtmp://server/application/ source=streamkey Some rtmp streaming servers support a source syntax as follows: * source=mp4:channel * source=mp3:channel This is to tell the server in which format to stream the content. ================== RTMPD Example ================== An example of rtmp streaming using crtmpserver: 1. First, in order to stream from your pc you can use ffmpeg as follows: * ffmpeg -i file.avi -vcodec libx264 -f flv -metadata \ streamName="test" tcp://127.0.0.1:6666 2. To play this stream on jarisplayer set the flashvars as follow: streamtype=rtmp server=rtmp://127.0.0.1/live/ source=test In the example 'live' is an alias of 'flvplayback' and 'test' is the streamName. ================== Flash Variables ================== Here is the list of variables that you can pass to the player. * source: This is the actual path of the media that is going to be played. * type: The type of file to play, allowable values are: audio, video. * streamtype: The stream type of the file, allowable values are: file, http, rtmp, youtube. * server: Used in coordination with rtmp stream servers * duration: Total times in seconds for input media or formatted string in the format hh:mm:ss * poster: Screenshot of the video that is displayed before playing in png, jpg or gif format. * autostart: A true or false value that indicates to the player if it should auto play the video on load. * logo: The path to the image of your logo. * logoposition: The position of the logo in the player, permitted values are: top left, top right, bottom left and bottom right * logoalpha: The transparency percent. values permitted 0 to 100, while more higher the vale less transparency is applied. * logowidth: The width in pixels of the logo. * logolink: A link to a webpage when the logo is clicked. * hardwarescaling: Enable or disable hardware scaling on fullscreen mode, values: false or true * logoalpha: The transparency percent. values permitted 1 to 100 * controls: To disable the displaying of controls, values: false to hide otherwise defaults to show * controltype Choose which controls to displa. 0 = old controls, 1 = new controls * controlsize Changes the height of the new controllers, the default value is 40 * seekcolor Change the seekbar color (new controls only) * darkcolor: The darker color of player controls in html hexadecimal format * brightcolor: The bright color of player controls in html hexadecimal format * controlcolor: The face color of controls in html hexadecimal format * hovercolor: On mouse hover color for controls in html hexadecimal format * aspectratio: To override original aspect ratio on first time player load. Allowable values: 1:1, 3:2, 4:3, 5:4, 14:9, 14:10, 16:9, 16:10 * jsapi: Expose events to javascript functions and enable controlling the player from the outside. Set to any value to enable. * loop: As the variable says this keeps looping the video. Set to any value to enable. * buffertime To change the default 10 seconds buffer time for local/pseudo streaming ================== Keyboard Shortcuts ================== Here is the list of keyboard shortcuts to control Jaris Player. * SPACE Play or pause video. * TAB Switch between different aspect ratios. * UP Raise volume * DOWN Lower volume * LEFT Rewind * RIGHT Forward * M Mute or unmute volume. * F Swtich to fullscreen mode. * X Stops and close current stream v2.0.17~dfsg/.gitignore0000644000000000000000000000001512625374554013532 0ustar rootrootproject.hide v2.0.17~dfsg/Jaris FLV Player.hxproj0000644000000000000000000000326012625374554015700 0ustar rootroot v2.0.17~dfsg/license.txt0000644000000000000000000011627712625374554013747 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.