Flex 4 UI

- build using gradle
 - launch from outside flex builder
This commit is contained in:
Richard Alam 2016-05-26 19:07:27 +00:00
parent a615ed7583
commit 785ee34453
75 changed files with 20097 additions and 53 deletions

View File

@ -465,7 +465,7 @@ class ApiController {
if (redirectClient){
String destUrl = clientURL + "?sessionToken=" + sessionToken
log.info("Successfully joined. Redirecting to ${paramsProcessorUtil.getDefaultClientUrl()}");
log.info("Successfully joined. Redirecting to ${destUrl}");
redirect(url: destUrl);
}
else{
@ -1399,6 +1399,8 @@ class ApiController {
* CONFIG API
***********************************************/
def configXML = {
String API_CALL = 'configXML'
log.debug CONTROLLER_NAME + "#${API_CALL}"
String logoutUrl = paramsProcessorUtil.getDefaultLogoutUrl()
boolean reject = false

View File

@ -31,6 +31,7 @@ package org.bigbluebutton.lib.common.services {
protected var _onUserCommand:Boolean;
public function BaseConnection() {
}
@ -150,7 +151,8 @@ package org.bigbluebutton.lib.common.services {
}
protected function netASyncError(event:AsyncErrorEvent):void {
trace(LOG + "Asynchronous code error - " + event.error);
trace(LOG + "Asynchronous code error - " + event.error + " on " + _uri);
trace(event.toString());
sendConnectionFailedSignal(ConnectionFailedEvent.UNKNOWN_REASON);
}

View File

@ -0,0 +1,58 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation; either version 3.0 of the License, or (at your option) any later
* version.
*
* BigBlueButton 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.lib.common.utils
{
import flash.external.ExternalInterface;
public class QueryStringParameters {
private var params:Array;
public function collectParameters():void {
try {
var url:String = ExternalInterface.call("window.location.search.substring", 1);
//var url:String = "host.pl?logouturl=http://www.google.com&host=rtmp://192.168.0.120/deskShare&room=6e87dfef-9f08-4f80-993f-c0ef5f7b999b&width=1024&height=768";
// Remove everything before the question mark, including the question mark
trace("URL = " + url);
var paramPattern:RegExp = /.*\?/;
url = url.replace(paramPattern, "");
// Create an array of name=value Strings.
params = url.split("&");
} catch(e:Error) {
}
}
public function getParameter(key:String):String {
var value:String = "";
for (var i:int = 0; i < params.length; i++) {
var tempA:Array = params[i].split("=");
trace("params key=" + String(tempA[0]).toUpperCase() + " val=" + String(tempA[1]));
if (String(tempA[0]).toUpperCase() == key.toUpperCase()) {
value = String(tempA[1])
}
}
return value;
}
}
}

View File

@ -7,6 +7,7 @@ package org.bigbluebutton.lib.common.utils {
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import flash.net.URLVariables;
import mx.utils.ObjectUtil;
@ -36,19 +37,26 @@ package org.bigbluebutton.lib.common.utils {
return _failureSignal;
}
public function fetch(url:String, urlRequest:URLRequest = null, dataFormat:String = URLLoaderDataFormat.TEXT):void {
public function fetch(url:String, urlRequest:URLRequest, reqVars: URLVariables,
dataFormat:String = URLLoaderDataFormat.TEXT):void {
trace("Fetching " + url);
_urlRequest = urlRequest;
if (_urlRequest == null) {
_urlRequest = new URLRequest();
if (_userAgent) {
_urlRequest["userAgent"] = _userAgent;
}
//if (_userAgent) {
// _urlRequest["userAgent"] = _userAgent;
//}
//_urlRequest.manageCookies = true; // only available in AIR, defaults to "true"
//_urlRequest.followRedirects = true; // only available in AIR, defaults to "true"
_urlRequest.method = URLRequestMethod.GET;
}
_urlRequest.url = _responseURL = url;
if (reqVars != null) {
trace("reqVars " + reqVars.toString());
_urlRequest.data = reqVars;
}
var urlLoader:URLLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, handleComplete);
urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
@ -56,7 +64,7 @@ package org.bigbluebutton.lib.common.utils {
if (HTTPStatusEvent.HTTP_RESPONSE_STATUS) { // only available in AIR, see http://stackoverflow.com/questions/2277650/unable-to-get-http-response-code-headers-in-actionscript-3
urlLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, httpResponseStatusHandler);
}
urlLoader.dataFormat = dataFormat;
//urlLoader.dataFormat = dataFormat;
urlLoader.load(_urlRequest);
}

View File

@ -116,7 +116,8 @@ package org.bigbluebutton.lib.deskshare.services {
}
public function connect():void {
baseConnection.connect(applicationURI);
trace("Deskshare connect");
//baseConnection.connect(applicationURI);
}
public function disconnect(onUserCommand:Boolean):void {

View File

@ -132,10 +132,12 @@ package org.bigbluebutton.lib.main.commands {
audioOptions.listenOnly = userSession.userList.me.listenOnly = true;
shareMicrophoneSignal.dispatch(audioOptions);
}
deskshareConnection.applicationURI = userSession.config.getConfigFor("DeskShareModule").@uri;
deskshareConnection.room = conferenceParameters.room;
deskshareConnection.connect();
userSession.deskshareConnection = deskshareConnection;
trace("Configuring deskshare");
//deskshareConnection.applicationURI = userSession.config.getConfigFor("DeskShareModule").@uri;
//deskshareConnection.room = conferenceParameters.room;
//deskshareConnection.connect();
//userSession.deskshareConnection = deskshareConnection;
// Query the server for chat, users, and presentation info
chatService.sendWelcomeMessage();
chatService.getPublicChatMessages();

View File

@ -2,9 +2,7 @@ package org.bigbluebutton.lib.main.services {
import flash.net.NetConnection;
import flash.net.Responder;
import mx.utils.ObjectUtil;
import org.bigbluebutton.lib.common.services.DefaultConnectionCallback;
import org.bigbluebutton.lib.common.services.IBaseConnection;
import org.bigbluebutton.lib.main.models.IConferenceParameters;
@ -91,7 +89,7 @@ package org.bigbluebutton.lib.main.services {
var uri:String = _applicationURI + "/" + _conferenceParameters.room;
var lockSettings:Object = {disableCam: false, disableMic: false, disablePrivateChat: false, disablePublicChat: false, lockedLayout: false, lockOnJoin: false, lockOnJoinConfigurable: false};
var connectParams:Array = [_conferenceParameters.username, _conferenceParameters.role, _conferenceParameters.room, _conferenceParameters.voicebridge, _conferenceParameters.record, _conferenceParameters.externUserID, _conferenceParameters.internalUserID, _conferenceParameters.muteOnStart, lockSettings];
trace(connectParams);
trace("BBB Apps connect: " + connectParams);
baseConnection.connect.apply(null, new Array(uri).concat(connectParams));
}

View File

@ -1,38 +1,66 @@
package org.bigbluebutton.lib.main.services {
import flash.events.Event;
import flash.events.HTTPStatusEvent;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import org.bigbluebutton.lib.common.utils.URLFetcher;
import org.osflash.signals.ISignal;
import org.osflash.signals.Signal;
import flash.net.URLRequestMethod;
import flash.net.URLVariables;
import org.bigbluebutton.lib.common.utils.QueryStringParameters;
import org.osflash.signals.ISignal;
import org.osflash.signals.Signal;
public class ConfigService {
protected var _successSignal:Signal = new Signal();
protected var _failureSignal:Signal = new Signal();
public function get successSignal():ISignal {
return _successSignal;
protected var _successSignal:Signal = new Signal();
protected var _failureSignal:Signal = new Signal();
private var urlLoader:URLLoader;
private var reqVars:URLVariables = new URLVariables();
public function get successSignal():ISignal {
return _successSignal;
}
public function get failureSignal():ISignal {
return _failureSignal;
}
public function getConfig(serverUrl:String, urlRequest:URLRequest):void {
var p:QueryStringParameters = new QueryStringParameters();
p.collectParameters();
var sessionToken:String = p.getParameter("sessionToken");
trace("sessionToken=" + sessionToken);
reqVars.sessionToken = sessionToken;
urlLoader = new URLLoader();
var configUrl:String = serverUrl + "/bigbluebutton/api/configXML";
var request:URLRequest = new URLRequest(configUrl);
request.method = URLRequestMethod.GET;
request.data = reqVars;
urlLoader.addEventListener(Event.COMPLETE, handleComplete);
urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
urlLoader.load(request);
}
public function get failureSignal():ISignal {
return _failureSignal;
}
public function getConfig(serverUrl:String, urlRequest:URLRequest):void {
var configUrl:String = serverUrl + "/bigbluebutton/api/configXML?a=" + new Date().time;
var fetcher:URLFetcher = new URLFetcher;
fetcher.successSignal.add(onSuccess);
fetcher.failureSignal.add(onFailure);
fetcher.fetch(configUrl, urlRequest);
}
protected function onSuccess(data:Object, responseUrl:String, urlRequest:URLRequest, httpStatusCode:Number = 0):void {
successSignal.dispatch(new XML(data));
}
protected function onFailure(reason:String):void {
failureSignal.dispatch(reason);
}
private function httpStatusHandler(event:HTTPStatusEvent):void {
trace("httpStatusHandler: {0}", [event]);
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: {0}", [event]);
failureSignal.dispatch(event.text);
}
private function handleComplete(e:Event):void {
successSignal.dispatch(new XML(e.target.data));
}
}
}

View File

@ -1,7 +1,9 @@
package org.bigbluebutton.lib.main.services {
import flash.net.URLRequest;
import flash.net.URLVariables;
import org.bigbluebutton.lib.common.utils.QueryStringParameters;
import org.bigbluebutton.lib.common.utils.URLFetcher;
import org.osflash.signals.ISignal;
import org.osflash.signals.Signal;
@ -20,10 +22,16 @@ package org.bigbluebutton.lib.main.services {
}
public function enter(enterUrl:String, urlRequest:URLRequest):void {
var p:QueryStringParameters = new QueryStringParameters();
p.collectParameters();
var sessionToken:String = p.getParameter("sessionToken");
var reqVars:URLVariables = new URLVariables();
reqVars.sessionToken = sessionToken;
var fetcher:URLFetcher = new URLFetcher;
fetcher.successSignal.add(onSuccess);
fetcher.failureSignal.add(onFailure);
fetcher.fetch(enterUrl, urlRequest);
fetcher.fetch(enterUrl, urlRequest, reqVars);
}
protected function onSuccess(data:Object, responseUrl:String, urlRequest:URLRequest, httpStatusCode:Number = 0):void {

View File

@ -274,6 +274,8 @@ package org.bigbluebutton.lib.user.services {
} else {
// why 2 different signals for authentication??
//userUISession.loading = false; in authentication command can break order of functions
trace(LOG + "got here!");
if (userSession == null) trace(LOG + "User Session is NULL!!!!");
userSession.authTokenSignal.dispatch(true);
}
}

View File

@ -23,7 +23,7 @@ package org.bigbluebutton.lib.video.services {
var fetcher:URLFetcher = new URLFetcher;
fetcher.successSignal.add(onSuccess);
fetcher.failureSignal.add(onFailure);
fetcher.fetch(ProfileUrl, urlRequest);
fetcher.fetch(ProfileUrl, urlRequest, null);
}
protected function onSuccess(data:Object, responseUrl:String, urlRequest:URLRequest, httpStatusCode:String = null):void {

View File

@ -111,6 +111,7 @@ package org.bigbluebutton.lib.video.services {
}
public function connect():void {
trace("Video connect");
baseConnection.connect(uri, conferenceParameters.meetingID, userSession.userId);
}

View File

@ -103,6 +103,7 @@ package org.bigbluebutton.lib.voice.services {
_conferenceParameters = confParams;
_listenOnly = listenOnly;
_username = encodeURIComponent(confParams.internalUserID + "-bbbID-" + confParams.username);
trace("Voice app connect");
baseConnection.connect(_applicationURI, confParams.meetingID, confParams.externUserID, _username);
}

View File

@ -4,6 +4,8 @@ additionalCompilerOptions = [
"-target-player=11.2"
]
output = 'bbb-web-client'
dependencies {
merged project(':common-library')
merged files("libs/as3-signals-utilities-async-v0.9-BETA.swc")

View File

@ -0,0 +1,7 @@
#!/bin/bash
set -x
rm -rf build/*
gradle build

View File

@ -37,7 +37,7 @@ package org.bigbluebutton.web.main.services {
var fetcher:URLFetcher = new URLFetcher();
fetcher.successSignal.add(onSuccess);
fetcher.failureSignal.add(onFailure);
fetcher.fetch(joinUrl);
fetcher.fetch(joinUrl, null, null);
}
protected function onSuccess(data:Object, responseUrl:String, urlRequest:URLRequest):void {

View File

@ -20,12 +20,14 @@ package org.bigbluebutton.web.main.views {
override public function initialize():void {
uiSession.loadingChangeSignal.add(onLoadingChange);
onLoadingChange(uiSession.loading, uiSession.loadingMessage);
var tempURL:String = "http://192.168.23.53/bigbluebutton/api/join?fullName=Foo&meetingID=random-9342782&password=mp&redirect=true&checksum=0491da5c90460ed8fd1690cbbf15960bd26bc90c";
// Call join service
var joinSubservice:JoinService = new JoinService();
joinSubservice.successSignal.add(joinSuccess);
joinSubservice.failureSignal.add(joinFailure);
joinSubservice.join(tempURL);
joinMeetingSignal.dispatch("http://192.168.23.53");
// var tempURL:String = "http://192.168.23.53/bigbluebutton/api/join?fullName=Foo&meetingID=random-9342782&password=mp&redirect=true&checksum=0491da5c90460ed8fd1690cbbf15960bd26bc90c";
// // Call join service
// var joinSubservice:JoinService = new JoinService();
// joinSubservice.successSignal.add(joinSuccess);
// joinSubservice.failureSignal.add(joinFailure);
// joinSubservice.join(tempURL);
}
private function onLoadingChange(loading:Boolean, message:String):void {

View File

@ -0,0 +1,172 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css" media="screen">
html, body, #flashclient { height:100%; }
body { margin:0; padding:0; overflow:hidden; }
#altContent { /* style alt content */ }
</style>
<script type="text/javascript" src="http://192.168.0.249/client/swfobject/swfobject.js"></script>
<script type="text/javascript">
swfobject.registerObject("BigBlueButton", "11", "expressInstall.swf");
swfobject.registerObject("WebcamPreviewStandalone", "11", "expressInstall.swf");
swfobject.registerObject("WebcamViewStandalone", "11", "expressInstall.swf");
</script>
<!--<script src="http://192.168.0.249/client/lib/jquery-1.5.1.min.js" language="javascript"></script>-->
<script src="http://192.168.0.249/client/lib/bigbluebutton.js" language="javascript"></script>
<script src="http://192.168.0.249/client/lib/bbb_localization.js" language="javascript"></script>
<script src="http://192.168.0.249/client/lib/bbb_blinker.js" language="javascript"></script>
<script src="http://192.168.0.249/client/lib/jquery.mobile.min.js" language="javascript"></script>
<script src="http://192.168.0.249/client/lib/jquery.json-2.4.min.js" language="javascript"></script>
<!-- <script src="http://192.168.0.249/client/lib/getScreenId.js" language="javascript"></script> -->
<script src="http://192.168.0.249/client/lib/jquery.cookie.js" language="javascript"></script>
<script src="http://192.168.0.249/client/lib/jquery.dataTables.min.js" language="javascript"></script>
<script src="lib/getScreenId.js" language="javascript"></script>
<script src="lib/jquery.FSRTC.js" language="javascript"></script>
<script src="lib/jquery.jsonrpcclient.js" language="javascript"></script>
<script src="lib/jquery.verto.js" language="javascript"></script>
<script src="lib/Screen-Capturing.js" language="javascript"></script>
<script src="lib/verto_extension.js" language="javascript"></script>
<script src="lib/verto_extension_share.js" language="javascript"></script>
<!-- <script src="http://192.168.0.249/client/lib/verto_extension.js" language="javascript"></script> -->
<!-- <script src="http://192.168.0.249/client/lib/verto_extension_share.js" language="javascript"></script> -->
<script src="http://192.168.0.249/client/lib/bbb_deskshare.js" language="javascript"></script>
<script type="text/javascript" src="http://192.168.0.249/client/lib/bbb_api_bridge.js"></script>
<script type="text/javascript" src="http://192.168.0.249/client/lib/bbb_api_cam_preview.js"></script>
<script type="text/javascript" src="http://192.168.0.249/client/lib/bbb_api_cam_view.js"></script>
<script type="text/javascript" src="http://192.168.0.249/3rd-party.js"></script>
<script>
window.chatLinkClicked = function(url) {
window.open(url, '_blank');
window.focus();
}
window.displayBBBClient = function() {
var bbbc = document.getElementById("flashclient");
var wcpc = document.getElementById("webcampreviewclient");
wcpc.style.display = "none";
bbbc.style.display = "block";
}
window.displayWCClient = function() {
console.log("Displaying webcam preview client");
var wcpc = document.getElementById("webcampreview");
wcpc.style.display = "block";
}
window.onload = function() {
registerListeners();
}
</script>
</head>
<body>
<div id="controls">
<button type="button" onclick="registerListeners()">Listen for Events</button>
<button type="button" onclick="displayBBBClient()">Show BBB Client</button>
<button type="button" onclick="displayWCClient()">Show WC Client</button>
<button type="button" onclick="BBB.shareVideoCamera()">Share Webcam</button>
<button type="button" onclick="BBB.stopSharingCamera()">Stop Webcam</button>
<button type="button" onclick="BBB.switchPresenter('x8hxeozsqbk1')">Switch Presenter</button>
<button type="button" onclick="joinVoiceConference2()">Join Voice</button>
<button type="button" onclick="leaveVoiceConference2()">Leave Voice</button>
<button type="button" onclick="getMyUserID()">Get My UserID</button>
<button type="button" onclick="getMeetingID()">Get MeetingID</button>
<button type="button" onclick="getMyRoleAsynch()">Get My Role Asynch</button>
<button type="button" onclick="getMyRoleSynch()">Get My Role Synch</button>
<button type="button" onclick="muteMe()">Mute Me</button>
<button type="button" onclick="unmuteMe()">Unmute Me</button>
<button type="button" onclick="muteAll()">Mute All</button>
<button type="button" onclick="unmuteAll()">Unmute All</button>
<button type="button" onclick="raiseHand(true)">Raise Hand</button>
<button type="button" onclick="raiseHand(false)">Lower Hand</button>
<button type="button" onclick="switchLayout('S2SVideoChat')">Switch Video Layout</button>
<button type="button" onclick="switchLayout('S2SPresentation')">Switch Present Layout</button>
<button type="button" onclick="lockLayout(true)">Lock Layout</button>
<button type="button" onclick="lockLayout(false)">Unlock Layout</button>
<button type="button" onclick="sendPublicChat()">Send Public Chat</button>
<button type="button" onclick="sendPrivateChat()">Send Private Chat</button>
<button type="button" onclick="amIPresenterSync()">Am I Presenter Sync</button>
<button type="button" onclick="amIPresenterAsync()">Am I Presenter Async</button>
<button type="button" onclick="getMyUserInfoAsynch()">User Info Async</button>
<button type="button" onclick="getMyUserInfoSynch()">UserInfo Sync</button>
<button type="button" onclick="queryListOfPresentations()">Query Presentations</button>
<button type="button" onclick="displayPresentation('presentation3')">Display Presentation</button>
<button type="button" onclick="deletePresentation('presentation3')">Delete Presentation</button>
<form id="formUpload" name="formUpload" enctype="multipart/form-data">
<input type="file" name="fileUpload" id="fileUpload" />
<button type="button" onclick="uploadPresentation()">Upload Presentation</button>
</form>
</div>
<div id="webcampreview" style="background-color:#FFD700;height:240px;width:320px;float:left;">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540001" width="100%" height="100%" id="WebcamPreviewStandalone" name="WebcamPreviewStandalone" align="middle">
<param name="movie" value="http://192.168.0.249/client/WebcamPreviewStandalone.swf?v=VERSION" />
<param name="quality" value="high" />
<param name="allowfullscreen" value="true" />
<param name="bgcolor" value="#869ca7" />
<param name="wmode" value="window" />
<param name="allowScriptAccess" value="always" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="http://192.168.0.249/client/WebcamPreviewStandalone.swf?v=VERSION" width="100%" height="100%" align="middle">
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="always" />
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
</a>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
<div id="webcamview" style="background-color:#FFD700;height:240px;width:320px;float:left;">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540002" width="100%" height="100%" id="WebcamViewStandalone" name="WebcamViewStandalone" align="middle">
<param name="movie" value="http://192.168.0.249/client/WebcamViewStandalone.swf?v=VERSION" />
<param name="quality" value="high" />
<param name="allowfullscreen" value="true" />
<param name="bgcolor" value="#869ca7" />
<param name="wmode" value="window" />
<param name="allowScriptAccess" value="always" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="http://192.168.0.249/client/WebcamViewStandalone.swf?v=VERSION" width="100%" height="100%" align="middle">
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="always" />
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
</a>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
<div id="flashclient" style="background-color:#EEEEEE;height:900px;width:1200px;float:left;">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="50%" height="50%" id="BigBlueButton" name="BigBlueButton" align="middle">
<param name="movie" value="http://192.168.0.249/client/BigBlueButton.swf?v=VERSION" />
<param name="quality" value="high" />
<param name="allowfullscreen" value="true" />
<param name="bgcolor" value="#869ca7" />
<param name="wmode" value="window" />
<param name="allowScriptAccess" value="always" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="http://192.168.0.249/client/BigBlueButton.swf?v=VERSION" width="100%" height="90%" align="middle">
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="always" />
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
</a>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
<div id="update-display"/>
<div id="notifications" aria-live="polite" role="region" aria-label="Chat Notifications"></div>
</body>
</html>

View File

@ -0,0 +1,195 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css" media="screen">
html, body, #content { height:100%; }
body { margin:0; padding:0; overflow:hidden; }
#altContent { /* style alt content */ }
.visually-hidden {
position: absolute !important;
clip: rect(1px 1px, 1px, 1px);
clip: rect(1px, 1px, 1px, 1px);
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden;
}
#deployJavaPlugin {
display : none;
}
</style>
<script type="text/javascript" src="swfobject/swfobject.js"></script>
<script src="lib/deployJava.js?v=VERSION" language="javascript"></script>
<script type="text/javascript">
// Check for Firefox 41.0.1/2 to workaround Flash hang
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1210665
var ffHangWorkaround = function() {
if (navigator.userAgent.indexOf("Windows") != -1 &&
(navigator.userAgent.indexOf("Firefox/41.0") != -1 &&
navigator.buildID > "20150928" &&
navigator.buildID < "20151015")) {
console.log("Browser appears to be Firefox 41.0.1 or .2 on Windows");
return true;
}
return false;
};
//swfobject.registerObject("BigBlueButton", "11", "expressInstall.swf");
var flashvars = {};
var params = {};
params.quality = "high";
params.bgcolor = "#869ca7";
params.allowfullscreen = "true";
if (ffHangWorkaround()) {
console.log("Applying Firefox Flash hang workaround");
// wmode = opaque causes button clicks to be sometimes unresponsive,
// and right-click in particular is unreliable. It disables Flash
// permission prompts on Linux (causing webcams, flash voice to be
// unusable there). But it's better than a browser hang...
params.wmode = "opaque";
} else {
params.wmode = "window";
}
params.allowscriptaccess = "true";
params.seamlesstabbing = "true";
var attributes = {};
attributes.id = "BigBlueButton";
attributes.name = "BigBlueButton";
attributes.align = "middle";
attributes.tabIndex = 0;
swfobject.embedSWF("bbb-web-client.swf?v=VERSION", "altFlash", "100%", "100%", "11.0.0", "expressInstall.swf", flashvars, params, attributes, embedCallback);
function embedCallback(e) {
// Work around pixel alignment bug with Chrome 21 on Mac.
// See: http://code.google.com/p/bigbluebutton/issues/detail?id=1294
var objs = $('object');
objs.each(function(i, o) {
var o = $(o);
var top = o.offset().top;
var left = o.offset().left;
var roundtop = Math.round(top);
var roundleft = Math.round(left);
o.css("position", "relative");
if (roundtop === top) {
} else {
o.css("top", roundtop - top);
}
if (roundleft === left) {
} else {
o.css("left", roundleft - left);
}
});
}
</script>
<!--<script src="lib/jquery-1.5.1.min.js?v=VERSION" language="javascript"></script>-->
<script src="lib/jquery-2.1.1.min.js" language="javascript"></script>
<script src="lib/bbblogger.js?v=VERSION" language="javascript"></script>
<script src="lib/bigbluebutton.js?v=VERSION" language="javascript"></script>
<script src="lib/bbb_localization.js?v=VERSION" language="javascript"></script>
<script src="lib/bbb_blinker.js?v=VERSION" language="javascript"></script>
<script src="lib/bbb_screenshare.js" language="javascript"></script>
<!--<script src="lib/jquery.mobile.min.js" language="javascript"></script>-->
<script src="lib/jquery.json-2.4.min.js" language="javascript"></script>
<script src="lib/jquery.cookie.js" language="javascript"></script>
<!--<script src="lib/jquery.dataTables.min.js" language="javascript"></script>-->
<script src="lib/getScreenId.js" language="javascript"></script>
<script src="lib/jquery.FSRTC.js" language="javascript"></script>
<script src="lib/jquery.jsonrpcclient.js" language="javascript"></script>
<script src="lib/jquery.verto.js" language="javascript"></script>
<script src="lib/Screen-Capturing.js" language="javascript"></script>
<script src="lib/verto_extension.js" language="javascript"></script>
<script src="lib/verto_extension_share.js" language="javascript"></script>
<script src="lib/bbb_deskshare.js?v=VERSION" language="javascript"></script>
<script src="lib/bbb_api_bridge.js?v=VERSION" language="javascript"></script>
<script src="lib/sip.js?v=VERSION" language="javascript"></script>
<script src="lib/bbb_webrtc_bridge_sip.js?v=VERSION" language="javascript"></script>
<script src="lib/weburl_regex.js?v=VERSION" language="javascript"></script>
<script src="lib/jsnlog.min.js?v=VERSION" language="javascript"></script>
<script>
window.chatLinkClicked = function(url) {
window.open(url, '_blank');
window.focus();
}
</script>
<script type="text/javascript">
window.onload = function() {
var checkRequest = $.ajax({
dataType: 'json',
url: '/html5client/check'
});
checkRequest.done(function(data) {
if(typeof data.html5clientStatus !== "undefined" && data.html5clientStatus === "running" && document.getElementById('html5Section') != null) {
document.getElementById('html5Section').style.display='inherit';
}
});
};
function html5() {
// no Flash detected on the client
var originalPath, enterRequest, authToken, meetingId, userId;
originalPath = document.location.pathname;
// use the enter api to detect the meetingid, userid and authToken
// and reuse them to join via the HTML5 client
enterRequest = $.ajax({
dataType: 'json',
url: '/bigbluebutton/api/enter'
});
enterRequest.done(function(enterData) {
meetingId = enterData.response.meetingID;
userId = enterData.response.externUserID;
authToken = enterData.response.authToken;
if ((meetingId != null) && (userId != null) && (authToken != null)) {
// redirect to the html5 client with the received info
// format <IP>/html5client/<meetingId>/<userId>/<authToken>
document.location.pathname = "/html5client/"+meetingId+"/"+userId+"/"+authToken;
} else {
// go back to the redirection page
document.location.pathname = originalPath;
}
});
enterRequest.fail(function(enterData, textStatus, errorThrown){
BBBLog.debug("Enter request failed");
});
}
</script>
</head>
<body>
<div>
<audio id="remote-media" autoplay="autoplay"></audio>
<video id="localVertoVideo" autoplay="autoplay" style="display: none;">
<p>Your browser doesn't support HTML5 video.</p>
</video>
</div>
<div id="accessibile-progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="visually-hidden">0 %</div>
<button id="enterFlash" type="button" class="visually-hidden" onclick="startFlashFocus();">Set focus to client</button>
<div id="content">
<div id="altFlash" style="width:50%; margin-left: auto; margin-right: auto; ">
<h2>You need Flash installed and enabled in order to use the Flash client.</h2>
<br/>
<div style="width:50%; margin-left: auto; margin-right: auto; ">
<a href="http://www.adobe.com/go/getflashplayer">
<img src="get_flash_player.gif" alt="Get Adobe Flash player" />
</a>
<div id="html5Section" style="display:none">
<p style="margin-left:50px;" >OR</p>
<button type="button" onclick="html5();"><h3>Launch the HTML5 client instead</h3></button>
</div>
</div>
</div>
</div>
<div id="clientReady" aria-atomic="false" aria-live="polite" class="visually-hidden"></div>
</body>
</html>

View File

@ -0,0 +1,111 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- saved from url=(0014)about:internet -->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<!--
Smart developers always View Source.
This application was built using Adobe Flex, an open source framework
for building rich Internet applications that get delivered via the
Flash Player or to desktops via Adobe AIR.
Learn more about Flex at http://flex.org
// -->
<head>
<title>BigBlueButton</title>
<meta name="google" value="notranslate" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- Include CSS to eliminate any default margins/padding and set the height of the html element and
the body element to 100%, because Firefox, or any Gecko based browser, interprets percentage as
the percentage of the height of its parent container, which has to be set explicitly. Fix for
Firefox 3.6 focus border issues. Initially, don't display flashContent div so it won't show
if JavaScript disabled.
-->
<style type="text/css" media="screen">
html, body { height:100%; }
body { margin:0; padding:0; overflow:auto; text-align:center;
background-color: #ffffff; }
object:focus { outline:none; }
#flashContent { display:none; }
</style>
<!-- Enable Browser History by replacing useBrowserHistory tokens with two hyphens -->
<!-- BEGIN Browser History required section -->
<link rel="stylesheet" type="text/css" href="history/history.css" />
<script type="text/javascript" src="history/history.js"></script>
<!-- END Browser History required section -->
<script src="jquery-1.5.1.min.js" language="javascript"></script>
<script src="bigbluebutton.js" language="javascript"></script>
<script src="bbb_localization.js" language="javascript"></script>
<script src="deployJava.js" language="javascript"></script>
<script src="bbb_blinker.js" language="javascript"></script>
<script src="bbb_deskshare.js" language="javascript"></script>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
// For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection.
var swfVersionStr = "10.3.0";
// To use express install, set to playerProductInstall.swf, otherwise the empty string.
var xiSwfUrlStr = "playerProductInstall.swf";
var flashvars = {};
var params = {};
params.quality = "high";
params.bgcolor = "#ffffff";
params.allowscriptaccess = "sameDomain";
params.allowfullscreen = "true";
var attributes = {};
attributes.id = "BigBlueButton";
attributes.name = "BigBlueButton";
attributes.align = "middle";
swfobject.embedSWF(
"BigBlueButton.swf", "flashContent",
"100%", "100%",
swfVersionStr, xiSwfUrlStr,
flashvars, params, attributes);
// JavaScript enabled so display the flashContent div in case it is not replaced with a swf object.
swfobject.createCSS("#flashContent", "display:block;text-align:left;");
</script>
</head>
<body>
<!-- SWFObject's dynamic embed method replaces this alternative HTML content with Flash content when enough
JavaScript and Flash plug-in support is available. The div is initially hidden so that it doesn't show
when JavaScript is disabled.
-->
<div id="flashContent">
<p>
To view this page ensure that Adobe Flash Player version
10.3.0 or greater is installed.
</p>
<a href="http://www.adobe.com/go/getflashplayer"><img src="//www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player"></a>
</div>
<noscript>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%" id="BigBlueButton">
<param name="movie" value="BigBlueButton.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="BigBlueButton.swf" width="100%" height="100%">
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<!--<![endif]-->
<!--[if gte IE 6]>-->
<p>
Either scripts and active content are not permitted to run or Adobe Flash Player version
10.3.0 or greater is not installed.
</p>
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash Player" />
</a>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</noscript>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css" media="screen">
html, body, #content { height:100%; }
body { margin:0; padding:0; overflow:hidden; }
#altContent { /* style alt content */ }
</style>
<script type="text/javascript" src="swfobject/swfobject.js"></script>
<script type="text/javascript">
swfobject.registerObject("BigBlueButton", "10.3.0", "expressInstall.swf");
</script>
<script src="lib/jquery-2.1.1.min.js" language="javascript"></script>
<!--<script src="lib/jquery-1.5.1.min.js" language="javascript"></script>-->
<script src="lib/bigbluebutton.js" language="javascript"></script>
<script src="lib/bbb_localization.js" language="javascript"></script>
<script src="lib/bbb_blinker.js" language="javascript"></script>
<script src="lib/jquery.mobile.min.js" language="javascript"></script>
<script src="lib/jquery.json-2.4.min.js" language="javascript"></script>
<script src="lib/jquery.cookie.js" language="javascript"></script>
<script src="lib/jquery.dataTables.min.js" language="javascript"></script>
<script src="lib/getScreenId.js" language="javascript"></script>
<script src="lib/jquery.FSRTC.js" language="javascript"></script>
<script src="lib/jquery.jsonrpcclient.js" language="javascript"></script>
<script src="lib/jquery.verto.js" language="javascript"></script>
<script src="lib/Screen-Capturing.js" language="javascript"></script>
<script src="lib/verto_extension.js" language="javascript"></script>
<script src="lib/verto_extension_share.js" language="javascript"></script>
<script src="lib/bbb_deskshare.js" language="javascript"></script>
</head>
<body>
<div id="content">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%" id="BigBlueButton" name="BigBlueButton" align="middle">
<param name="movie" value="DeskshareStandalone.swf?v=VERSION" />
<param name="quality" value="high" />
<param name="allowfullscreen" value="true" />
<param name="bgcolor" value="#869ca7" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="DeskshareStandalone.swf?v=VERSION" width="100%" height="100%" align="middle">
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflashplayer">
<img src="//www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
</a>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
</body>
</html>

View File

@ -0,0 +1,45 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css" media="screen">
html, body, #content { height:100%; }
body { margin:0; padding:0; overflow:hidden; }
#altContent { /* style alt content */ }
</style>
<script type="text/javascript" src="swfobject/swfobject.js"></script>
<script type="text/javascript">
swfobject.registerObject("BigBlueButton", "11", "expressInstall.swf");
</script>
<script src="lib/jquery-1.5.1.min.js" language="javascript"></script>
<script src="lib/bigbluebutton.js" language="javascript"></script>
<script src="lib/bbb_localization.js" language="javascript"></script>
<script src="lib/bbb_blinker.js" language="javascript"></script>
<script src="lib/bbb_deskshare.js" language="javascript"></script>
</head>
<body>
<div id="controls"/>
<div id="content">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%" id="BigBlueButton" name="BigBlueButton" align="middle">
<param name="movie" value="BigBlueButton.swf?v=VERSION" />
<param name="quality" value="high" />
<param name="allowfullscreen" value="true" />
<param name="bgcolor" value="#869ca7" />
<param name="wmode" value="window" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="BigBlueButton.swf?v=VERSION" width="100%" height="100%" align="middle">
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflashplayer">
<img src="//www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
</a>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
<div id="notifications" aria-live="polite" role="region" aria-label="Chat Notifications"></div>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css" media="screen">
html, body, #content { height:100%; }
body { margin:0; padding:0; overflow:hidden; }
#altContent { /* style alt content */ }
</style>
<script type="text/javascript" src="swfobject/swfobject.js"></script>
<script type="text/javascript">
swfobject.registerObject("BigBlueButton", "10.3.0", "expressInstall.swf");
</script>
<script src="lib/jquery-1.5.1.min.js" language="javascript"></script>
<script src="lib/bigbluebutton.js" language="javascript"></script>
<script src="lib/bbb_localization.js" language="javascript"></script>
<script src="lib/bbb_blinker.js" language="javascript"></script>
<script src="lib/bbb_deskshare.js" language="javascript"></script>
</head>
<body>
<div id="content">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%" id="BigBlueButton" name="BigBlueButton" align="middle">
<param name="movie" value="ScreenshareStandalone.swf?v=VERSION" />
<param name="quality" value="high" />
<param name="allowfullscreen" value="true" />
<param name="bgcolor" value="#869ca7" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="DeskshareStandalone.swf?v=VERSION" width="100%" height="100%" align="middle">
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
</a>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,31 @@
<?xml version="1.0" ?>
<info>
<returncode>SUCCESS</returncode>
<created>2010-05-12 20:57</created>
<topbar>
<components>
<label>
<htmlLabel><![CDATA[<b>Dial In Numbers:</b>]]></htmlLabel>
</label>
<combobox>
<array>
<value>+1 (254) 555-1212</value>
<value>+1 (830) 555-1212</value>
<value>+1 (504) 555-1212</value>
<value>+1 (957) 555-1212</value>
</array>
</combobox>
<label>
<htmlLabel><![CDATA[<b>Moderator PIN: 111222</b>]]></htmlLabel>
</label>
<label>
<htmlLabel><![CDATA[<b>Attendee PIN: 222333</b>]]></htmlLabel>
</label>
<button label="Help" url="http://bigbluebutton.org" />
</components>
</topbar>
</info>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,110 @@
<?xml version="1.0"?>
<layouts>
<layout name="bbb.layout.name.defaultlayout" default="true">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="PresentationWindow" width="0.513" height="0.684" x="0.180" y="0" />
<window name="CaptionWindow" width="0.513" height="0.308" x="0.180" y="0.692" />
<window name="VideoDock" width="0.177" height="0.308" x="0" y="0.687" minWidth="280" />
<window name="ChatWindow" width="0.304" height="1" x="0.696" y="0" />
<window name="UsersWindow" width="0.177" height="0.679" x="0" y="0" minWidth="280" />
</layout>
<layout name="bbb.layout.name.videochat">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="VideoDock" width="1" height="1" x="0" y="0" order="0"/>
<window name="ChatWindow" width="0.303125" height="0.9955703211517165" x="0.3229166666666667" y="0.9656699889258029" order="4" hidden="true" />
<window name="PresentationWindow" minimized="true" order="1" hidden="true" />
<window name="UsersWindow" minimized="true" hidden="true" order="2"/>
</layout>
<layout name="bbb.layout.name.webcamsfocus">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="VideoDock" width="0.6570188133140377" height="0.9960106382978723" x="0" y="0" />
<window name="ChatWindow" width="0.3393632416787265" height="0.5305851063829787" x="0.658465991316932" y="0" />
<window name="UsersWindow" hidden="true" />
<window name="PresentationWindow" width="0.34008683068017365" height="0.4601063829787234" x="0.658465991316932" y="0.535904255319149" />
</layout>
<layout name="bbb.layout.name.presentfocus">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="UsersWindow" minimized="true" />
<window name="VideoDock" width="0.2923611111111111" height="0.4640957446808511" x="0.7048611111111112" y="0.535904255319149" />
<window name="PresentationWindow" width="0.7027777777777777" height="0.9986702127659575" x="0" y="0" />
<window name="ChatWindow" width="0.2923611111111111" height="0.5305851063829787" x="0.7048611111111112" y="0" />
</layout>
<layout name="bbb.layout.name.lectureassistant">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="ChatWindow" width="0.4597222222222222" height="0.9958677685950413" x="0.2263888888888889" y="0" />
<window name="UsersWindow" width="0.22152777777777777" height="0.9958677685950413" x="0" y="0" minWidth="280" />
<window name="PresentationWindow" width="0.3104166666666667" height="0.5537190082644629" x="0.6895833333333333" y="0" />
<window name="VideoDock" width="0.30972222222222223" height="0.4357198347107438" x="0.6902777777777778" y="0.558870523415978" />
</layout>
<layout name="bbb.layout.name.lecture">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="UsersWindow" hidden="true" />
<window name="VideoDock" width="0.2923611111111111" height="0.4640957446808511" x="0.7048611111111112" y="0.535904255319149" />
<window name="PresentationWindow" width="0.7027777777777777" height="0.9986702127659575" x="0" y="0" />
<window name="ChatWindow" width="0.2923611111111111" height="0.5305851063829787" x="0.7048611111111112" y="0" />
</layout>
<layout name="bbb.layout.name.lecture" role="presenter">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="ChatWindow" hidden="true" />
<window name="UsersWindow" hidden="true" />
<window name="PresentationWindow" maximized="true" />
<window name="VideoDock" hidden="true" />
</layout>
<layout name="bbb.layout.name.lecture" role="moderator">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="ChatWindow" width="0.4597222222222222" height="0.9958677685950413" x="0.2263888888888889" y="0" />
<window name="UsersWindow" width="0.22152777777777777" height="0.9944903581267218" x="0" y="0" minWidth="280" />
<window name="PresentationWindow" width="0.3104166666666667" height="0.5537190082644629" x="0.6895833333333333" y="0" />
<window name="VideoDock" width="0.30972222222222223" height="0.4256198347107438" x="0.6902777777777778" y="0.568870523415978" />
</layout>
<!--
<layout name="Users">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="UsersWindow" width="0.1772793053545586" height="0.6795212765957446" x="0" y="0" />
<window name="PresentationWindow" width="0.5137481910274964" height="0.9946808510638298" x="0.18017366136034732" y="0" />
<window name="VideoDock" width="0.1772793053545586" height="0.30851063829787234" x="0" y="0.6875" />
<window name="ChatWindow" width="0.3031837916063676" height="0.9960106382978723" x="0.6968162083936325" y="0" />
</layout>
<layout name="S2SPresentation">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="ChatWindow" hidden="true" draggable="false" resizable="false"/>
<window name="UsersWindow" hidden="true" draggable="false" resizable="false"/>
<window name="PresentationWindow" width="0.8" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="VideoDock" hidden="true" draggable="false" resizable="false"/>
</layout>
<layout name="S2SVideoChat">
<window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
<window name="UsersWindow" hidden="true" draggable="false" resizable="false"/>
<window name="VideoDock" width="1" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="ChatWindow" hidden="true" draggable="false" resizable="false"/>
<window name="PresentationWindow" hidden="true" draggable="false" resizable="false"/>
</layout>
<layout name="Notes">
<window name="NotesWindow" hidden="false" width="0.7" height="0.4" x="0" y="0.6" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="false" width="0.7" height="0.6" x="0" y="0" draggable="false" resizable="false"/>
<window name="UsersWindow" hidden="true" draggable="false" resizable="false"/>
<window name="VideoDock" hidden="true" draggable="false" resizable="false"/>
<window name="ChatWindow" width="0.3" height="1" x="0.7" y="0" draggable="false" resizable="false"/>
<window name="PresentationWindow" hidden="true" draggable="false" resizable="false"/>
</layout>
<layout name="Broadcast">
<window name="NotesWindow" hidden="false" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
<window name="BroadcastWindow" hidden="false" width="0.7" height="0.9" x="0" y="0" draggable="false" resizable="false"/>
<window name="UsersWindow" hidden="true" draggable="false" resizable="false"/>
<window name="VideoDock" hidden="true" draggable="false" resizable="false"/>
<window name="ChatWindow" width="0.3" height="1" x="0.7" y="0" draggable="false" resizable="false"/>
<window name="PresentationWindow" hidden="true" draggable="false" resizable="false"/>
</layout>
-->
</layouts>

View File

@ -0,0 +1,347 @@
var presenterUserID = "";
var registerListeners = function() {
console.log("Listening for events.");
BBB.listen("QueryPresentationsReplyEvent", function(bbbEvent) {
console.log("Number of presentations [" + bbbEvent.presentations.length + "]. First presentation [" + bbbEvent.presentations[0] + "].");
});
BBB.listen("OpenExternalFileUploadWindowEvent", function(bbbEvent) {
console.log("Open file upload dialog. Max file size is [" + bbbEvent.maxFileSize + "].");
});
BBB.listen("UserKickedOutEvent", function(bbbEvent) {
console.log("User has been kicked [" + bbbEvent.userID + "].");
});
BBB.listen("SwitchedLayoutEvent", function(bbbEvent) {
console.log("New Layout [" + bbbEvent.layoutID + "].");
});
BBB.listen("NewRoleEvent", function(bbbEvent) {
console.log("New Role Event [amIPresenter=" + bbbEvent.amIPresenter + ",role=" + bbbEvent.role + ",newPresenterUserID=" + bbbEvent.newPresenterUserID + "].");
});
BBB.listen("SwitchedPresenterEvent", function(bbbEvent) {
console.log("Switched Presenter [amIPresenter=" + bbbEvent.amIPresenter + ",role=" + bbbEvent.role + ",newPresenterUserID=" + bbbEvent.newPresenterUserID + "].");
presenterUserID = bbbEvent.newPresenterUserID;
if (bbbEvent.amIPresenter) {
console.log("*** I am presenter. Am I publishing webcam?");
BBB.listen("AmISharingCamQueryResponse", function(bbbEvent2) {
console.log("AmISharingCamQueryResponse [isPublishing=" + bbbEvent2.isPublishing + ",camIndex=" + bbbEvent2.camIndex + "]");
});
BBB.amISharingWebcam();
BBB.amISharingWebcam(function(bbbEvent3) {
console.log("amISharingWebcam [isPublishing=" + bbbEvent3.isPublishing
+ ",camIndex=" + bbbEvent3.camIndex
+ ",camWidth=" + bbbEvent3.camWidth
+ ",camHeight=" + bbbEvent3.camHeight
+ ",camKeyFrameInterval=" + bbbEvent3.camKeyFrameInterval
+ ",camModeFps=" + bbbEvent3.camModeFps
+ ",camQualityBandwidth=" + bbbEvent3.camQualityBandwidth
+ ",camQualityPicture=" + bbbEvent3.camQualityPicture
+ "]");
if (bbbEvent3.isPublishing) {
CAM_PREVIEW.stopPreviewCamera(bbbEvent3.avatarURL);
CAM_PREVIEW.previewCamera(bbbEvent3.camIndex, bbbEvent3.camWidth, bbbEvent3.camHeight, bbbEvent3.camKeyFrameInterval,
bbbEvent3.camModeFps, bbbEvent3.camQualityBandwidth, bbbEvent3.camQualityPicture, bbbEvent3.avatarURL);
}
});
} else {
console.log("*** I am NOT presenter. Is new presenter publishing webcam?");
BBB.listen("IsUserPublishingCamResponse", function(bbbEvent4) {
console.log("IsUserPublishingCamResponse [isUserPublishing=" + bbbEvent4.isUserPublishing
+ ",uri=" + bbbEvent4.uri
+ ",streamName=" + bbbEvent4.streamName + "]");
});
BBB.isUserSharingWebcam(bbbEvent.newPresenterUserID);
BBB.isUserSharingWebcam(bbbEvent.newPresenterUserID, function(bbbEvent5) {
console.log("isUserSharingWebcam [isUserPublishing=" + bbbEvent5.isUserPublishing
+ ",uri=" + bbbEvent5.uri
+ ",streamName=" + bbbEvent5.streamName + "]");
if (presenterUserID == bbbEvent.userID) {
CAM_VIEW.stopViewWebcamStream(bbbEvent.avatarURL);
CAM_VIEW.viewWebcamStream(bbbEvent.uri, bbbEvent.streamName, bbbEvent5.avatarURL);
}
});
CAM_PREVIEW.stopPreviewCamera(bbbEvent.avatarURL);
}
});
BBB.listen("UserLeftEvent", function(bbbEvent) {
console.log("User [" + bbbEvent.userID + "] has left.");
});
BBB.listen("UserJoinedEvent", function(bbbEvent) {
console.log("User [" + bbbEvent.userID + ", [" + bbbEvent.userName + "] has joined.");
});
BBB.listen("NewPublicChatEvent", function(bbbEvent) {
console.log("Received NewPublicChatEvent [" + bbbEvent.message + "]");
});
BBB.listen("NewPrivateChatEvent", function(bbbEvent) {
console.log("Received NewPrivateChatEvent event");
});
BBB.listen("UserJoinedVoiceEvent", function(bbbEvent) {
console.log("User [" + bbbEvent.userID + "] had joined the voice conference.");
});
BBB.listen("UserLeftVoiceEvent", function(bbbEvent) {
console.log("User [" + bbbEvent.userID + "has left the voice conference.");
});
BBB.listen("UserVoiceMutedEvent", function(bbbEvent) {
console.log("User [" + bbbEvent.userID + "] is muted [" + bbbEvent.muted + "]");
});
BBB.listen("UserLockedVoiceEvent", function(bbbEvent) {
console.log("User [" + bbbEvent.userID + "] is locked [" + bbbEvent.locked + "]");
});
BBB.listen("CamStreamSharedEvent", function(bbbEvent) {
console.log("User CamStreamSharedEvent [" + bbbEvent.uri + "," + bbbEvent.streamName + "]");
if (presenterUserID == bbbEvent.userID) {
CAM_VIEW.stopViewWebcamStream(bbbEvent.avatarURL);
CAM_VIEW.viewWebcamStream(bbbEvent.uri, bbbEvent.streamName, bbbEvent.avatarURL);
}
});
BBB.listen("BroadcastingCameraStartedEvent", function(bbbEvent) {
console.log("User BroadcastingCameraStartedEvent [" + bbbEvent.camIndex + "] [" + bbbEvent.camWidth + "]");
if (bbbEvent.isPresenter) {
CAM_PREVIEW.stopPreviewCamera(bbbEvent.avatarURL);
CAM_PREVIEW.previewCamera(bbbEvent.camIndex, bbbEvent.camWidth, bbbEvent.camHeight, bbbEvent.camKeyFrameInterval,
bbbEvent.camModeFps, bbbEvent.camQualityBandwidth, bbbEvent.camQualityPicture, bbbEvent.avatarURL);
}
});
BBB.listen("BroadcastingCameraStoppedEvent", function(bbbEvent) {
console.log("User BroadcastingCameraStoppedEvent ]");
CAM_PREVIEW.stopPreviewCamera(bbbEvent.avatarURL);
});
console.log("Listen Presentation Updates");
BBB.listen("OfficeDocConversionSuccessEvent", function(bbbEvent) {
console.log("Successfully converted Office document. : " + JSON.stringify(bbbEvent));
});
BBB.listen("OfficeDocConversionFailedEvent", function(bbbEvent) {
console.log("Failed to convert Office document. : " + JSON.stringify(bbbEvent));
});
BBB.listen("SupportedDocEvent", function(bbbEvent) {
console.log("Uploaded presentation file type is supported. : " + JSON.stringify(bbbEvent));
});
BBB.listen("UnsupportedDocEvent", function(bbbEvent) {
console.log("Uploaded presentation file type is unsupported. : " + JSON.stringify(bbbEvent));
});
BBB.listen("PageCountFailedEvent", function(bbbEvent) {
console.log("Failed to determine number of pages for the uploaded presentation. : " + JSON.stringify(bbbEvent));
});
BBB.listen("ThumbnailsUpdateEvent", function(bbbEvent) {
console.log("Generating thumbnails for uploaded presentation. : " + JSON.stringify(bbbEvent));
});
BBB.listen("PageCountExceededEvent", function(bbbEvent) {
console.log("Uploaded presentation had exceeded max number of pages. : " + JSON.stringify(bbbEvent));
});
BBB.listen("ConversionSuccessEvent", function(bbbEvent) {
console.log("Successfully converted uploaded presentation. : " + JSON.stringify(bbbEvent));
});
BBB.listen("ConversionProgressEvent", function(bbbEvent) {
console.log("Progress update on conversion process. : " + JSON.stringify(bbbEvent));
});
}
var leaveVoiceConference2 = function () {
BBB.leaveVoiceConference();
}
var joinVoiceConference2 = function () {
BBB.joinVoiceConference();
}
var amIPresenterAsync = function() {
BBB.listen("AmIPresenterQueryResponse", function(bbbEvent) {
console.log("Received AmIPresenterQueryResponse event [" + bbbEvent.amIPresenter + "]");
});
BBB.amIPresenter();
}
var amIPresenterSync = function() {
BBB.amIPresenter(function(amIPresenter) {
console.log("Am I Presenter = " + amIPresenter);
});
}
var getMyUserInfoAsynch = function() {
BBB.listen("GetMyUserInfoResponse", function(bbbEvent) {
console.log("User info response [myUserID=" + bbbEvent.myUserID
+ ",myUsername=" + bbbEvent.myUsername + ",myAvatarURL=" + bbbEvent.myAvatarURL
+ ",myRole=" + bbbEvent.myRole + ",amIPresenter=" + bbbEvent.amIPresenter
+ ",dialNumber=" + bbbEvent.dialNumber + ",voiceBridge=" + bbbEvent.voiceBridge + "].");
for(var key in bbbEvent.customdata){
console.log(key + " " + bbbEvent.customdata[key]);
}
});
BBB.getMyUserInfo();
}
var getMyUserInfoSynch = function() {
BBB.getMyUserInfo(function(userInfo) {
console.log("User info callback [myUserID=" + userInfo.myUserID
+ ",myUsername=" + userInfo.myUsername + ",myAvatarURL=" + userInfo.myAvatarURL
+ ",myRole=" + userInfo.myRole + ",amIPresenter=" + userInfo.amIPresenter
+ ",dialNumber=" + userInfo.dialNumber + ",voiceBridge=" + userInfo.voiceBridge + "].");
for(var key in userInfo.customdata){
console.log(key + " " + userInfo.customdata[key]);
}
});
}
var getMyRoleAsynch = function() {
BBB.listen("GetMyRoleResponse", function(bbbEvent) {
console.log("Received GetMyRoleResponse event [" + bbbEvent.myRole + "]");
});
BBB.getMyRole();
}
var getMyRoleSynch = function() {
BBB.getMyRole(function(myRole) {
console.log("My role = " + myRole);
});
}
var getMyUserID = function() {
BBB.getMyUserID(function(userID) {
console.log("My user ID = [" + userID + "]");
});
}
var getMeetingID = function() {
BBB.getMeetingID(function(meetingID) {
console.log("Meeting ID = [" + meetingID + "]");
});
}
var emojiStatus = function(emojiStatus) {
BBB.emojiStatus(emojiStatus);
}
var muteMe = function() {
BBB.muteMe();
}
var unmuteMe = function() {
BBB.unmuteMe();
}
var muteAll = function() {
BBB.muteAll();
}
var unmuteAll = function() {
BBB.unmuteAll();
}
var switchLayout = function(newLayout) {
BBB.switchLayout(newLayout);
}
var lockLayout = function(lock) {
BBB.lockLayout(lock);
}
var queryListOfPresentations = function() {
BBB.queryListOfPresentations();
}
var displayPresentation = function(presentationID) {
BBB.displayPresentation(presentationID);
}
var deletePresentation = function(presentationID) {
BBB.deletePresentation(presentationID);
}
var sendPublicChat = function () {
var message = "Hello from the Javascript API";
BBB.sendPublicChatMessage('0x7A7A7A', "en", message);
}
var sendPrivateChat = function () {
var message = "ECHO: " + bbbEvent.message;
BBB.sendPrivateChatMessage(bbbEvent.fromColor, bbbEvent.fromLang, message, bbbEvent.fromUserID);
}
var webcamViewStandaloneAppReady = function() {
console.log("WebcamViewStandalone App is ready.");
BBB.getPresenterUserID(function(puid) {
if (puid == "") {
console.log("There is no presenter in the meeting");
} else {
console.log("The presenter user id is [" + puid + "]");
// Is presenter sharing webcam? If so, get the webcam stream and display.
}
});
}
var webcamPreviewStandaloneAppReady = function() {
console.log("WebcamPreviewStandalone App is ready.");
BBB.getPresenterUserID(function(puid) {
if (puid == "") {
console.log("There is no presenter in the meeting");
} else {
console.log("The presenter user id is [" + puid + "]");
}
});
// Am I presenter? If so, am I publishing my camera? If so, display my camera.
}
var uploadPresentation = function() {
console.log("uploadPresentation");
BBB.getInternalMeetingID(function(meetingID) {
var formData = new FormData($('form')[0]);
formData.append("presentation_name", document.getElementById('fileUpload').value.split(/(\\|\/)/g).pop());
formData.append("conference", meetingID);
formData.append("room", meetingID);
$.ajax({
url: '/bigbluebutton/presentation/upload', //server script to process data
type: 'POST',
xhr: function() { // custom xhr
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // check if upload property exists
myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // for handling the progress of the upload
}
return myXhr;
},
//Ajax events
success: completeHandler,
error: errorHandler,
// Form data
data: formData,
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false
});
});
}
function progressHandlingFunction(e){
if(e.lengthComputable){
console.log("progress: loaded " + e.loaded + " total:" + e.total);
}
}
function completeHandler(e){
$('form')[0].reset();
console.log("you file has been uploaded!");
}
function errorHandler(e){
console.log("There was an error uploading your file.");
}

View File

@ -0,0 +1,159 @@
// Last time updated at January 07, 2016
// By Daniel Perrone (perroned)
// Latest file can be found here: https://cdn.webrtc-experiment.com/Screen-Capturing.js
// Muaz Khan - www.MuazKhan.com
// MIT License - www.WebRTC-Experiment.com/licence
// Documentation - https://github.com/muaz-khan/Chrome-Extensions/tree/master/Screen-Capturing.js
// Demo - https://www.webrtc-experiment.com/Screen-Capturing/
// ___________________
// Screen-Capturing.js
// Source code: https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture
// Google AppStore installation path: https://chrome.google.com/webstore/detail/screen-capturing/ajhifddimkapgcifgcodmmfdlknahffk
// This JavaScript file is aimed to explain steps needed to integrate above chrome extension
// in your own webpages
// Usage:
// getScreenConstraints(function(screen_constraints) {
// navigator.webkitGetUserMedia({ video: screen_constraints }, onSuccess, onFailure );
// });
// First Step: Download the extension, modify "manifest.json" and publish to Google AppStore
// https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture#how-to-publish-yourself
// Second Step: Listen for postMessage handler
// postMessage is used to exchange "sourceId" between chrome extension and you webpage.
// though, there are tons other options as well, e.g. XHR-signaling, websockets, etc.
window.addEventListener('message', function(event) {
if (event.origin != window.location.origin) {
return;
}
onMessageCallback(event.data);
});
// and the function that handles received messages
function onMessageCallback(data) {
// "cancel" button is clicked
if (data == 'PermissionDeniedError') {
chromeMediaSource = 'PermissionDeniedError';
if (screenCallback) return screenCallback('PermissionDeniedError');
else throw new Error('PermissionDeniedError');
}
// extension notified his presence
if (data == 'rtcmulticonnection-extension-loaded') {
chromeMediaSource = 'desktop';
}
// extension shared temp sourceId
if (data.sourceId && screenCallback) {
screenCallback(sourceId = data.sourceId);
}
}
// global variables
var chromeMediaSource = 'screen';
var sourceId;
var screenCallback;
// this method can be used to check if chrome extension is installed & enabled.
function isChromeExtensionAvailable(callback) {
if (!callback) return;
if (chromeMediaSource == 'desktop') return callback(true);
// ask extension if it is available
window.postMessage('are-you-there', '*');
setTimeout(function() {
if (chromeMediaSource == 'screen') {
callback(false);
} else callback(true);
}, 2000);
}
// this function can be used to get "source-id" from the extension
function getSourceId(callback) {
if (!callback) throw '"callback" parameter is mandatory.';
if(sourceId) return callback(sourceId);
screenCallback = callback;
window.postMessage('get-sourceId', '*');
}
var isFirefox = typeof window.InstallTrigger !== 'undefined';
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
var isChrome = !!window.chrome && !isOpera;
function getChromeExtensionStatus(extensionid, callback) {
callback = normalizeCallback(callback);
if (isFirefox) return callback('not-chrome');
if (chromeMediaSource == 'desktop') return callback('installed-enabled');
if (arguments.length != 2) {
callback = extensionid;
extensionid = 'ajhifddimkapgcifgcodmmfdlknahffk'; // Muaz Khan's Screen Capturing
}
var image = document.createElement('img');
image.src = 'chrome-extension://' + extensionid + '/icon.png';
image.onload = function() {
chromeMediaSource = 'screen';
window.postMessage('are-you-there', '*');
setTimeout(function() {
callback('installed-enabled');
}, 2000);
};
image.onerror = function() {
callback('not-installed');
};
}
// this function explains how to use above methods/objects
function getScreenConstraints(callback) {
var firefoxScreenConstraints = {
mozMediaSource: 'window',
mediaSource: 'window'
};
if(isFirefox) return callback(null, firefoxScreenConstraints);
// this statement defines getUserMedia constraints
// that will be used to capture content of screen
var screen_constraints = {
mandatory: {
chromeMediaSource: chromeMediaSource,
maxWidth: screen.width > 1920 ? screen.width : 1920,
maxHeight: screen.height > 1080 ? screen.height : 1080
},
optional: []
};
// this statement verifies chrome extension availability
// if installed and available then it will invoke extension API
// otherwise it will fallback to command-line based screen capturing API
sourceId = null;
if (chromeMediaSource == 'desktop') {
getSourceId(function() {
screen_constraints.mandatory.chromeMediaSourceId = sourceId;
callback(sourceId == 'PermissionDeniedError' ? sourceId : null, screen_constraints);
});
return;
}
// this statement sets gets 'sourceId" and sets "chromeMediaSourceId"
if (chromeMediaSource == 'desktop') {
screen_constraints.mandatory.chromeMediaSourceId = sourceId;
}
// now invoking native getUserMedia API
callback(null, screen_constraints);
}

View File

@ -0,0 +1,652 @@
/**
This file contains the BigBlueButton client APIs that will allow 3rd-party applications
to embed the Flash client and interact with it through Javascript.
HOW TO USE:
Some APIs allow synchronous and asynchronous calls. When using asynchronous, the 3rd-party
JS should register as listener for events listed at the bottom of this file. For synchronous,
3rd-party JS should pass in a callback function when calling the API.
For an example on how to use these APIs, see:
https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/resources/prod/lib/3rd-party.js
https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/resources/prod/3rd-party.html
*/
(function(window, undefined) {
var BBB = {};
/**
* Internal function to get the BBB embed object. Seems like we have to do this
* each time and can't create a var for it.
*
* To get the object, see https://code.google.com/p/swfobject/wiki/api
*/
function getSwfObj() {
return swfobject.getObjectById("BigBlueButton");
}
/**
* Query if the current user is sharing webcam.
*
* Param:
* callback - function to return the result
*
* If you want to instead receive an event with the result, register a listener
* for AM_I_SHARING_CAM_RESP (see below).
*
*/
BBB.amISharingWebcam = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
if (arguments.length == 0) {
swfObj.amISharingCameraRequestAsync();
} else {
if (typeof callback === 'function') {
callback(swfObj.amISharingCameraRequestSync());
}
}
}
}
/**
* Query if another user is sharing her camera.
*
* Param:
* userID : the id of the user that may be sharing the camera
* callback: function if you want to be informed synchronously. Don't pass a function
* if you want to be informed through an event. You have to register for
* IS_USER_PUBLISHING_CAM_RESP (see below).
*/
BBB.isUserSharingWebcam = function(userID, callback) {
var swfObj = getSwfObj();
if (swfObj) {
if (arguments.length == 1) {
swfObj.isUserPublishingCamRequestAsync(userID);
} else {
if (arguments.length == 2 && typeof callback === 'function') {
callback(swfObj.isUserPublishingCamRequestSync(userID));
}
}
}
}
/**
* Raise user's hand.
*
* Param:
* emojiStatus - [string]
*
*/
BBB.emojiStatus = function(emojiStatus) {
var swfObj = getSwfObj();
if (swfObj) {
console.log("Request to change emoji status [" + emojiStatus + "]");
swfObj.emojiStatusRequest(emojiStatus);
}
}
/**
* Issue a switch presenter command.
*
* Param:
* newPresenterUserID - the user id of the new presenter
*
* 3rd-party JS must listen for SWITCHED_PRESENTER (see below) to get notified
* of switch presenter events.
*
*/
BBB.switchPresenter = function(newPresenterUserID) {
var swfObj = getSwfObj();
if (swfObj) {
console.log("Request to switch presenter to [" + newPresenterUserID + "]");
swfObj.switchPresenterRequest(newPresenterUserID);
}
}
/**
* Query if current user is presenter.
*
* Params:
* callback - function if you want a callback as response. Otherwise, you need to listen
* for AM_I_PRESENTER_RESP (see below).
*/
BBB.amIPresenter = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
if (arguments.length == 0) {
swfObj.amIPresenterRequestAsync();
} else {
if (typeof callback === 'function') {
callback(swfObj.amIPresenterRequestSync());
}
}
}
}
/**
* Eject a user.
*
* Params:
* userID - userID of the user you want to eject.
*/
BBB.ejectUser = function(userID) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.ejectUserRequest(userID);
}
}
/**
* Query who is presenter.
*
* Params:
* callback - function that gets executed for the response.
*/
BBB.getPresenterUserID = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
if (typeof callback === 'function') {
callback(swfObj.getPresenterUserID());
}
}
}
/**
* Query the current user's role.
* Params:
* callback - function if you want a callback as response. Otherwise, you need to listen
* for GET_MY_ROLE_RESP (see below).
*/
BBB.getMyRole = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
if (arguments.length == 0) {
swfObj.getMyRoleRequestAsync();
} else {
if (typeof callback === 'function') {
callback(swfObj.getMyRoleRequestSync());
}
}
}
}
/**
* Query the current user's id.
*
* Params:
* callback - function that gets executed for the response.
*/
BBB.getMyUserID = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
console.log("Getting my userID");
if (typeof callback === 'function') {
callback(swfObj.getMyUserID());
}
}
}
/**
* Query the current user's role.
* Params:
* callback - function if you want a callback as response. Otherwise, you need to listen
* for GET_MY_ROLE_RESP (see below).
*/
BBB.getMyUserInfo = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
if (arguments.length == 0) {
swfObj.getMyUserInfoAsync();
} else {
if (typeof callback === 'function') {
callback(swfObj.getMyUserInfoSync());
}
}
}
}
/**
* Query the meeting id.
*
* Params:
* callback - function that gets executed for the response.
*/
BBB.getMeetingID = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
console.log("Getting external meetingID");
if (typeof callback === 'function') {
callback(swfObj.getExternalMeetingID());
}
}
}
BBB.getInternalMeetingID = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
console.log("Getting internal meetingID");
if (typeof callback === 'function') {
callback(swfObj.getInternalMeetingID());
}
}
}
/**
* Join the voice conference.
*/
BBB.joinVoiceConference = function() {
var swfObj = getSwfObj();
if (swfObj) {
console.log("Joining voice");
swfObj.joinVoiceRequest();
}
}
/**
* Leave the voice conference.
*/
BBB.leaveVoiceConference = function() {
var swfObj = getSwfObj();
if (swfObj) {
console.log("Leave voice");
swfObj.leaveVoiceRequest();
}
}
/**
* Share user's webcam.
*
* Params:
* publishInClient : (DO NOT USE - Unimplemented)
*/
BBB.shareVideoCamera = function(publishInClient) {
var swfObj = getSwfObj();
if (swfObj) {
if (typeof publishInClient === 'boolean') {
swfObj.shareVideoCamera(publishInClient);
} else {
swfObj.shareVideoCamera();
}
}
}
/**
* Stop share user's webcam.
*
*/
BBB.stopSharingCamera = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.stopShareCameraRequest();
}
}
/**
* Mute the current user.
*
*/
BBB.muteMe = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.muteMeRequest();
}
}
/**
* Unmute the current user.
*
*/
BBB.unmuteMe = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.unmuteMeRequest();
}
}
/**
* Mute all the users.
*
*/
BBB.muteAll = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.muteAllUsersRequest();
}
}
/**
* Unmute all the users.
*
*/
BBB.unmuteAll = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.unmuteAllUsersRequest();
}
}
/**
* Switch to a new layout.
*
* Param:
* newLayout : name of the layout as defined in layout.xml (found in /var/www/bigbluebutton/client/conf/layout.xml)
*
*/
BBB.switchLayout = function(newLayout) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.switchLayout(newLayout);
}
}
/**
* Lock the layout.
*
* Locking the layout means that users will have the same layout with the moderator that issued the lock command.
* Other users won't be able to move or resize the different windows.
*/
BBB.lockLayout = function(lock) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.lockLayout(lock);
}
}
/**
* Request to send a public chat
* fromUserID - the external user id for the sender
* fontColor - the color of the font to display the message
* localeLang - the 2-char locale code (e.g. en) for the sender
* message - the message to send
*/
BBB.sendPublicChatMessage = function(fontColor, localeLang, message) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.sendPublicChatRequest(fontColor, localeLang, message);
}
}
/**
* Request to send a private chat
* fromUserID - the external user id for the sender
* fontColor - the color of the font to display the message
* localeLang - the 2-char locale code (e.g. en) for the sender
* message - the message to send
* toUserID - the external user id of the receiver
*/
BBB.sendPrivateChatMessage = function(fontColor, localeLang, message, toUserID) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.sendPrivateChatRequest(fontColor, localeLang, message, toUserID);
}
}
/**
* Request to display a presentation.
* presentationID - the presentation to display
*/
BBB.displayPresentation = function(presentationID) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.displayPresentationRequest(presentationID);
}
}
/**
* Query the list of uploaded presentations.
*/
BBB.queryListOfPresentations = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.queryListsOfPresentationsRequest();
}
}
/**
* Request to delete a presentation.
* presentationID - the presentation to delete
*/
BBB.deletePresentation = function(presentationID) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.deletePresentationRequest(presentationID);
}
}
/**
*
*/
BBB.webRTCCallStarted = function(inEchoTest) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCCallStarted(inEchoTest);
}
}
BBB.webRTCCallConnecting = function(inEchoTest) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCCallConnecting(inEchoTest);
}
}
BBB.webRTCCallEnded = function(inEchoTest) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCCallEnded(inEchoTest);
}
}
BBB.webRTCCallFailed = function(inEchoTest, errorcode, cause) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCCallFailed(inEchoTest, errorcode, cause);
}
}
BBB.webRTCCallWaitingForICE = function(inEchoTest) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCCallWaitingForICE(inEchoTest);
}
}
BBB.webRTCCallTransferring = function(inEchoTest) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCCallTransferring(inEchoTest);
}
}
BBB.webRTCCallProgressCallback = function(progress) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCCallProgressCallback(progress);
}
}
BBB.webRTCMediaRequest = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCMediaRequest();
}
}
BBB.webRTCMediaSuccess = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCMediaSuccess();
}
}
BBB.webRTCMediaFail = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.webRTCMediaFail();
}
}
BBB.javaAppletLaunched = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.javaAppletLaunched();
}
}
// Third-party JS apps should use this to query if the BBB SWF file is ready to handle calls.
BBB.isSwfClientReady = function() {
return swfReady;
}
/* ***********************************************************************************
* Broadcasting of events to 3rd-party apps.
*************************************************************************************/
/** Stores the 3rd-party app event listeners ***/
var listeners = {};
/**
* 3rd-party apps should user this method to register to listen for events.
*/
BBB.listen = function(eventName, handler) {
if (typeof listeners[eventName] === 'undefined')
listeners[eventName] = [];
listeners[eventName].push(handler);
};
/**
* 3rd-party app should use this method to unregister listener for a given event.
*/
BBB.unlisten = function(eventName, handler) {
if (!listeners[eventName])
return;
for (var i = 0; i < listeners[eventName].length; i++) {
if (listeners[eventName][i] === handler) {
listeners[eventName].splice(i, 1);
break;
}
}
};
/**
* Private function to broadcast received event from the BigBlueButton Flash client to
* 3rd-parties.
*/
function broadcast(bbbEvent) {
if (!listeners[bbbEvent.eventName]) {
console.log("No listeners for [" + bbbEvent.eventName + "]");
return;
}
for (var i = 0; i < listeners[bbbEvent.eventName].length; i++) {
console.log("Notifying listeners for [" + bbbEvent.eventName + "]");
listeners[bbbEvent.eventName][i](bbbEvent);
}
};
/**
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*
* DO NOT CALL THIS METHOD FROM YOUR JS CODE.
*
* This is called by the BigBlueButton Flash client to inform 3rd-parties of internal events.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
BBB.handleFlashClientBroadcastEvent = function (bbbEvent) {
console.log("Received [" + bbbEvent.eventName + "]");
broadcast(bbbEvent);
}
// Flag to indicate that the SWF file has been loaded and ready to handle calls.
var swfReady = false;
/**
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*
* DO NOT CALL THIS METHOD FROM YOUR JS CODE.
*
* This is called by the BigBlueButton Flash client to inform 3rd-parties that it is ready.
*
* WARNING:
* Doesn't actually work as intended. The Flash client calls this function when it's loaded.
* However, the client as to query the BBB server to get the status of the meeting.
* We're working on the proper way to determining that the client is TRULY ready.
*
* !!! As a workaround, 3rd-party JS on init should call getUserInfo until it return NOT NULL.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
BBB.swfClientIsReady = function () {
console.log("BigBlueButton SWF is ready.");
swfReady = true;
}
/* ********************************************************************* */
BBB.init = function(callback) {
callback;
}
/************************************************
* EVENT NAME CONSTANTS
*
* See https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/src/org/bigbluebutton/core/EventConstants.as
*
************************************************/
var GET_MY_ROLE_RESP = 'GetMyRoleResponse';
var AM_I_PRESENTER_RESP = 'AmIPresenterQueryResponse';
var AM_I_SHARING_CAM_RESP = 'AmISharingCamQueryResponse';
var BROADCASTING_CAM_STARTED = 'BroadcastingCameraStartedEvent';
var BROADCASTING_CAM_STOPPED = 'BroadcastingCameraStoppedEvent';
var I_AM_SHARING_CAM = 'IAmSharingCamEvent';
var CAM_STREAM_SHARED = 'CamStreamSharedEvent';
var USER_JOINED = 'UserJoinedEvent';
var USER_LEFT = 'UserLeftEvent';
var SWITCHED_PRESENTER = 'SwitchedPresenterEvent';
var NEW_ROLE = 'NewRoleEvent';
var NEW_PRIVATE_CHAT = 'NewPrivateChatEvent';
var NEW_PUBLIC_CHAT = 'NewPublicChatEvent';
var SWITCHED_LAYOUT = 'SwitchedLayoutEvent';
var REMOTE_LOCKED_LAYOUT = 'RemoteLockedLayoutEvent';
var REMOTE_UNLOCKED_LAYOUT = 'RemoteUnlockedLayoutEvent';
var USER_JOINED_VOICE = 'UserJoinedVoiceEvent';
var USER_LEFT_VOICE = 'UserLeftVoiceEvent';
var USER_KICKED_OUT = 'UserKickedOutEvent';
var USER_MUTED_VOICE = 'UserVoiceMutedEvent';
var USER_TALKING = 'UserTalkingEvent';
var USER_LOCKED_VOICE = 'UserLockedVoiceEvent';
var START_PRIVATE_CHAT = "StartPrivateChatEvent";
var GET_MY_USER_INFO_REP = "GetMyUserInfoResponse";
var IS_USER_PUBLISHING_CAM_RESP = "IsUserPublishingCamResponse";
/*conversion events*/
var OFFICE_DOC_CONVERSION_SUCCESS = "OfficeDocConversionSuccess";
var OFFICE_DOC_CONVERSION_FAILED = "OfficeDocConversionFailed";
var SUPPORTED_DOCUMENT = "SupportedDocument";
var UNSUPPORTED_DOCUMENT = "UnsupportedDocument";
var PAGE_COUNT_FAILED = "PageCountFailed";
var THUMBNAILS_UPDATE = "ThumbnailsUpdate";
var PAGE_COUNT_EXCEEDED = "PageCountExceeded";
var CONVERT_SUCCESS = "ConvertSuccess";
var CONVERT_UPDATE = "ConvertUpdate";
window.BBB = BBB;
})(this);

View File

@ -0,0 +1,44 @@
(function(window, undefined) {
var CAM_PREVIEW = {};
/**
* Internal function to get the BBB embed object. Seems like we have to do this
* each time and can't create a var for it.
*
* To get the object, see https://code.google.com/p/swfobject/wiki/api
*/
function getSwfObj() {
return swfobject.getObjectById("WebcamPreviewStandalone");
}
/**
* Preview user's webcam.
*/
CAM_PREVIEW.previewCamera = function(camIndex, camWidth, camHeight,
camKeyFrameInterval, camModeFps,
camQualityBandwidth, camQualityPicture, avatarURL) {
console.log("CAM_PREVIEW::previewCamera [" + camIndex + "]");
var swfObj = getSwfObj();
if (swfObj) {
swfObj.startPreviewCamera(camIndex, camWidth, camHeight, camKeyFrameInterval, camModeFps,
camQualityBandwidth, camQualityPicture, avatarURL);
}
}
/**
* Stop previewing user's webcam.
*/
CAM_PREVIEW.stopPreviewCamera = function(avatarURL) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.stopPreviewCamera(avatarURL);
}
}
console.log("CAM_PREVIEW INITIALIZED");
window.CAM_PREVIEW = CAM_PREVIEW;
})(this);

View File

@ -0,0 +1,42 @@
(function(window, undefined) {
var CAM_VIEW = {};
/**
* Internal function to get the BBB embed object. Seems like we have to do this
* each time and can't create a var for it.
*
* To get the object, see https://code.google.com/p/swfobject/wiki/api
*/
function getSwfObj() {
return swfobject.getObjectById("WebcamViewStandalone");
}
/**
* View user's webcam.
*/
CAM_VIEW.viewWebcamStream = function(url, streamName, avatarURL) {
console.log("CAM_VIEW::viewWebcamStream [" + url + "," + streamName + "]");
var swfObj = getSwfObj();
if (swfObj) {
console.log("CAM_VIEW::viewWebcamStream 2 [" + url + "," + streamName + "]");
swfObj.startViewCameraStream(url, streamName, avatarURL);
}
}
/**
* Stop viewing user's webcam.
*/
CAM_VIEW.stopViewWebcamStream = function(avatarURL) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.stopViewCameraStream(avatarURL);
}
}
console.log("CAM_VIEW INITIALIZED");
window.CAM_VIEW = CAM_VIEW;
})(this);

View File

@ -0,0 +1,142 @@
function setTitle(title){
document.title= "BigBlueButton - " + title;
}
function clientReady(message){
var target = document.getElementById("clientReady");
if (target) target.innerHTML = message;
}
function setProgressBar(percent){
var bar = document.getElementById("accessibile-progress");
if (bar) {
bar.setAttribute("aria-valuenow", percent);
bar.innerHTML = percent + " " + "%";
}
}
function removeProgressBar(){
var bar = document.getElementById("accessibile-progress");
if (bar) bar.parentNode.removeChild(bar);
}
function determineModifier()
{
var browser = determineBrowser()[0];
var modifier;
if (browser == "Firefox"){
modifier = "control+";
}
else if (browser == "Chrome"){
modifier = "control+";
}
else if (browser == "Microsoft Internet Explorer"){
modifier = "control+shift+";
}
//else if (browser == "Safari"){
// modifier = "control+shift+";
//}
else{
modifier = "control+shift+";
}
return modifier;
}
function determineGlobalModifier()
{
var browser = determineBrowser()[0];
var modifier;
if (browser == "Firefox"){
modifier = "control+shift+";
}
else if (browser == "Chrome"){
modifier = "control+shift+";
}
else if (browser == "Microsoft Internet Explorer"){
modifier = "control+alt+";
}
//else if (browser == "Safari"){
// modifier = "control+alt";
//}
else{
modifier = "control+alt+";
}
return modifier;
}
function determineBrowser()
{
// Browser name extraction code provided by http://www.javascripter.net/faq/browsern.htm
var nVer = navigator.appVersion;
var nAgt = navigator.userAgent;
var browserName = navigator.appName;
var fullVersion = ''+parseFloat(navigator.appVersion);
var majorVersion = parseInt(navigator.appVersion,10);
var nameOffset,verOffset,ix;
// In Opera, the true version is after "Opera" or after "Version"
if ((verOffset=nAgt.indexOf("Opera"))!=-1) {
browserName = "Opera";
fullVersion = nAgt.substring(verOffset+6);
if ((verOffset=nAgt.indexOf("Version"))!=-1)
fullVersion = nAgt.substring(verOffset+8);
}
// In MSIE, the true version is after "MSIE" in userAgent
else if ((verOffset=nAgt.indexOf("MSIE"))!=-1) {
browserName = "Microsoft Internet Explorer";
fullVersion = nAgt.substring(verOffset+5);
}
// In Puffin, the true version is after "Puffin" in userAgent
else if ((verOffset=nAgt.indexOf("Puffin"))!=-1) {
browserName = "Puffin";
fullVersion = nAgt.substring(verOffset+7);
}
// search for Edge before Chrome or Safari because Microsoft
// includes Chrome and Safari user agents in Edge's UA
// In Microsoft Edge, the true version is the last chunk of the UA
// it follows "Edge"
else if ((verOffset=nAgt.indexOf("Edge"))!=-1) {
browserName = "Edge";
// "Edge".length = 4, plus 1 character for the trailing slash
fullVersion = nAgt.substring(verOffset+5);
}
// In Chrome, the true version is after "Chrome"
else if ((verOffset=nAgt.indexOf("Chrome"))!=-1) {
browserName = "Chrome";
fullVersion = nAgt.substring(verOffset+7);
}
// In Safari, the true version is after "Safari" or after "Version"
else if ((verOffset=nAgt.indexOf("Safari"))!=-1) {
browserName = "Safari";
fullVersion = nAgt.substring(verOffset+7);
if ((verOffset=nAgt.indexOf("Version"))!=-1)
fullVersion = nAgt.substring(verOffset+8);
}
// In Firefox, the true version is after "Firefox"
else if ((verOffset=nAgt.indexOf("Firefox"))!=-1) {
browserName = "Firefox";
fullVersion = nAgt.substring(verOffset+8);
}
// In most other browsers, "name/version" is at the end of userAgent
else if ( (nameOffset=nAgt.lastIndexOf(' ')+1) < (verOffset=nAgt.lastIndexOf('/')) )
{
browserName = nAgt.substring(nameOffset,verOffset);
fullVersion = nAgt.substring(verOffset+1);
if (browserName.toLowerCase()==browserName.toUpperCase()) {
browserName = navigator.appName;
}
}
// trim the fullVersion string at semicolon/space if present
if ((ix=fullVersion.indexOf(";"))!=-1)
fullVersion=fullVersion.substring(0,ix);
if ((ix=fullVersion.indexOf(" "))!=-1)
fullVersion=fullVersion.substring(0,ix);
majorVersion = parseInt(''+fullVersion,10);
if (isNaN(majorVersion)) {
fullVersion = ''+parseFloat(navigator.appVersion);
majorVersion = parseInt(navigator.appVersion,10);
}
return [browserName, majorVersion, fullVersion];
}

View File

@ -0,0 +1,174 @@
if (!window.console) window.console = {};
if (!window.console.log) window.console.log = function () { };
function startApplet(IP, useTLS , roomNumber, fullScreen, useSVC2)
{
var deskshareElement = document.getElementById("deskshare");
if (deskshareElement == null) {
console.log("Starting deskshare applet.");
var div = document.createElement("div");
div.id = "deskshare";
div.innerHTML =
"<applet code=\"org.bigbluebutton.deskshare.client.DeskShareApplet.class\"" +
"id=\"DeskShareApplet\" width=\"100\" height=\"10\" archive=\"bbb-deskshare-applet-0.9.0.jar\">" +
"<param name=\"ROOM\" value=\"" + roomNumber + "\"/>" +
"<param name=\"IP\" value=\"" + IP + "\"/>" +
"<param name=\"useTLS\" value=\"" + useTLS + "\"/>" +
"<param name=\"PORT\" value=\"9123\"/>" +
"<param name=\"SCALE\" value=\"0.8\"/>" +
"<param name=\"FULL_SCREEN\" value=\"" + fullScreen + "\"/>" +
"<param name=\"SVC2\" value=\"" + useSVC2 + "\"/>" +
"<param name=\"JavaVersion\" value=\"1.7.0_51\"/>" +
"<param name=\"permissions\" value=\"all-permissions\"/>" +
"</applet>";
document.body.appendChild(div);
} else {
console.log("Deskshare applet element already exists.");
var div = document.getElementById("deskshare");
if (div.parentNode) {
// Just rewrite the applet tag to kick off the applet. We don't remove the applet tag
// when desktop sharing is stopped to prevent Firefox (38.0.5) from asking for user permissions
// again resulting in the page reloading. (ralam june 17, 2015)
// https://code.google.com/p/bigbluebutton/issues/detail?id=1953
div.innerHTML =
"<applet code=\"org.bigbluebutton.deskshare.client.DeskShareApplet.class\"" +
"id=\"DeskShareApplet\" width=\"100\" height=\"10\" archive=\"bbb-deskshare-applet-0.9.0.jar\">" +
"<param name=\"ROOM\" value=\"" + roomNumber + "\"/>" +
"<param name=\"IP\" value=\"" + IP + "\"/>" +
"<param name=\"PORT\" value=\"9123\"/>" +
"<param name=\"SCALE\" value=\"0.8\"/>" +
"<param name=\"FULL_SCREEN\" value=\"" + fullScreen + "\"/>" +
"<param name=\"SVC2\" value=\"" + useSVC2 + "\"/>" +
"<param name=\"JavaVersion\" value=\"1.7.0_51\"/>" +
"<param name=\"permissions\" value=\"all-permissions\"/>" +
"</applet>";
}
}
}
function removeFrame () {
var div = document.getElementById("deskshare");
if (div.parentNode) {
// Need to set the innerHTML otherwise the applet will restart in IE.
// see https://code.google.com/p/bigbluebutton/issues/detail?id=1776
// Do NOT remove the applet tag as it makes Firefox (38.0.5) prompt for
// permissions again resulting in the page reloading. (ralam june 17, 2015)
// div.innerHTML = "";
// div.parentNode.removeChild(div);
}
}
function setScreenCoordinates(x, y) {
document.DeskShareApplet.setScreenCoordinates(x,y);
}
function stopApplet(){
console.log("Stopping deskshare applet.");
removeFrame();
}
function appletStartupCallback() {
BBB.javaAppletLaunched();
}
function getHighestJavaVersion(javas) {
var highestJava = javas[0];
console.log("highestJava = [" + highestJava + "]");
for (j = 0; j < javas.length; j++) {
var java = javas[j];
console.log("java[" + j + "]=[" + java + "]");
var highest = highestJava.split(".");
console.log(highest);
var iter = java.split(".");
console.log(iter);
if (parseInt(iter[0]) > parseInt(highest[0])) {
highestJava = java;
} else if (parseInt(iter[0]) == parseInt(highest[0]) && parseInt(iter[1]) > parseInt(highest[1])) {
highestJava = java;
console.log(highestJava);
} else if (parseInt(iter[0]) == parseInt(highest[0]) && parseInt(iter[1]) == parseInt(highest[1])) {
var iterMinor = parseInt((iter[2]).split("_")[1]);
var highestMinor = parseInt((highest[2]).split("_")[1]);
if (iterMinor > highestMinor) {
highestJava = java;
console.log(highestJava);
}
}
}
return highestJava;
}
function getIcedTeaWebVersion() {
for (i = 0; i < navigator.plugins.length; i++) {
var matches;
if (matches = navigator.plugins[i].name.match(/using IcedTea-Web ([0-9.]+)/)) {
return matches[1];
}
}
return null;
}
function isJavaVersionOk(installedVersion, minVersion) {
var required = minVersion.split(".");
highest = installedVersion.split(".");
if (parseInt(required[0]) > parseInt(highest[0])) {
console.log("older major version=[" + installedVersion + "]");
return {result: "JAVA_OLDER", version: installedVersion};
} else if (parseInt(required[0]) == parseInt(highest[0]) && parseInt(required[1]) > parseInt(highest[1])) {
console.log("older minor version=[" + installedVersion + "]");
return {result: "JAVA_OLDER", version: installedVersion};
} else if (parseInt(required[0]) == parseInt(highest[0]) && parseInt(required[1]) == parseInt(highest[1])) {
var requiredMinor = parseInt((required[2]).split("_")[1]);
var highestJavaMinor = parseInt((highest[2]).split("_")[1]);
if (requiredMinor > highestJavaMinor) {
console.log("older update version=[" + installedVersion + "]");
return {result: "JAVA_OLDER", version: installedVersion};
}
}
return {result: "JAVA_OK"};
}
function isIcedTeaVersionOkLinux(installedVersion, minVersion) {
var required = minVersion.split(".");
highest = installedVersion.split(".");
if (parseInt(required[0]) > parseInt(highest[0])) {
console.log("ice: older major version=[" + installedVersion + "]");
return {result: "JAVA_OLDER", version: installedVersion};
} else if (parseInt(required[0]) == parseInt(highest[0]) && parseInt(required[1]) > parseInt(highest[1])) {
console.log("ice: older minor version=[" + installedVersion + "]");
return {result: "JAVA_OLDER", version: installedVersion};
}
return {result: "JAVA_OK"};
}
function checkJavaVersion(minJavaVersion) {
var javas = deployJava.getJREs();
var highestJavaVersion = null;
if (javas == null || javas.length == 0) {
if (javas == null) {
return {result:"JAVA_NOT_DETECTED"};
}
if (javas.length == 0) {
return {result: "JAVA_NOT_INSTALLED"};
}
} else {
var highestJavaVersion = getHighestJavaVersion(javas);
var isOk = isJavaVersionOk(highestJavaVersion, minJavaVersion);
if (isOk.result === "JAVA_OLDER") {
highestJavaVersion = getIcedTeaWebVersion();
return isIcedTeaVersionOkLinux(highestJavaVersion, "1.5.0");
} else {
return isOk;
}
}
}

View File

@ -0,0 +1,27 @@
// Check locale
var localeChain = "en_US";
if (navigator.language)
localeChain = navigator.language;
else if (navigator.browserLanguage)
localeChain = navigator.browserLanguage;
if(/^([a-z]+)-([a-z]+)$/i.test(localeChain)){
var matches = /^([a-z]+)-([a-z]+)$/i.exec(localeChain);
localeChain = matches[1].toLowerCase() + "_" + matches[2].toUpperCase();
}
else if(/^en$/i.test(localeChain)){
localeChain = "en_US";
}
else if(/^([a-z]+)$/i.test(localeChain)){
var matches = /^([a-z]+)$/i.exec(localeChain);
localeChain = matches[1].toLowerCase() + "_" + matches[1].toUpperCase();
}
else{
localeChain = "en_US";
}
function getLanguage(){
return localeChain;
}

View File

@ -0,0 +1,27 @@
function startScreensharing(jnlp, meetingId, authToken, fullScreen)
{
console.log("Starting JSW [" + authToken + "]");
var launchuri = jnlp + "?authToken=" + authToken + "&fullScreen=" + fullScreen + "&meetingId=" + meetingId;
$('<iframe id="iframe"><iframe/>').attr('src', launchuri).hide().appendTo('body');
}
function removeFrame () {
var div = document.getElementById("deskshare");
div.parentNode.removeChild(div);
}
function setScreenCoordinates(x, y) {
document.DeskShareApplet.setScreenCoordinates(x,y);
}
function stopApplet(){
document.DeskShareApplet.destroy();
removeFrame();
}
function checkForJava(){
// if (navigator.javaEnabled() || window.navigator.javaEnabled())
return 1;
}

View File

@ -0,0 +1,522 @@
var userID, callerIdName=null, conferenceVoiceBridge, userAgent=null, userMicMedia, userWebcamMedia, currentSession=null, callTimeout, callActive, callICEConnected, iceConnectedTimeout, callFailCounter, callPurposefullyEnded, uaConnected, transferTimeout, iceGatheringTimeout;
var inEchoTest = true;
function webRTCCallback(message) {
switch (message.status) {
case 'failed':
if (message.errorcode !== 1004) {
message.cause = null;
}
BBB.webRTCCallFailed(inEchoTest, message.errorcode, message.cause);
break;
case 'ended':
BBB.webRTCCallEnded(inEchoTest);
break;
case 'started':
BBB.webRTCCallStarted(inEchoTest);
break;
case 'connecting':
BBB.webRTCCallConnecting(inEchoTest);
break;
case 'waitingforice':
BBB.webRTCCallWaitingForICE(inEchoTest);
break;
case 'transferring':
BBB.webRTCCallTransferring(inEchoTest);
break;
case 'mediarequest':
BBB.webRTCMediaRequest();
break;
case 'mediasuccess':
BBB.webRTCMediaSuccess();
break;
case 'mediafail':
BBB.webRTCMediaFail();
break;
}
}
function callIntoConference(voiceBridge, callback, isListenOnly) {
// root of the call initiation process from the html5 client
// Flash will not pass in the listen only field. For html5 it is optional. Assume NOT listen only if no state passed
if (isListenOnly == null) {
isListenOnly = false;
}
// reset callerIdName
callerIdName = null;
if (!callerIdName) {
BBB.getMyUserInfo(function(userInfo) {
console.log("User info callback [myUserID=" + userInfo.myUserID
+ ",myUsername=" + userInfo.myUsername + ",myAvatarURL=" + userInfo.myAvatarURL
+ ",myRole=" + userInfo.myRole + ",amIPresenter=" + userInfo.amIPresenter
+ ",dialNumber=" + userInfo.dialNumber + ",voiceBridge=" + userInfo.voiceBridge
+ ",isListenOnly=" + isListenOnly + "].");
userID = userInfo.myUserID;
callerIdName = userInfo.myUserID + "-bbbID-" + userInfo.myUsername;
if (isListenOnly) {
//prepend the callerIdName so it is recognized as a global audio user
callerIdName = "GLOBAL_AUDIO_" + callerIdName;
}
conferenceVoiceBridge = userInfo.voiceBridge
if (voiceBridge === "9196") {
voiceBridge = voiceBridge + conferenceVoiceBridge;
} else {
voiceBridge = conferenceVoiceBridge;
}
console.log(callerIdName);
webrtc_call(callerIdName, voiceBridge, callback, isListenOnly);
});
} else {
if (voiceBridge === "9196") {
voiceBridge = voiceBridge + conferenceVoiceBridge;
} else {
voiceBridge = conferenceVoiceBridge;
}
webrtc_call(callerIdName, voiceBridge, callback, isListenOnly);
}
}
function joinWebRTCVoiceConference() {
console.log("Joining to the voice conference directly");
inEchoTest = false;
// set proper callbacks to previously created user agent
if(userAgent) {
setUserAgentListeners(webRTCCallback);
}
callIntoConference(conferenceVoiceBridge, webRTCCallback);
}
function leaveWebRTCVoiceConference() {
console.log("Leaving the voice conference");
webrtc_hangup();
}
function startWebRTCAudioTest(){
console.log("Joining the audio test first");
inEchoTest = true;
callIntoConference("9196", webRTCCallback);
}
function stopWebRTCAudioTest(){
console.log("Stopping webrtc audio test");
webrtc_hangup();
}
function stopWebRTCAudioTestJoinConference(){
console.log("Transferring from audio test to conference");
webRTCCallback({'status': 'transferring'});
transferTimeout = setTimeout( function() {
console.log("Call transfer failed. No response after 3 seconds");
webRTCCallback({'status': 'failed', 'errorcode': 1008});
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
}, 5000);
BBB.listen("UserJoinedVoiceEvent", userJoinedVoiceHandler);
currentSession.dtmf(1);
inEchoTest = false;
}
function userJoinedVoiceHandler(event) {
console.log("UserJoinedVoiceHandler - " + event);
if (inEchoTest === false && userID === event.userID) {
BBB.unlisten("UserJoinedVoiceEvent", userJoinedVoiceHandler);
clearTimeout(transferTimeout);
webRTCCallback({'status': 'started'});
}
}
function createUA(username, server, callback, makeCallFunc) {
if (userAgent) {
console.log("User agent already created");
return;
}
console.log("Fetching STUN/TURN server info for user agent");
$.ajax({
dataType: 'json',
url: '/bigbluebutton/api/stuns'
}).done(function(data) {
var stunsConfig = {};
stunsConfig['stunServers'] = ( data['stunServers'] ? data['stunServers'].map(function(data) {
return data['url'];
}) : [] );
stunsConfig['turnServers'] = ( data['turnServers'] ? data['turnServers'].map(function(data) {
return {
'urls': data['url'],
'username': data['username'],
'password': data['password']
};
}) : [] );
createUAWithStuns(username, server, callback, stunsConfig, makeCallFunc);
}).fail(function(data, textStatus, errorThrown) {
BBBLog.error("Could not fetch stun/turn servers", {error: textStatus, user: callerIdName, voiceBridge: conferenceVoiceBridge});
callback({'status':'failed', 'errorcode': 1009});
});
}
function createUAWithStuns(username, server, callback, stunsConfig, makeCallFunc) {
console.log("Creating new user agent");
/* VERY IMPORTANT
* - You must escape the username because spaces will cause the connection to fail
* - We are connecting to the websocket through an nginx redirect instead of directly to 5066
*/
var configuration = {
uri: 'sip:' + encodeURIComponent(username) + '@' + server,
wsServers: 'ws://' + server + '/ws',
displayName: username,
register: false,
traceSip: true,
autostart: false,
userAgentString: "BigBlueButton",
stunServers: stunsConfig['stunServers'],
turnServers: stunsConfig['turnServers']
};
uaConnected = false;
userAgent = new SIP.UA(configuration);
setUserAgentListeners(callback, makeCallFunc);
userAgent.start();
};
function setUserAgentListeners(callback, makeCallFunc) {
console.log("reseting UA callbacks");
userAgent.off('connected');
userAgent.on('connected', function() {
uaConnected = true;
makeCallFunc();
});
userAgent.off('disconnected');
userAgent.on('disconnected', function() {
if (userAgent) {
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
if (uaConnected) {
callback({'status':'failed', 'errorcode': 1001}); // WebSocket disconnected
} else {
callback({'status':'failed', 'errorcode': 1002}); // Could not make a WebSocket connection
}
}
});
};
function getUserMicMedia(getUserMicMediaSuccess, getUserMicMediaFailure) {
if (userMicMedia == undefined) {
if (SIP.WebRTC.isSupported()) {
SIP.WebRTC.getUserMedia({audio:true, video:false}, getUserMicMediaSuccess, getUserMicMediaFailure);
} else {
console.log("getUserMicMedia: webrtc not supported");
getUserMicMediaFailure("WebRTC is not supported");
}
} else {
console.log("getUserMicMedia: mic already set");
getUserMicMediaSuccess(userMicMedia);
}
};
function webrtc_call(username, voiceBridge, callback, isListenOnly) {
if (!isWebRTCAvailable()) {
callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
return;
}
if (isListenOnly == null) { // assume NOT listen only unless otherwise stated
isListenOnly = false;
}
var server = window.document.location.hostname;
console.log("user " + username + " calling to " + voiceBridge);
var makeCallFunc = function() {
// only make the call when both microphone and useragent have been created
// for listen only, stating listen only is a viable substitute for acquiring user media control
if ((isListenOnly||userMicMedia) && userAgent)
make_call(username, voiceBridge, server, callback, false, isListenOnly);
};
// Reset userAgent so we can successfully switch between listenOnly and listen+speak modes
userAgent = null;
if (!userAgent) {
createUA(username, server, callback, makeCallFunc);
}
// if the user requests to proceed as listen only (does not require media) or media is already acquired,
// proceed with making the call
if (isListenOnly || userMicMedia !== undefined) {
makeCallFunc();
} else {
callback({'status':'mediarequest'});
getUserMicMedia(function(stream) {
console.log("getUserMicMedia: success");
userMicMedia = stream;
callback({'status':'mediasuccess'});
makeCallFunc();
}, function(e) {
console.error("getUserMicMedia: failure - " + e);
callback({'status':'mediafail', 'cause': e});
}
);
}
}
function make_call(username, voiceBridge, server, callback, recall, isListenOnly) {
if (isListenOnly == null) {
isListenOnly = false;
}
if (userAgent == null) {
console.log("userAgent is still null. Delaying call");
var callDelayTimeout = setTimeout( function() {
make_call(username, voiceBridge, server, callback, recall, isListenOnly);
}, 100);
return;
}
if (!userAgent.isConnected()) {
console.log("Trying to make call, but UserAgent hasn't connected yet. Delaying call");
userAgent.once('connected', function() {
console.log("UserAgent has now connected, retrying the call");
make_call(username, voiceBridge, server, callback, recall, isListenOnly);
});
return;
}
if (currentSession) {
console.log('Active call detected ignoring second make_call');
return;
}
// Make an audio/video call:
console.log("Setting options.. ");
var options = {};
if (isListenOnly) {
// create necessary options for a listen only stream
var stream = null;
// handle the web browser
// create a stream object through the browser separated from user media
if (typeof webkitMediaStream !== 'undefined') {
// Google Chrome
stream = new webkitMediaStream;
} else {
// Firefox
audioContext = new window.AudioContext;
stream = audioContext.createMediaStreamDestination().stream;
}
options = {
media: {
stream: stream, // use the stream created above
render: {
remote: {
// select an element to render the incoming stream data
audio: document.getElementById('remote-media')
}
}
},
// a list of our RTC Connection constraints
RTCConstraints: {
// our constraints are mandatory. We must received audio and must not receive audio
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: false
}
}
};
} else {
options = {
media: {
stream: userMicMedia,
render: {
remote: {
audio: document.getElementById('remote-media')
}
}
}
};
}
callTimeout = setTimeout(function() {
console.log('Ten seconds without updates sending timeout code');
callback({'status':'failed', 'errorcode': 1006}); // Failure on call
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
}, 10000);
callActive = false;
callICEConnected = false;
callPurposefullyEnded = false;
callFailCounter = 0;
console.log("Calling to " + voiceBridge + "....");
currentSession = userAgent.invite('sip:' + voiceBridge + '@' + server, options);
// Only send the callback if it's the first try
if (recall === false) {
console.log('call connecting');
callback({'status':'connecting'});
} else {
console.log('call connecting again');
}
iceGatheringTimeout = setTimeout(function() {
console.log('Thirty seconds without ICE gathering finishing');
callback({'status':'failed', 'errorcode': 1011}); // ICE Gathering Failed
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
}, 30000);
currentSession.mediaHandler.on('iceComplete', function() {
clearTimeout(iceGatheringTimeout);
});
// The connecting event fires before the listener can be added
currentSession.on('connecting', function(){
clearTimeout(callTimeout);
});
currentSession.on('progress', function(response){
console.log('call progress: ' + response);
clearTimeout(callTimeout);
});
currentSession.on('failed', function(response, cause){
console.log('call failed with cause: '+ cause);
if (currentSession) {
if (callActive === false) {
callback({'status':'failed', 'errorcode': 1004, 'cause': cause}); // Failure on call
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
} else {
callActive = false;
//currentSession.bye();
currentSession = null;
if (userAgent != null) {
userAgent.stop();
}
}
}
clearTimeout(callTimeout);
});
currentSession.on('bye', function(request){
callActive = false;
if (currentSession) {
console.log('call ended ' + currentSession.endTime);
if (callPurposefullyEnded === true) {
callback({'status':'ended'});
} else {
callback({'status':'failed', 'errorcode': 1005}); // Call ended unexpectedly
}
clearTimeout(callTimeout);
currentSession = null;
} else {
console.log('bye event already received');
}
});
currentSession.on('accepted', function(data){
callActive = true;
console.log('BigBlueButton call accepted');
if (callICEConnected === true) {
callback({'status':'started'});
} else {
callback({'status':'waitingforice'});
console.log('Waiting for ICE negotiation');
iceConnectedTimeout = setTimeout(function() {
console.log('60 seconds without ICE finishing');
callback({'status':'failed', 'errorcode': 1010}); // ICE negotiation timeout
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
}, 60000);
}
clearTimeout(callTimeout);
});
currentSession.mediaHandler.on('iceFailed', function() {
console.log('received ice negotiation failed');
callback({'status':'failed', 'errorcode': 1007}); // Failure on call
currentSession = null;
clearTimeout(iceConnectedTimeout);
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
clearTimeout(callTimeout);
});
// Some browsers use status of 'connected', others use 'completed', and a couple use both
currentSession.mediaHandler.on('iceConnected', function() {
console.log('Received ICE status changed to connected');
if (callICEConnected === false) {
callICEConnected = true;
clearTimeout(iceConnectedTimeout);
if (callActive === true) {
callback({'status':'started'});
}
clearTimeout(callTimeout);
}
});
currentSession.mediaHandler.on('iceCompleted', function() {
console.log('Received ICE status changed to completed');
if (callICEConnected === false) {
callICEConnected = true;
clearTimeout(iceConnectedTimeout);
if (callActive === true) {
callback({'status':'started'});
}
clearTimeout(callTimeout);
}
});
}
function webrtc_hangup(callback) {
callPurposefullyEnded = true;
console.log("Hanging up current session");
if (callback) {
currentSession.on('bye', callback);
}
currentSession.bye();
}
function isWebRTCAvailable() {
return SIP.WebRTC.isSupported();
}
function getCallStatus() {
return currentSession;
}

View File

@ -0,0 +1,28 @@
(function(window, undefined) {
var BBBLog = {};
BBBLog.critical = function (message, data) {
console.log(message, JSON.stringify(data));
}
BBBLog.error = function (message, data) {
console.log(message, JSON.stringify(data));
}
BBBLog.warning = function (message, data) {
console.log(message, JSON.stringify(data));
}
BBBLog.info = function (message, data) {
console.log(message, JSON.stringify(data));
}
BBBLog.debug = function (message, data) {
console.log(message, JSON.stringify(data));
}
window.BBBLog = BBBLog;
})(this);

View File

@ -0,0 +1,26 @@
$(function () {
setTimeout(function(){
$('#BigBlueButton').focus();
},1000);
});
function startFlashFocus() {
f = $('#BigBlueButton')[0]
f.tabIndex = 0;
f.focus();
}
function stopFlashFocus() {
$('#enterFlash')[0].focus();
}
// http://stackoverflow.com/questions/5916900/detect-version-of-browser
navigator.sayswho= (function(){
var ua= navigator.userAgent,
N= navigator.appName,
tem,
M= ua.match(/(opera|chrome|safari|firefox|msie|trident)\/?\s*([\d\.]+)/i) || [];
M= M[2]? [M[1], M[2]]:[N, navigator.appVersion, '-?'];
if(M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
return M;
})();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,103 @@
// Last time updated at Sep 07, 2014, 08:32:23
// Latest file can be found here: https://cdn.webrtc-experiment.com/getScreenId.js
// Muaz Khan - www.MuazKhan.com
// MIT License - www.WebRTC-Experiment.com/licence
// Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/getScreenId.js
// ______________
// getScreenId.js
/*
getScreenId(function (error, sourceId, screen_constraints) {
// error == null || 'permission-denied' || 'not-installed' || 'installed-disabled' || 'not-chrome'
// sourceId == null || 'string' || 'firefox'
if(sourceId == 'firefox') {
navigator.mozGetUserMedia(screen_constraints, onSuccess, onFailure);
}
else navigator.webkitGetUserMedia(screen_constraints, onSuccess, onFailure);
});
*/
(function() {
window.getScreenId = function(callback) {
// for Firefox:
// sourceId == 'firefox'
// screen_constraints = {...}
if (!!navigator.mozGetUserMedia) {
callback(null, 'firefox', {
video: {
mozMediaSource: 'window',
mediaSource: 'window'
}
});
return;
}
postMessage();
window.addEventListener('message', onIFrameCallback);
function onIFrameCallback(event) {
if (!event.data) return;
if (event.data.chromeMediaSourceId) {
if (event.data.chromeMediaSourceId === 'PermissionDeniedError') {
callback('permission-denied');
} else callback(null, event.data.chromeMediaSourceId, getScreenConstraints(null, event.data.chromeMediaSourceId));
}
if (event.data.chromeExtensionStatus) {
callback(event.data.chromeExtensionStatus, null, getScreenConstraints(event.data.chromeExtensionStatus));
}
// this event listener is no more needed
window.removeEventListener('message', onIFrameCallback);
}
};
function getScreenConstraints(error, sourceId) {
var screen_constraints = {
audio: false,
video: {
mandatory: {
chromeMediaSource: error ? 'screen' : 'desktop',
maxWidth: window.screen.width > 1920 ? window.screen.width : 1920,
maxHeight: window.screen.height > 1080 ? window.screen.height : 1080
},
optional: []
}
};
console.log("____in getScreenConstraints and error=" + error + " and sourceId=" + sourceId +
" and chromeMediaSource = " + screen_constraints.video.mandatory.chromeMediaSource);
if (sourceId) {
screen_constraints.video.mandatory.chromeMediaSourceId = sourceId;
}
return screen_constraints;
}
function postMessage() {
console.log("___in postMessage and iframe isLoaded=" + iframe.isLoaded);
if (!iframe.isLoaded) {
setTimeout(postMessage, 100);
return;
}
iframe.contentWindow.postMessage({
captureSourceId: true
}, '*');
}
var iframe = document.createElement('iframe');
iframe.onload = function() {
iframe.isLoaded = true;
};
iframe.src = 'https://www.webrtc-experiment.com/getSourceId/';
iframe.style.display = 'none';
(document.body || document.documentElement).appendChild(iframe);
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
/*!
* jQuery Cookie Plugin v1.3.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2013 Klaus Hartl
* Released under the MIT license
*/
(function ($, document, undefined) {
var pluses = /\+/g;
function raw(s) {
return s;
}
function decoded(s) {
return unRfc2068(decodeURIComponent(s.replace(pluses, ' ')));
}
function unRfc2068(value) {
if (value.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape
value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
return value;
}
function fromJSON(value) {
return config.json ? JSON.parse(value) : value;
}
var config = $.cookie = function (key, value, options) {
// write
if (value !== undefined) {
options = $.extend({}, config.defaults, options);
if (value === null) {
options.expires = -1;
}
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setDate(t.getDate() + days);
}
value = config.json ? JSON.stringify(value) : String(value);
return (document.cookie = [
encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// read
var decode = config.raw ? raw : decoded;
var cookies = document.cookie.split('; ');
var result = key ? null : {};
for (var i = 0, l = cookies.length; i < l; i++) {
var parts = cookies[i].split('=');
var name = decode(parts.shift());
var cookie = decode(parts.join('='));
if (key && key === name) {
result = fromJSON(cookie);
break;
}
if (!key) {
result[name] = fromJSON(cookie);
}
}
return result;
};
config.defaults = {};
$.removeCookie = function (key, options) {
if ($.cookie(key) !== null) {
$.cookie(key, null, options);
return true;
}
return false;
};
})(jQuery, document);

View File

@ -0,0 +1,155 @@
/*! DataTables 1.10.1
* ©2008-2014 SpryMedia Ltd - datatables.net/license
*/
(function(za,O,l){var N=function(h){function T(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()),d[c]=e,"o"===b[1]&&T(a[e])});a._hungarianMap=d}function G(a,b,c){a._hungarianMap||T(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==l&&(c||b[d]===l))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),G(a[d],b[d],c)):b[d]=b[e]})}function N(a){var b=p.defaults.oLanguage,c=a.sZeroRecords;
!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&D(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&D(a,a,"sZeroRecords","sLoadingRecords");a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&cb(a)}function db(a){w(a,"ordering","bSort");w(a,"orderMulti","bSortMulti");w(a,"orderClasses","bSortClasses");w(a,"orderCellsTop","bSortCellsTop");w(a,"order","aaSorting");w(a,"orderFixed","aaSortingFixed");w(a,"paging","bPaginate");
w(a,"pagingType","sPaginationType");w(a,"pageLength","iDisplayLength");w(a,"searching","bFilter");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&G(p.models.oSearch,a[b])}function eb(a){w(a,"orderable","bSortable");w(a,"orderData","aDataSort");w(a,"orderSequence","asSorting");w(a,"orderDataType","sortDataType")}function fb(a){var a=a.oBrowser,b=h("<div/>").css({position:"absolute",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",top:1,left:1,width:100,
overflow:"scroll"}).append(h('<div class="test"/>').css({width:"100%",height:10}))).appendTo("body"),c=b.find(".test");a.bScrollOversize=100===c[0].offsetWidth;a.bScrollbarLeft=1!==c.offset().left;b.remove()}function gb(a,b,c,d,e,f){var g,j=!1;c!==l&&(g=c,j=!0);for(;d!==e;)a.hasOwnProperty(d)&&(g=j?b(g,a[d],d,a):a[d],j=!0,d+=f);return g}function Aa(a,b){var c=p.defaults.column,d=a.aoColumns.length,c=h.extend({},p.models.oColumn,c,{nTh:b?b:O.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:
"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=h.extend({},p.models.oSearch,c[d]);fa(a,d,null)}function fa(a,b,c){var b=a.aoColumns[b],d=a.oClasses,e=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=e.attr("width")||null;var f=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==l&&null!==c&&(eb(c),G(p.defaults.column,c),c.mDataProp!==l&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&
!c.sClass&&(c.sClass=c.className),h.extend(b,c),D(b,c,"sWidth","sWidthOrig"),"number"===typeof c.iDataSort&&(b.aDataSort=[c.iDataSort]),D(b,c,"aDataSort"));var g=b.mData,j=U(g),i=b.mRender?U(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b.fnGetData=function(a,b,c){var d=j(a,b,l,c);return i&&b?i(d,b,a,c):d};b.fnSetData=function(a,b,c){return Ba(g)(a,b,c)};a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));
a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI)}function V(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Ca(a);for(var c=0,d=b.length;c<d;c++)b[c].nTh.style.width=b[c].sWidth}b=
a.oScroll;(""!==b.sY||""!==b.sX)&&W(a);u(a,null,"column-sizing",[a])}function ga(a,b){var c=X(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function Y(a,b){var c=X(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}function Z(a){return X(a,"bVisible").length}function X(a,b){var c=[];h.map(a.aoColumns,function(a,e){a[b]&&c.push(e)});return c}function Da(a){var b=a.aoColumns,c=a.aoData,d=p.ext.type.detect,e,f,g,j,i,h,m,n,k;e=0;for(f=b.length;e<f;e++)if(m=b[e],k=[],!m.sType&&m._sManualType)m.sType=
m._sManualType;else if(!m.sType){g=0;for(j=d.length;g<j;g++){i=0;for(h=c.length;i<h&&!(k[i]===l&&(k[i]=A(a,i,e,"type")),n=d[g](k[i],a),!n||"html"===n);i++);if(n){m.sType=n;break}}m.sType||(m.sType="string")}}function hb(a,b,c,d){var e,f,g,j,i,o,m=a.aoColumns;if(b)for(e=b.length-1;0<=e;e--){o=b[e];var n=o.targets!==l?o.targets:o.aTargets;h.isArray(n)||(n=[n]);f=0;for(g=n.length;f<g;f++)if("number"===typeof n[f]&&0<=n[f]){for(;m.length<=n[f];)Aa(a);d(n[f],o)}else if("number"===typeof n[f]&&0>n[f])d(m.length+
n[f],o);else if("string"===typeof n[f]){j=0;for(i=m.length;j<i;j++)("_all"==n[f]||h(m[j].nTh).hasClass(n[f]))&&d(j,o)}}if(c){e=0;for(a=c.length;e<a;e++)d(e,c[e])}}function I(a,b,c,d){var e=a.aoData.length,f=h.extend(!0,{},p.models.oRow,{src:c?"dom":"data"});f._aData=b;a.aoData.push(f);for(var b=a.aoColumns,f=0,g=b.length;f<g;f++)c&&Ea(a,e,f,A(a,e,f)),b[f].sType=null;a.aiDisplayMaster.push(e);(c||!a.oFeatures.bDeferRender)&&Fa(a,e,c,d);return e}function ha(a,b){var c;b instanceof h||(b=h(b));return b.map(function(b,
e){c=ia(a,e);return I(a,c.data,e,c.cells)})}function A(a,b,c,d){var e=a.iDraw,f=a.aoColumns[c],g=a.aoData[b]._aData,j=f.sDefaultContent,c=f.fnGetData(g,d,{settings:a,row:b,col:c});if(c===l)return a.iDrawError!=e&&null===j&&(P(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b,4),a.iDrawError=e),j;if((c===g||null===c)&&null!==j)c=j;else if("function"===typeof c)return c.call(g);return null===c&&"display"==d?"":c}function Ea(a,b,c,d){a.aoColumns[c].fnSetData(a.aoData[b]._aData,
d,{settings:a,row:b,col:c})}function Ga(a){return h.map(a.match(/(\\.|[^\.])+/g),function(a){return a.replace(/\\./g,".")})}function U(a){if(h.isPlainObject(a)){var b={};h.each(a,function(a,c){c&&(b[a]=U(c))});return function(a,c,f,g){var j=b[c]||b._;return j!==l?j(a,c,f,g):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,c,f,g){return a(b,c,f,g)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,b,f){var g,
j;if(""!==f){j=Ga(f);for(var i=0,h=j.length;i<h;i++){f=j[i].match($);g=j[i].match(Q);if(f){j[i]=j[i].replace($,"");""!==j[i]&&(a=a[j[i]]);g=[];j.splice(0,i+1);j=j.join(".");i=0;for(h=a.length;i<h;i++)g.push(c(a[i],b,j));a=f[0].substring(1,f[0].length-1);a=""===a?g:g.join(a);break}else if(g){j[i]=j[i].replace(Q,"");a=a[j[i]]();continue}if(null===a||a[j[i]]===l)return l;a=a[j[i]]}}return a};return function(b,e){return c(b,e,a)}}return function(b){return b[a]}}function Ba(a){if(h.isPlainObject(a))return Ba(a._);
if(null===a)return function(){};if("function"===typeof a)return function(b,d,e){a(b,"set",d,e)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,d,e){var e=Ga(e),f;f=e[e.length-1];for(var g,j,i=0,h=e.length-1;i<h;i++){g=e[i].match($);j=e[i].match(Q);if(g){e[i]=e[i].replace($,"");a[e[i]]=[];f=e.slice();f.splice(0,i+1);g=f.join(".");j=0;for(h=d.length;j<h;j++)f={},b(f,d[j],g),a[e[i]].push(f);return}j&&(e[i]=e[i].replace(Q,""),a=a[e[i]](d));if(null===
a[e[i]]||a[e[i]]===l)a[e[i]]={};a=a[e[i]]}if(f.match(Q))a[f.replace(Q,"")](d);else a[f.replace($,"")]=d};return function(c,d){return b(c,d,a)}}return function(b,d){b[a]=d}}function Ha(a){return C(a.aoData,"_aData")}function ja(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0}function ka(a,b,c){for(var d=-1,e=0,f=a.length;e<f;e++)a[e]==b?d=e:a[e]>b&&a[e]--; -1!=d&&c===l&&a.splice(d,1)}function la(a,b,c,d){var e=a.aoData[b],f;if("dom"===c||(!c||"auto"===c)&&"dom"===e.src)e._aData=
ia(a,e).data;else{var g=e.anCells,j;if(g){c=0;for(f=g.length;c<f;c++){for(j=g[c];j.childNodes.length;)j.removeChild(j.firstChild);g[c].innerHTML=A(a,b,c,"display")}}}e._aSortData=null;e._aFilterData=null;a=a.aoColumns;if(d!==l)a[d].sType=null;else{c=0;for(f=a.length;c<f;c++)a[c].sType=null}Ia(e)}function ia(a,b){var c=[],d=[],e=b.firstChild,f,g,j,i=0,o,m=a.aoColumns,n=function(a,b,c){"string"===typeof a&&(b=a.indexOf("@"),-1!==b&&(a=a.substring(b+1),j["@"+a]=c.getAttribute(a)))},k=function(a){g=m[i];
o=h.trim(a.innerHTML);g&&g._bAttrSrc?(j={display:o},n(g.mData.sort,j,a),n(g.mData.type,j,a),n(g.mData.filter,j,a),c.push(j)):c.push(o);i++};if(e)for(;e;){f=e.nodeName.toUpperCase();if("TD"==f||"TH"==f)k(e),d.push(e);e=e.nextSibling}else{d=b.anCells;e=0;for(f=d.length;e<f;e++)k(d[e])}return{data:c,cells:d}}function Fa(a,b,c,d){var e=a.aoData[b],f=e._aData,g=[],j,i,h,m,n;if(null===e.nTr){j=c||O.createElement("tr");e.nTr=j;e.anCells=g;j._DT_RowIndex=b;Ia(e);m=0;for(n=a.aoColumns.length;m<n;m++){h=a.aoColumns[m];
i=c?d[m]:O.createElement(h.sCellType);g.push(i);if(!c||h.mRender||h.mData!==m)i.innerHTML=A(a,b,m,"display");h.sClass&&(i.className+=" "+h.sClass);h.bVisible&&!c?j.appendChild(i):!h.bVisible&&c&&i.parentNode.removeChild(i);h.fnCreatedCell&&h.fnCreatedCell.call(a.oInstance,i,A(a,b,m),f,b,m)}u(a,"aoRowCreatedCallback",null,[j,f,b])}e.nTr.setAttribute("role","row")}function Ia(a){var b=a.nTr,c=a._aData;if(b){c.DT_RowId&&(b.id=c.DT_RowId);if(c.DT_RowClass){var d=c.DT_RowClass.split(" ");a.__rowc=a.__rowc?
Ja(a.__rowc.concat(d)):d;h(b).removeClass(a.__rowc.join(" ")).addClass(c.DT_RowClass)}c.DT_RowData&&h(b).data(c.DT_RowData)}}function ib(a){var b,c,d,e,f,g=a.nTHead,j=a.nTFoot,i=0===h("th, td",g).length,o=a.oClasses,m=a.aoColumns;i&&(e=h("<tr/>").appendTo(g));b=0;for(c=m.length;b<c;b++)f=m[b],d=h(f.nTh).addClass(f.sClass),i&&d.appendTo(e),a.oFeatures.bSort&&(d.addClass(f.sSortingClass),!1!==f.bSortable&&(d.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),Ka(a,f.nTh,b))),f.sTitle!=d.html()&&
d.html(f.sTitle),La(a,"header")(a,d,f,o);i&&aa(a.aoHeader,g);h(g).find(">tr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(o.sHeaderTH);h(j).find(">tr>th, >tr>td").addClass(o.sFooterTH);if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=m[b],f.nTf=a[b].cell,f.sClass&&h(f.nTf).addClass(f.sClass)}}function ba(a,b,c){var d,e,f,g=[],j=[],i=a.aoColumns.length,o;if(b){c===l&&(c=!1);d=0;for(e=b.length;d<e;d++){g[d]=b[d].slice();g[d].nTr=b[d].nTr;for(f=i-1;0<=f;f--)!a.aoColumns[f].bVisible&&
!c&&g[d].splice(f,1);j.push([])}d=0;for(e=g.length;d<e;d++){if(a=g[d].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[d].length;f<b;f++)if(o=i=1,j[d][f]===l){a.appendChild(g[d][f].cell);for(j[d][f]=1;g[d+i]!==l&&g[d][f].cell==g[d+i][f].cell;)j[d+i][f]=1,i++;for(;g[d][f+o]!==l&&g[d][f].cell==g[d][f+o].cell;){for(c=0;c<i;c++)j[d+c][f+o]=1;o++}h(g[d][f].cell).attr("rowspan",i).attr("colspan",o)}}}}function K(a){var b=u(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))B(a,!1);else{var b=
[],c=0,d=a.asStripeClasses,e=d.length,f=a.oLanguage,g=a.iInitDisplayStart,j="ssp"==z(a),i=a.aiDisplay;a.bDrawing=!0;g!==l&&-1!==g&&(a._iDisplayStart=j?g:g>=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=-1);var g=a._iDisplayStart,o=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,B(a,!1);else if(j){if(!a.bDestroying&&!jb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:o;for(j=j?0:g;j<f;j++){var m=i[j],n=a.aoData[m];null===n.nTr&&Fa(a,m);m=n.nTr;if(0!==e){var k=d[c%e];n._sRowStripe!=
k&&(h(m).removeClass(n._sRowStripe).addClass(k),n._sRowStripe=k)}u(a,"aoRowCallback",null,[m,n._aData,c,j]);b.push(m);c++}}else c=f.sZeroRecords,1==a.iDraw&&"ajax"==z(a)?c=f.sLoadingRecords:f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=h("<tr/>",{"class":e?d[0]:""}).append(h("<td />",{valign:"top",colSpan:Z(a),"class":a.oClasses.sRowEmpty}).html(c))[0];u(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ha(a),g,o,i]);u(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],
Ha(a),g,o,i]);d=h(a.nTBody);d.children().detach();d.append(h(b));u(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function L(a,b){var c=a.oFeatures,d=c.bFilter;c.bSort&&kb(a);d?ca(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;K(a);a._drawHold=!1}function lb(a){var b=a.oClasses,c=h(a.nTable),c=h("<div/>").insertBefore(c),d=a.oFeatures,e=h("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});
a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,o,m,n,k=0;k<f.length;k++){g=null;j=f[k];if("<"==j){i=h("<div/>")[0];o=f[k+1];if("'"==o||'"'==o){m="";for(n=2;f[k+n]!=o;)m+=f[k+n],n++;"H"==m?m=b.sJUIHeader:"F"==m&&(m=b.sJUIFooter);-1!=m.indexOf(".")?(o=m.split("."),i.id=o[0].substr(1,o[0].length-1),i.className=o[1]):"#"==m.charAt(0)?i.id=m.substr(1,m.length-1):i.className=m;k+=n}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==
j&&d.bPaginate&&d.bLengthChange)g=mb(a);else if("f"==j&&d.bFilter)g=nb(a);else if("r"==j&&d.bProcessing)g=ob(a);else if("t"==j)g=pb(a);else if("i"==j&&d.bInfo)g=qb(a);else if("p"==j&&d.bPaginate)g=rb(a);else if(0!==p.ext.feature.length){i=p.ext.feature;n=0;for(o=i.length;n<o;n++)if(j==i[n].cFeature){g=i[n].fnInit(a);break}}g&&(i=a.aanFeatures,i[j]||(i[j]=[]),i[j].push(g),e.append(g))}c.replaceWith(e)}function aa(a,b){var c=h(b).children("tr"),d,e,f,g,j,i,o,m,n,k;a.splice(0,a.length);f=0;for(i=c.length;f<
i;f++)a.push([]);f=0;for(i=c.length;f<i;f++){d=c[f];for(e=d.firstChild;e;){if("TD"==e.nodeName.toUpperCase()||"TH"==e.nodeName.toUpperCase()){m=1*e.getAttribute("colspan");n=1*e.getAttribute("rowspan");m=!m||0===m||1===m?1:m;n=!n||0===n||1===n?1:n;g=0;for(j=a[f];j[g];)g++;o=g;k=1===m?!0:!1;for(j=0;j<m;j++)for(g=0;g<n;g++)a[f+g][o+j]={cell:e,unique:k},a[f+g].nTr=d}e=e.nextSibling}}}function ma(a,b,c){var d=[];c||(c=a.aoHeader,b&&(c=[],aa(c,b)));for(var b=0,e=c.length;b<e;b++)for(var f=0,g=c[b].length;f<
g;f++)if(c[b][f].unique&&(!d[f]||!a.bSortCellsTop))d[f]=c[b][f].cell;return d}function na(a,b,c){u(a,"aoServerParams","serverParams",[b]);if(b&&h.isArray(b)){var d={},e=/(.*?)\[\]$/;h.each(b,function(a,b){var c=b.name.match(e);c?(c=c[0],d[c]||(d[c]=[]),d[c].push(b.value)):d[b.name]=b.value});b=d}var f,g=a.ajax,j=a.oInstance;if(h.isPlainObject(g)&&g.data){f=g.data;var i=h.isFunction(f)?f(b):f,b=h.isFunction(f)&&i?i:h.extend(!0,b,i);delete g.data}i={data:b,success:function(b){var d=b.error||b.sError;
d&&a.oApi._fnLog(a,0,d);a.json=b;u(a,null,"xhr",[a,b]);c(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,c){var d=a.oApi._fnLog;"parsererror"==c?d(a,0,"Invalid JSON response",1):4===b.readyState&&d(a,0,"Ajax error",7);B(a,!1)}};a.oAjaxData=b;u(a,null,"preXhr",[a,b]);a.fnServerData?a.fnServerData.call(j,a.sAjaxSource,h.map(b,function(a,b){return{name:b,value:a}}),c,a):a.sAjaxSource||"string"===typeof g?a.jqXHR=h.ajax(h.extend(i,{url:g||a.sAjaxSource})):h.isFunction(g)?a.jqXHR=g.call(j,
b,c,a):(a.jqXHR=h.ajax(h.extend(i,g)),g.data=f)}function jb(a){return a.bAjaxDataGet?(a.iDraw++,B(a,!0),na(a,sb(a),function(b){tb(a,b)}),!1):!0}function sb(a){var b=a.aoColumns,c=b.length,d=a.oFeatures,e=a.oPreviousSearch,f=a.aoPreSearchCols,g,j=[],i,o,m,n=R(a);g=a._iDisplayStart;i=!1!==d.bPaginate?a._iDisplayLength:-1;var k=function(a,b){j.push({name:a,value:b})};k("sEcho",a.iDraw);k("iColumns",c);k("sColumns",C(b,"sName").join(","));k("iDisplayStart",g);k("iDisplayLength",i);var l={draw:a.iDraw,
columns:[],order:[],start:g,length:i,search:{value:e.sSearch,regex:e.bRegex}};for(g=0;g<c;g++)o=b[g],m=f[g],i="function"==typeof o.mData?"function":o.mData,l.columns.push({data:i,name:o.sName,searchable:o.bSearchable,orderable:o.bSortable,search:{value:m.sSearch,regex:m.bRegex}}),k("mDataProp_"+g,i),d.bFilter&&(k("sSearch_"+g,m.sSearch),k("bRegex_"+g,m.bRegex),k("bSearchable_"+g,o.bSearchable)),d.bSort&&k("bSortable_"+g,o.bSortable);d.bFilter&&(k("sSearch",e.sSearch),k("bRegex",e.bRegex));d.bSort&&
(h.each(n,function(a,b){l.order.push({column:b.col,dir:b.dir});k("iSortCol_"+a,b.col);k("sSortDir_"+a,b.dir)}),k("iSortingCols",n.length));b=p.ext.legacy.ajax;return null===b?a.sAjaxSource?j:l:b?j:l}function tb(a,b){var c=b.sEcho!==l?b.sEcho:b.draw,d=b.iTotalRecords!==l?b.iTotalRecords:b.recordsTotal,e=b.iTotalDisplayRecords!==l?b.iTotalDisplayRecords:b.recordsFiltered;if(c){if(1*c<a.iDraw)return;a.iDraw=1*c}ja(a);a._iRecordsTotal=parseInt(d,10);a._iRecordsDisplay=parseInt(e,10);c=oa(a,b);d=0;for(e=
c.length;d<e;d++)I(a,c[d]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;K(a);a._bInitComplete||pa(a,b);a.bAjaxDataGet=!0;B(a,!1)}function oa(a,b){var c=h.isPlainObject(a.ajax)&&a.ajax.dataSrc!==l?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?U(c)(b):b}function nb(a){var b=a.oClasses,c=a.sTableId,d=a.oLanguage,e=a.oPreviousSearch,f=a.aanFeatures,g='<input type="search" class="'+b.sFilterInput+'"/>',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("<div/>",
{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("<label/>").append(j)),f=function(){var b=!this.value?"":this.value;b!=e.sSearch&&(ca(a,{sSearch:b,bRegex:e.bRegex,bSmart:e.bSmart,bCaseInsensitive:e.bCaseInsensitive}),a._iDisplayStart=0,K(a))},i=h("input",b).val(e.sSearch).attr("placeholder",d.sSearchPlaceholder).bind("keyup.DT search.DT input.DT paste.DT cut.DT","ssp"===z(a)?Ma(f,400):f).bind("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);h(a.nTable).on("search.dt.DT",
function(b,c){if(a===c)try{i[0]!==O.activeElement&&i.val(e.sSearch)}catch(d){}});return b[0]}function ca(a,b,c){var d=a.oPreviousSearch,e=a.aoPreSearchCols,f=function(a){d.sSearch=a.sSearch;d.bRegex=a.bRegex;d.bSmart=a.bSmart;d.bCaseInsensitive=a.bCaseInsensitive};Da(a);if("ssp"!=z(a)){ub(a,b.sSearch,c,b.bEscapeRegex!==l?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<e.length;b++)vb(a,e[b].sSearch,b,e[b].bEscapeRegex!==l?!e[b].bEscapeRegex:e[b].bRegex,e[b].bSmart,e[b].bCaseInsensitive);
wb(a)}else f(b);a.bFiltered=!0;u(a,null,"search",[a])}function wb(a){for(var b=p.ext.search,c=a.aiDisplay,d,e,f=0,g=b.length;f<g;f++){for(var j=[],i=0,h=c.length;i<h;i++)e=c[i],d=a.aoData[e],b[f](a,d._aFilterData,e,d._aData,i)&&j.push(e);c.length=0;c.push.apply(c,j)}}function vb(a,b,c,d,e,f){if(""!==b)for(var g=a.aiDisplay,d=Na(b,d,e,f),e=g.length-1;0<=e;e--)b=a.aoData[g[e]]._aFilterData[c],d.test(b)||g.splice(e,1)}function ub(a,b,c,d,e,f){var d=Na(b,d,e,f),e=a.oPreviousSearch.sSearch,f=a.aiDisplayMaster,
g;0!==p.ext.search.length&&(c=!0);g=xb(a);if(0>=b.length)a.aiDisplay=f.slice();else{if(g||c||e.length>b.length||0!==b.indexOf(e)||a.bSorted)a.aiDisplay=f.slice();b=a.aiDisplay;for(c=b.length-1;0<=c;c--)d.test(a.aoData[b[c]]._sFilterRow)||b.splice(c,1)}}function Na(a,b,c,d){a=b?a:Oa(a);c&&(a="^(?=.*?"+h.map(a.match(/"[^"]+"|[^ ]+/g)||"",function(a){return'"'===a.charAt(0)?a.match(/^"(.*)"$/)[1]:a}).join(")(?=.*?")+").*$");return RegExp(a,d?"i":"")}function Oa(a){return a.replace(Vb,"\\$1")}function xb(a){var b=
a.aoColumns,c,d,e,f,g,j,i,h,m=p.ext.type.search;c=!1;d=0;for(f=a.aoData.length;d<f;d++)if(h=a.aoData[d],!h._aFilterData){j=[];e=0;for(g=b.length;e<g;e++)if(c=b[e],c.bSearchable?(i=A(a,d,e,"filter"),i=m[c.sType]?m[c.sType](i):null!==i?i:""):i="",i)i.indexOf&&-1!==i.indexOf("&")&&(qa.innerHTML=i,i=Wb?qa.textContent:qa.innerText),i.replace&&(i=i.replace(/[\r\n]/g,"")),j.push(i);h._aFilterData=j;h._sFilterRow=j.join(" ");c=!0}return c}function yb(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,
caseInsensitive:a.bCaseInsensitive}}function zb(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}function qb(a){var b=a.sTableId,c=a.aanFeatures.i,d=h("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Ab,sName:"information"}),d.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",b+"_info"));return d[0]}function Ab(a){var b=a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,d=a._iDisplayStart+
1,e=a.fnDisplayEnd(),f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Bb(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,d,e,f,g,j));h(b).html(j)}}function Bb(a,b){var c=a.fnFormatNumber,d=a._iDisplayStart+1,e=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===e;return b.replace(/_START_/g,c.call(a,d)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,
f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(d/e))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/e)))}function ra(a){var b,c,d=a.iInitDisplayStart,e=a.aoColumns,f;c=a.oFeatures;if(a.bInitialised){lb(a);ib(a);ba(a,a.aoHeader);ba(a,a.aoFooter);B(a,!0);c.bAutoWidth&&Ca(a);b=0;for(c=e.length;b<c;b++)f=e[b],f.sWidth&&(f.nTh.style.width=s(f.sWidth));L(a);e=z(a);"ssp"!=e&&("ajax"==e?na(a,[],function(c){var f=oa(a,c);for(b=0;b<f.length;b++)I(a,f[b]);a.iInitDisplayStart=d;L(a);B(a,!1);pa(a,c)},a):(B(a,!1),
pa(a)))}else setTimeout(function(){ra(a)},200)}function pa(a,b){a._bInitComplete=!0;b&&V(a);u(a,"aoInitComplete","init",[a,b])}function Pa(a,b){var c=parseInt(b,10);a._iDisplayLength=c;Qa(a);u(a,null,"length",[a,c])}function mb(a){for(var b=a.oClasses,c=a.sTableId,d=a.aLengthMenu,e=h.isArray(d[0]),f=e?d[0]:d,d=e?d[1]:d,e=h("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g<j;g++)e[0][g]=new Option(d[g],f[g]);var i=h("<div><label/></div>").addClass(b.sLength);
a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).bind("change.DT",function(){Pa(a,h(this).val());K(a)});h(a.nTable).bind("length.dt.DT",function(b,c,d){a===c&&h("select",i).val(d)});return i[0]}function rb(a){var b=a.sPaginationType,c=p.ext.pager[b],d="function"===typeof c,e=function(a){K(a)},b=h("<div/>").addClass(a.oClasses.sPaging+b)[0],f=a.aanFeatures;d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+
"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),m=-1===i,b=m?0:Math.ceil(b/i),i=m?1:Math.ceil(h/i),h=c(b,i),n,m=0;for(n=f.p.length;m<n;m++)La(a,"pageButton")(a,f.p[m],m,h,b,i)}else c.fnUpdate(a,e)},sName:"pagination"}));return b}function Ra(a,b,c){var d=a._iDisplayStart,e=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===e?d=0:"number"===typeof b?(d=b*e,d>f&&(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==
b?d+e<f&&(d+=e):"last"==b?d=Math.floor((f-1)/e)*e:P(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==d;a._iDisplayStart=d;b&&(u(a,null,"page",[a]),c&&K(a));return b}function ob(a){return h("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function B(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none");u(a,null,"processing",[a,b])}function pb(a){var b=h(a.nTable);b.attr("role",
"grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),o=h(b[0].cloneNode(!1)),m=b.children("tfoot");c.sX&&"100%"===b.attr("width")&&b.removeAttr("width");m.length||(m=null);c=h("<div/>",{"class":f.sScrollWrapper}).append(h("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?!d?null:s(d):"100%"}).append(h("<div/>",{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",
width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append(b.children("thead")))).append("top"===j?g:null)).append(h("<div/>",{"class":f.sScrollBody}).css({overflow:"auto",height:!e?null:s(e),width:!d?null:s(d)}).append(b));m&&c.append(h("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:s(d):"100%"}).append(h("<div/>",{"class":f.sScrollFootInner}).append(o.removeAttr("id").css("margin-left",0).append(b.children("tfoot")))).append("bottom"===j?g:
null));var b=c.children(),n=b[0],f=b[1],k=m?b[2]:null;d&&h(f).scroll(function(){var a=this.scrollLeft;n.scrollLeft=a;m&&(k.scrollLeft=a)});a.nScrollHead=n;a.nScrollBody=f;a.nScrollFoot=k;a.aoDrawCallback.push({fn:W,sName:"scrolling"});return c[0]}function W(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,f=b.iBarWidth,g=h(a.nScrollHead),j=g[0].style,i=g.children("div"),o=i[0].style,m=i.children("table"),i=a.nScrollBody,n=h(i),k=i.style,l=h(a.nScrollFoot).children("div"),p=l.children("table"),r=h(a.nTHead),
q=h(a.nTable),da=q[0],M=da.style,J=a.nTFoot?h(a.nTFoot):null,u=a.oBrowser,v=u.bScrollOversize,y,t,x,w,z,A=[],B=[],C=[],D,E=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};q.children("thead, tfoot").remove();z=r.clone().prependTo(q);y=r.find("tr");x=z.find("tr");z.find("th, td").removeAttr("tabindex");J&&(w=J.clone().prependTo(q),t=J.find("tr"),w=w.find("tr"));c||(k.width="100%",g[0].style.width="100%");h.each(ma(a,z),function(b,c){D=
ga(a,b);c.style.width=a.aoColumns[D].sWidth});J&&F(function(a){a.style.width=""},w);b.bCollapse&&""!==e&&(k.height=n[0].offsetHeight+r[0].offsetHeight+"px");g=q.outerWidth();if(""===c){if(M.width="100%",v&&(q.find("tbody").height()>i.offsetHeight||"scroll"==n.css("overflow-y")))M.width=s(q.outerWidth()-f)}else""!==d?M.width=s(d):g==n.width()&&n.height()<q.height()?(M.width=s(g-f),q.outerWidth()>g-f&&(M.width=s(g))):M.width=s(g);g=q.outerWidth();F(E,x);F(function(a){C.push(a.innerHTML);A.push(s(h(a).css("width")))},
x);F(function(a,b){a.style.width=A[b]},y);h(x).height(0);J&&(F(E,w),F(function(a){B.push(s(h(a).css("width")))},w),F(function(a,b){a.style.width=B[b]},t),h(w).height(0));F(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+C[b]+"</div>";a.style.width=A[b]},x);J&&F(function(a,b){a.innerHTML="";a.style.width=B[b]},w);if(q.outerWidth()<g){t=i.scrollHeight>i.offsetHeight||"scroll"==n.css("overflow-y")?g+f:g;if(v&&(i.scrollHeight>i.offsetHeight||"scroll"==n.css("overflow-y")))M.width=
s(t-f);(""===c||""!==d)&&P(a,1,"Possible column misalignment",6)}else t="100%";k.width=s(t);j.width=s(t);J&&(a.nScrollFoot.style.width=s(t));!e&&v&&(k.height=s(da.offsetHeight+f));e&&b.bCollapse&&(k.height=s(e),b=c&&da.offsetWidth>i.offsetWidth?f:0,da.offsetHeight<i.offsetHeight&&(k.height=s(da.offsetHeight+b)));b=q.outerWidth();m[0].style.width=s(b);o.width=s(b);m=q.height()>i.clientHeight||"scroll"==n.css("overflow-y");u="padding"+(u.bScrollbarLeft?"Left":"Right");o[u]=m?f+"px":"0px";J&&(p[0].style.width=
s(b),l[0].style.width=s(b),l[0].style[u]=m?f+"px":"0px");n.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)i.scrollTop=0}function F(a,b,c){for(var d=0,e=0,f=b.length,g,j;e<f;){g=b[e].firstChild;for(j=c?c[e].firstChild:null;g;)1===g.nodeType&&(c?a(g,j,d):a(g,d),d++),g=g.nextSibling,j=c?j.nextSibling:null;e++}}function Ca(a){var b=a.nTable,c=a.aoColumns,d=a.oScroll,e=d.sY,f=d.sX,g=d.sXInner,j=c.length,d=X(a,"bVisible"),i=h("th",a.nTHead),o=b.getAttribute("width"),m=b.parentNode,n=!1,k,l;for(k=0;k<
d.length;k++)l=c[d[k]],null!==l.sWidth&&(l.sWidth=Cb(l.sWidthOrig,m),n=!0);if(!n&&!f&&!e&&j==Z(a)&&j==i.length)for(k=0;k<j;k++)c[k].sWidth=s(i.eq(k).width());else{j=h(b).clone().empty().css("visibility","hidden").removeAttr("id").append(h(a.nTHead).clone(!1)).append(h(a.nTFoot).clone(!1)).append(h("<tbody><tr/></tbody>"));j.find("tfoot th, tfoot td").css("width","");var p=j.find("tbody tr"),i=ma(a,j.find("thead")[0]);for(k=0;k<d.length;k++)l=c[d[k]],i[k].style.width=null!==l.sWidthOrig&&""!==l.sWidthOrig?
s(l.sWidthOrig):"";if(a.aoData.length)for(k=0;k<d.length;k++)n=d[k],l=c[n],h(Db(a,n)).clone(!1).append(l.sContentPadding).appendTo(p);j.appendTo(m);f&&g?j.width(g):f?(j.css("width","auto"),j.width()<m.offsetWidth&&j.width(m.offsetWidth)):e?j.width(m.offsetWidth):o&&j.width(o);Eb(a,j[0]);if(f){for(k=g=0;k<d.length;k++)l=c[d[k]],e=h(i[k]).outerWidth(),g+=null===l.sWidthOrig?e:parseInt(l.sWidth,10)+e-h(i[k]).width();j.width(s(g));b.style.width=s(g)}for(k=0;k<d.length;k++)if(l=c[d[k]],e=h(i[k]).width())l.sWidth=
s(e);b.style.width=s(j.css("width"));j.remove()}o&&(b.style.width=s(o));if((o||f)&&!a._reszEvt)h(za).bind("resize.DT-"+a.sInstance,Ma(function(){V(a)})),a._reszEvt=!0}function Ma(a,b){var c=b||200,d,e;return function(){var b=this,g=+new Date,j=arguments;d&&g<d+c?(clearTimeout(e),e=setTimeout(function(){d=l;a.apply(b,j)},c)):d?(d=g,a.apply(b,j)):d=g}}function Cb(a,b){if(!a)return 0;var c=h("<div/>").css("width",s(a)).appendTo(b||O.body),d=c[0].offsetWidth;c.remove();return d}function Eb(a,b){var c=
a.oScroll;if(c.sX||c.sY)c=!c.sX?c.iBarWidth:0,b.style.width=s(h(b).outerWidth()-c)}function Db(a,b){var c=Fb(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h("<td/>").html(A(a,c,b,"display"))[0]:d.anCells[b]}function Fb(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;f<g;f++)c=A(a,f,b,"display")+"",c=c.replace(Xb,""),c.length>d&&(d=c.length,e=f);return e}function s(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function Gb(){if(!p.__scrollbarWidth){var a=
h("<p/>").css({width:"100%",height:200,padding:0})[0],b=h("<div/>").css({position:"absolute",top:0,left:0,width:200,height:150,padding:0,overflow:"hidden",visibility:"hidden"}).append(a).appendTo("body"),c=a.offsetWidth;b.css("overflow","scroll");a=a.offsetWidth;c===a&&(a=b[0].clientWidth);b.remove();p.__scrollbarWidth=c-a}return p.__scrollbarWidth}function R(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var o=[];f=function(a){a.length&&!h.isArray(a[0])?o.push(a):o.push.apply(o,
a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<o.length;a++){i=o[a][0];f=e[i].aDataSort;b=0;for(c=f.length;b<c;b++)g=f[b],j=e[g].sType||"string",d.push({src:i,col:g,dir:o[a][1],index:o[a][2],type:j,formatter:p.ext.type.order[j+"-pre"]})}return d}function kb(a){var b,c,d=[],e=p.ext.type.order,f=a.aoData,g=0,j,i=a.aiDisplayMaster,h;Da(a);h=R(a);b=0;for(c=h.length;b<c;b++)j=h[b],j.formatter&&g++,Hb(a,j.col);if("ssp"!=z(a)&&0!==h.length){b=0;for(c=i.length;b<c;b++)d[i[b]]=
b;g===h.length?i.sort(function(a,b){var c,e,g,j,i=h.length,l=f[a]._aSortData,p=f[b]._aSortData;for(g=0;g<i;g++)if(j=h[g],c=l[j.col],e=p[j.col],c=c<e?-1:c>e?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return c<e?-1:c>e?1:0}):i.sort(function(a,b){var c,g,j,i,l=h.length,p=f[a]._aSortData,r=f[b]._aSortData;for(j=0;j<l;j++)if(i=h[j],c=p[i.col],g=r[i.col],i=e[i.type+"-"+i.dir]||e["string-"+i.dir],c=i(c,g),0!==c)return c;c=d[a];g=d[b];return c<g?-1:c>g?1:0})}a.bSorted=!0}function Ib(a){for(var b,c,
d=a.aoColumns,e=R(a),a=a.oLanguage.oAria,f=0,g=d.length;f<g;f++){c=d[f];var j=c.asSorting;b=c.sTitle.replace(/<.*?>/g,"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0<e.length&&e[0].col==f?(i.setAttribute("aria-sort","asc"==e[0].dir?"ascending":"descending"),c=j[e[0].index+1]||j[0]):c=j[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);i.setAttribute("aria-label",b)}}function Sa(a,b,c,d){var e=a.aaSorting,f=a.aoColumns[b].asSorting,g=function(a){var b=a._idx;b===l&&(b=h.inArray(a[1],
f));return b+1>=f.length?0:b+1};"number"===typeof e[0]&&(e=a.aaSorting=[e]);c&&a.oFeatures.bSortMulti?(c=h.inArray(b,C(e,"0")),-1!==c?(b=g(e[c]),e[c][1]=f[b],e[c]._idx=b):(e.push([b,f[0],0]),e[e.length-1]._idx=0)):e.length&&e[0][0]==b?(b=g(e[0]),e.length=1,e[0][1]=f[b],e[0]._idx=b):(e.length=0,e.push([b,f[0]]),e[0]._idx=0);L(a);"function"==typeof d&&d(a)}function Ka(a,b,c,d){var e=a.aoColumns[c];Ta(b,{},function(b){!1!==e.bSortable&&(a.oFeatures.bProcessing?(B(a,!0),setTimeout(function(){Sa(a,c,b.shiftKey,
d);"ssp"!==z(a)&&B(a,!1)},0)):Sa(a,c,b.shiftKey,d))})}function sa(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,d=R(a),e=a.oFeatures,f,g;if(e.bSort&&e.bSortClasses){e=0;for(f=b.length;e<f;e++)g=b[e].src,h(C(a.aoData,"anCells",g)).removeClass(c+(2>e?e+1:3));e=0;for(f=d.length;e<f;e++)g=d[e].src,h(C(a.aoData,"anCells",g)).addClass(c+(2>e?e+1:3))}a.aLastSort=d}function Hb(a,b){var c=a.aoColumns[b],d=p.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,Y(a,b)));for(var f,g=p.ext.type.order[c.sType+
"-pre"],j=0,i=a.aoData.length;j<i;j++)if(c=a.aoData[j],c._aSortData||(c._aSortData=[]),!c._aSortData[b]||d)f=d?e[j]:A(a,j,b,"sort"),c._aSortData[b]=g?g(f):f}function ta(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:h.extend(!0,[],a.aaSorting),search:yb(a.oPreviousSearch),columns:h.map(a.aoColumns,function(b,d){return{visible:b.bVisible,search:yb(a.aoPreSearchCols[d])}})};u(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=
b;a.fnStateSaveCallback.call(a.oInstance,a,b)}}function Jb(a){var b,c,d=a.aoColumns;if(a.oFeatures.bStateSave){var e=a.fnStateLoadCallback.call(a.oInstance,a);if(e&&e.time&&(b=u(a,"aoStateLoadParams","stateLoadParams",[a,e]),-1===h.inArray(!1,b)&&(b=a.iStateDuration,!(0<b&&e.time<+new Date-1E3*b)&&d.length===e.columns.length))){a.oLoadedState=h.extend(!0,{},e);a._iDisplayStart=e.start;a.iInitDisplayStart=e.start;a._iDisplayLength=e.length;a.aaSorting=[];h.each(e.order,function(b,c){a.aaSorting.push(c[0]>=
d.length?[0,c[1]]:c)});h.extend(a.oPreviousSearch,zb(e.search));b=0;for(c=e.columns.length;b<c;b++){var f=e.columns[b];d[b].bVisible=f.visible;h.extend(a.aoPreSearchCols[b],zb(f.search))}u(a,"aoStateLoaded","stateLoaded",[a,e])}}}function ua(a){var b=p.settings,a=h.inArray(a,C(b,"nTable"));return-1!==a?b[a]:null}function P(a,b,c,d){c="DataTables warning: "+(null!==a?"table id="+a.sTableId+" - ":"")+c;d&&(c+=". For more information about this error, please see http://datatables.net/tn/"+d);if(b)za.console&&
console.log&&console.log(c);else if(a=p.ext,"alert"==(a.sErrMode||a.errMode))alert(c);else throw Error(c);}function D(a,b,c,d){h.isArray(c)?h.each(c,function(c,d){h.isArray(d)?D(a,b,d[0],d[1]):D(a,b,d)}):(d===l&&(d=c),b[c]!==l&&(a[d]=b[c]))}function Kb(a,b,c){var d,e;for(e in b)b.hasOwnProperty(e)&&(d=b[e],h.isPlainObject(d)?(h.isPlainObject(a[e])||(a[e]={}),h.extend(!0,a[e],d)):a[e]=c&&"data"!==e&&"aaData"!==e&&h.isArray(d)?d.slice():d);return a}function Ta(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();
c(b)}).bind("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).bind("selectstart.DT",function(){return!1})}function x(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function u(a,b,c,d){var e=[];b&&(e=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,d)}));null!==c&&h(a.nTable).trigger(c+".dt",d);return e}function Qa(a){var b=a._iDisplayStart,c=a.fnDisplayEnd(),d=a._iDisplayLength;c===a.fnRecordsDisplay()&&(b=c-d);if(-1===d||0>b)b=0;a._iDisplayStart=b}function La(a,b){var c=
a.renderer,d=p.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function z(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Ua(a,b){var c=[],c=Lb.numbers_length,d=Math.floor(c/2);b<=c?c=S(0,b):a<=d?(c=S(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=S(b-(c-2),b):(c=S(a-1,a+2),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function cb(a){h.each({num:function(b){return va(b,
a)},"num-fmt":function(b){return va(b,a,Va)},"html-num":function(b){return va(b,a,wa)},"html-num-fmt":function(b){return va(b,a,wa,Va)}},function(b,c){t.type.order[b+a+"-pre"]=c})}function Mb(a){return function(){var b=[ua(this[p.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return p.ext.internal[a].apply(this,b)}}var p,t,q,r,v,Wa={},Nb=/[\r\n]/g,wa=/<.*?>/g,Yb=/^[\w\+\-]/,Zb=/[\w\+\-]$/,Vb=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Va=/[',$\u00a3\u20ac\u00a5%\u2009\u202F]/g,
H=function(a){return!a||!0===a||"-"===a?!0:!1},Ob=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Pb=function(a,b){Wa[b]||(Wa[b]=RegExp(Oa(b),"g"));return"string"===typeof a?a.replace(/\./g,"").replace(Wa[b],"."):a},Xa=function(a,b,c){var d="string"===typeof a;b&&d&&(a=Pb(a,b));c&&d&&(a=a.replace(Va,""));return H(a)||!isNaN(parseFloat(a))&&isFinite(a)},Qb=function(a,b,c){return H(a)?!0:!(H(a)||"string"===typeof a)?null:Xa(a.replace(wa,""),b,c)?!0:null},C=function(a,b,c){var d=
[],e=0,f=a.length;if(c!==l)for(;e<f;e++)a[e]&&a[e][b]&&d.push(a[e][b][c]);else for(;e<f;e++)a[e]&&d.push(a[e][b]);return d},xa=function(a,b,c,d){var e=[],f=0,g=b.length;if(d!==l)for(;f<g;f++)e.push(a[b[f]][c][d]);else for(;f<g;f++)e.push(a[b[f]][c]);return e},S=function(a,b){var c=[],d;b===l?(b=0,d=a):(d=b,b=a);for(var e=b;e<d;e++)c.push(e);return c},Ja=function(a){var b=[],c,d,e=a.length,f,g=0;d=0;a:for(;d<e;d++){c=a[d];for(f=0;f<g;f++)if(b[f]===c)continue a;b.push(c);g++}return b},w=function(a,
b,c){a[b]!==l&&(a[c]=a[b])},$=/\[.*?\]$/,Q=/\(\)$/,qa=h("<div>")[0],Wb=qa.textContent!==l,Xb=/<.*?>/g;p=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new q(ua(this[t.iApiIndex])):new q(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===l||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing=
function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===l||a?b.draw(!1):(""!==d.sX||""!==d.sY)&&W(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===l||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===l||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(!a)};
this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===l?e.search(a,c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==l){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==l||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==l?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();
return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===l||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===l||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return ua(this[t.iApiIndex])};
this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===l||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===l||e)&&h.columns.adjust();(d===l||d)&&h.draw();return 0};this.fnVersionCheck=t.fnVersionCheck;var b=this,c=a===l,d=this.length;c&&(a={});this.oApi=this.internal=t.internal;for(var e in p.ext.internal)e&&(this[e]=Mb(e));this.each(function(){var e={},g=1<d?Kb(e,a,!0):
a,j=0,i,o=this.getAttribute("id"),e=!1,m=p.defaults;if("table"!=this.nodeName.toLowerCase())P(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{db(m);eb(m.column);G(m,m,!0);G(m.column,m.column,!0);G(m,g);var n=p.settings,j=0;for(i=n.length;j<i;j++){if(n[j].nTable==this){i=g.bRetrieve!==l?g.bRetrieve:m.bRetrieve;if(c||i)return n[j].oInstance;if(g.bDestroy!==l?g.bDestroy:m.bDestroy){n[j].oInstance.fnDestroy();break}else{P(n[j],0,"Cannot reinitialise DataTable",3);return}}if(n[j].sTableId==
this.id){n.splice(j,1);break}}if(null===o||""===o)this.id=o="DataTables_Table_"+p.ext._unique++;var k=h.extend(!0,{},p.models.oSettings,{nTable:this,oApi:b.internal,oInit:g,sDestroyWidth:h(this)[0].style.width,sInstance:o,sTableId:o});n.push(k);k.oInstance=1===b.length?b:h(this).dataTable();db(g);g.oLanguage&&N(g.oLanguage);g.aLengthMenu&&!g.iDisplayLength&&(g.iDisplayLength=h.isArray(g.aLengthMenu[0])?g.aLengthMenu[0][0]:g.aLengthMenu[0]);g=Kb(h.extend(!0,{},m),g);D(k.oFeatures,g,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));
D(k,g,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback","renderer",["iCookieDuration","iStateDuration"],["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"],["bJQueryUI","bJUI"]]);D(k.oScroll,g,[["sScrollX","sX"],["sScrollXInner","sXInner"],
["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);D(k.oLanguage,g,"fnInfoCallback");x(k,"aoDrawCallback",g.fnDrawCallback,"user");x(k,"aoServerParams",g.fnServerParams,"user");x(k,"aoStateSaveParams",g.fnStateSaveParams,"user");x(k,"aoStateLoadParams",g.fnStateLoadParams,"user");x(k,"aoStateLoaded",g.fnStateLoaded,"user");x(k,"aoRowCallback",g.fnRowCallback,"user");x(k,"aoRowCreatedCallback",g.fnCreatedRow,"user");x(k,"aoHeaderCallback",g.fnHeaderCallback,"user");x(k,"aoFooterCallback",g.fnFooterCallback,
"user");x(k,"aoInitComplete",g.fnInitComplete,"user");x(k,"aoPreDrawCallback",g.fnPreDrawCallback,"user");o=k.oClasses;g.bJQueryUI?(h.extend(o,p.ext.oJUIClasses,g.oClasses),g.sDom===m.sDom&&"lfrtip"===m.sDom&&(k.sDom='<"H"lfr>t<"F"ip>'),k.renderer)?h.isPlainObject(k.renderer)&&!k.renderer.header&&(k.renderer.header="jqueryui"):k.renderer="jqueryui":h.extend(o,p.ext.classes,g.oClasses);h(this).addClass(o.sTable);if(""!==k.oScroll.sX||""!==k.oScroll.sY)k.oScroll.iBarWidth=Gb();!0===k.oScroll.sX&&(k.oScroll.sX=
"100%");k.iInitDisplayStart===l&&(k.iInitDisplayStart=g.iDisplayStart,k._iDisplayStart=g.iDisplayStart);null!==g.iDeferLoading&&(k.bDeferLoading=!0,j=h.isArray(g.iDeferLoading),k._iRecordsDisplay=j?g.iDeferLoading[0]:g.iDeferLoading,k._iRecordsTotal=j?g.iDeferLoading[1]:g.iDeferLoading);""!==g.oLanguage.sUrl?(k.oLanguage.sUrl=g.oLanguage.sUrl,h.getJSON(k.oLanguage.sUrl,null,function(a){N(a);G(m.oLanguage,a);h.extend(true,k.oLanguage,g.oLanguage,a);ra(k)}),e=!0):h.extend(!0,k.oLanguage,g.oLanguage);
null===g.asStripeClasses&&(k.asStripeClasses=[o.sStripeOdd,o.sStripeEven]);var j=k.asStripeClasses,r=h("tbody tr:eq(0)",this);-1!==h.inArray(!0,h.map(j,function(a){return r.hasClass(a)}))&&(h("tbody tr",this).removeClass(j.join(" ")),k.asDestroyStripes=j.slice());var n=[],q,j=this.getElementsByTagName("thead");0!==j.length&&(aa(k.aoHeader,j[0]),n=ma(k));if(null===g.aoColumns){q=[];j=0;for(i=n.length;j<i;j++)q.push(null)}else q=g.aoColumns;j=0;for(i=q.length;j<i;j++)Aa(k,n?n[j]:null);hb(k,g.aoColumnDefs,
q,function(a,b){fa(k,a,b)});if(r.length){var s=function(a,b){return a.getAttribute("data-"+b)?b:null};h.each(ia(k,r[0]).cells,function(a,b){var c=k.aoColumns[a];if(c.mData===a){var d=s(b,"sort")||s(b,"order"),e=s(b,"filter")||s(b,"search");if(d!==null||e!==null){c.mData={_:a+".display",sort:d!==null?a+".@data-"+d:l,type:d!==null?a+".@data-"+d:l,filter:e!==null?a+".@data-"+e:l};fa(k,a)}}})}var t=k.oFeatures;g.bStateSave&&(t.bStateSave=!0,Jb(k,g),x(k,"aoDrawCallback",ta,"state_save"));if(g.aaSorting===
l){n=k.aaSorting;j=0;for(i=n.length;j<i;j++)n[j][1]=k.aoColumns[j].asSorting[0]}sa(k);t.bSort&&x(k,"aoDrawCallback",function(){if(k.bSorted){var a=R(k),b={};h.each(a,function(a,c){b[c.src]=c.dir});u(k,null,"order",[k,a,b]);Ib(k)}});x(k,"aoDrawCallback",function(){(k.bSorted||z(k)==="ssp"||t.bDeferRender)&&sa(k)},"sc");fb(k);j=h(this).children("caption").each(function(){this._captionSide=h(this).css("caption-side")});i=h(this).children("thead");0===i.length&&(i=h("<thead/>").appendTo(this));k.nTHead=
i[0];i=h(this).children("tbody");0===i.length&&(i=h("<tbody/>").appendTo(this));k.nTBody=i[0];i=h(this).children("tfoot");if(0===i.length&&0<j.length&&(""!==k.oScroll.sX||""!==k.oScroll.sY))i=h("<tfoot/>").appendTo(this);0===i.length||0===i.children().length?h(this).addClass(o.sNoFooter):0<i.length&&(k.nTFoot=i[0],aa(k.aoFooter,k.nTFoot));if(g.aaData)for(j=0;j<g.aaData.length;j++)I(k,g.aaData[j]);else(k.bDeferLoading||"dom"==z(k))&&ha(k,h(k.nTBody).children("tr"));k.aiDisplay=k.aiDisplayMaster.slice();
k.bInitialised=!0;!1===e&&ra(k)}});b=null;return this};var Rb=[],y=Array.prototype,$b=function(a){var b,c,d=p.settings,e=h.map(d,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};
q=function(a,b){if(!this instanceof q)throw"DT API must be constructed as a new object";var c=[],d=function(a){(a=$b(a))&&c.push.apply(c,a)};if(h.isArray(a))for(var e=0,f=a.length;e<f;e++)d(a[e]);else d(a);this.context=Ja(c);b&&this.push.apply(this,b.toArray?b.toArray():b);this.selector={rows:null,cols:null,opts:null};q.extend(this,this,Rb)};p.Api=q;q.prototype={concat:y.concat,context:[],each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=
this.context;return b.length>a?new q(b[a],this[a]):null},filter:function(a){var b=[];if(y.filter)b=y.filter.call(this,a,this);else for(var c=0,d=this.length;c<d;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new q(this.context,b)},flatten:function(){var a=[];return new q(this.context,a.concat.apply(a,this.toArray()))},join:y.join,indexOf:y.indexOf||function(a,b){for(var c=b||0,d=this.length;c<d;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c){var d=[],e,f,g,h,i,o=this.context,
m,n,k=this.selector;"string"===typeof a&&(c=b,b=a,a=!1);f=0;for(g=o.length;f<g;f++)if("table"===b)e=c(o[f],f),e!==l&&d.push(e);else if("columns"===b||"rows"===b)e=c(o[f],this[f],f),e!==l&&d.push(e);else if("column"===b||"column-rows"===b||"row"===b||"cell"===b){n=this[f];"column-rows"===b&&(m=Ya(o[f],k.opts));h=0;for(i=n.length;h<i;h++)e=n[h],e="cell"===b?c(o[f],e.row,e.column,f,h):c(o[f],e,f,h,m),e!==l&&d.push(e)}return d.length?(a=new q(o,a?d.concat.apply([],d):d),b=a.selector,b.rows=k.rows,b.cols=
k.cols,b.opts=k.opts,a):this},lastIndexOf:y.lastIndexOf||function(a,b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(y.map)b=y.map.call(this,a,this);else for(var c=0,d=this.length;c<d;c++)b.push(a.call(this,this[c],c));return new q(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},pop:y.pop,push:y.push,reduce:y.reduce||function(a,b){return gb(this,a,b,0,this.length,1)},reduceRight:y.reduceRight||function(a,b){return gb(this,
a,b,this.length-1,-1,-1)},reverse:y.reverse,selector:null,shift:y.shift,sort:y.sort,splice:y.splice,toArray:function(){return y.slice.call(this)},to$:function(){return h(this)},toJQuery:function(){return h(this)},unique:function(){return new q(this.context,Ja(this))},unshift:y.unshift};q.extend=function(a,b,c){if(b&&(b instanceof q||b.__dt_wrapper)){var d,e,f,g=function(a,b,c){return function(){var d=b.apply(a,arguments);q.extend(d,d,c.methodExt);return d}};d=0;for(e=c.length;d<e;d++)f=c[d],b[f.name]=
"function"===typeof f.val?g(a,f.val,f):h.isPlainObject(f.val)?{}:f.val,b[f.name].__dt_wrapper=!0,q.extend(a,b[f.name],f.propExt)}};q.register=r=function(a,b){if(h.isArray(a))for(var c=0,d=a.length;c<d;c++)q.register(a[c],b);else for(var e=a.split("."),f=Rb,g,j,c=0,d=e.length;c<d;c++){g=(j=-1!==e[c].indexOf("()"))?e[c].replace("()",""):e[c];var i;a:{i=0;for(var o=f.length;i<o;i++)if(f[i].name===g){i=f[i];break a}i=null}i||(i={name:g,val:{},methodExt:[],propExt:[]},f.push(i));c===d-1?i.val=b:f=j?i.methodExt:
i.propExt}};q.registerPlural=v=function(a,b,c){q.register(a,c);q.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof q?a.length?h.isArray(a[0])?new q(a.context,a[0]):a[0]:l:a})};r("tables()",function(a){var b;if(a){b=q;var c=this.context;if("number"===typeof a)a=[c[a]];else var d=h.map(c,function(a){return a.nTable}),a=h(d).filter(a).map(function(){var a=h.inArray(this,d);return c[a]}).toArray();b=new b(a)}else b=this;return b});r("table()",function(a){var a=this.tables(a),
b=a.context;return b.length?new q(b[0]):a});v("tables().nodes()","table().node()",function(){return this.iterator("table",function(a){return a.nTable})});v("tables().body()","table().body()",function(){return this.iterator("table",function(a){return a.nTBody})});v("tables().header()","table().header()",function(){return this.iterator("table",function(a){return a.nTHead})});v("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot})});v("tables().containers()",
"table().container()",function(){return this.iterator("table",function(a){return a.nTableWrapper})});r("draw()",function(a){return this.iterator("table",function(b){L(b,!1===a)})});r("page()",function(a){return a===l?this.page.info().page:this.iterator("table",function(b){Ra(b,a)})});r("page.info()",function(){if(0===this.context.length)return l;var a=this.context[0],b=a._iDisplayStart,c=a._iDisplayLength,d=a.fnRecordsDisplay(),e=-1===c;return{page:e?0:Math.floor(b/c),pages:e?1:Math.ceil(d/c),start:b,
end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:d}});r("page.len()",function(a){return a===l?0!==this.context.length?this.context[0]._iDisplayLength:l:this.iterator("table",function(b){Pa(b,a)})});var Sb=function(a,b,c){"ssp"==z(a)?L(a,b):(B(a,!0),na(a,[],function(c){ja(a);for(var c=oa(a,c),d=0,g=c.length;d<g;d++)I(a,c[d]);L(a,b);B(a,!1)}));if(c){var d=new q(a);d.one("draw",function(){c(d.ajax.json())})}};r("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});
r("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});r("ajax.reload()",function(a,b){return this.iterator("table",function(c){Sb(c,!1===b,a)})});r("ajax.url()",function(a){var b=this.context;if(a===l){if(0===b.length)return l;b=b[0];return b.ajax?h.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){h.isPlainObject(b.ajax)?b.ajax.url=a:b.ajax=a})});r("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Sb(c,
!1===b,a)})});var Za=function(a,b){var c=[],d,e,f,g,j,i;if(!a||"string"===typeof a||a.length===l)a=[a];f=0;for(g=a.length;f<g;f++){e=a[f]&&a[f].split?a[f].split(","):[a[f]];j=0;for(i=e.length;j<i;j++)(d=b("string"===typeof e[j]?h.trim(e[j]):e[j]))&&d.length&&c.push.apply(c,d)}return c},$a=function(a){a||(a={});a.filter&&!a.search&&(a.search=a.filter);return{search:a.search||"none",order:a.order||"current",page:a.page||"all"}},ab=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=
a[b],a.length=1,a.context=[a.context[b]],a;a.length=0;return a},Ya=function(a,b){var c,d,e,f=[],g=a.aiDisplay;c=a.aiDisplayMaster;var j=b.search;d=b.order;e=b.page;if("ssp"==z(a))return"removed"===j?[]:S(0,c.length);if("current"==e){c=a._iDisplayStart;for(d=a.fnDisplayEnd();c<d;c++)f.push(g[c])}else if("current"==d||"applied"==d)f="none"==j?c.slice():"applied"==j?g.slice():h.map(c,function(a){return-1===h.inArray(a,g)?a:null});else if("index"==d||"original"==d){c=0;for(d=a.aoData.length;c<d;c++)"none"==
j?f.push(c):(e=h.inArray(c,g),(-1===e&&"removed"==j||0<=e&&"applied"==j)&&f.push(c))}return f};r("rows()",function(a,b){a===l?a="":h.isPlainObject(a)&&(b=a,a="");var b=$a(b),c=this.iterator("table",function(c){var e=b;return Za(a,function(a){var b=Ob(a);if(b!==null&&!e)return[b];var j=Ya(c,e);if(b!==null&&h.inArray(b,j)!==-1)return[b];if(!a)return j;for(var b=[],i=0,o=j.length;i<o;i++)b.push(c.aoData[j[i]].nTr);return a.nodeName&&h.inArray(a,b)!==-1?[a._DT_RowIndex]:h(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()})});
c.selector.rows=a;c.selector.opts=b;return c});r("rows().nodes()",function(){return this.iterator("row",function(a,b){return a.aoData[b].nTr||l})});r("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return xa(a.aoData,b,"_aData")})});v("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var d=b.aoData[c];return"search"===a?d._aFilterData:d._aSortData})});v("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",function(b,
c){la(b,c,a)})});v("rows().indexes()","row().index()",function(){return this.iterator("row",function(a,b){return b})});v("rows().remove()","row().remove()",function(){var a=this;return this.iterator("row",function(b,c,d){var e=b.aoData;e.splice(c,1);for(var f=0,g=e.length;f<g;f++)null!==e[f].nTr&&(e[f].nTr._DT_RowIndex=f);h.inArray(c,b.aiDisplay);ka(b.aiDisplayMaster,c);ka(b.aiDisplay,c);ka(a[d],c,!1);Qa(b)})});r("rows.add()",function(a){var b=this.iterator("table",function(b){var c,f,g,h=[];f=0;
for(g=a.length;f<g;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?h.push(ha(b,c)[0]):h.push(I(b,c));return h}),c=this.rows(-1);c.pop();c.push.apply(c,b.toArray());return c});r("row()",function(a,b){return ab(this.rows(a,b))});r("row().data()",function(a){var b=this.context;if(a===l)return b.length&&this.length?b[0].aoData[this[0]]._aData:l;b[0].aoData[this[0]]._aData=a;la(b[0],this[0],"data");return this});r("row().node()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]].nTr||
null:null});r("row.add()",function(a){a instanceof h&&a.length&&(a=a[0]);var b=this.iterator("table",function(b){return a.nodeName&&"TR"===a.nodeName.toUpperCase()?ha(b,a)[0]:I(b,a)});return this.row(b[0])});var bb=function(a){var b=a.context;b.length&&a.length&&(a=b[0].aoData[a[0]],a._details&&(a._details.remove(),a._detailsShow=l,a._details=l))},Tb=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];if(d._details){(d._detailsShow=b)?d._details.insertAfter(d.nTr):d._details.detach();
var e=c[0],f=new q(e),g=e.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0<C(g,"_details").length&&(f.on("draw.dt.DT_details",function(a,b){e===b&&f.rows({page:"current"}).eq(0).each(function(a){a=g[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(e===b)for(var c,d=Z(b),f=0,h=g.length;f<h;f++)c=g[f],c._details&&c._details.children("td[colspan]").attr("colspan",d)}),f.on("destroy.dt.DT_details",function(a,
b){if(e===b)for(var c=0,d=g.length;c<d;c++)g[c]._details&&bb(g[c])}))}}};r("row().child()",function(a,b){var c=this.context;if(a===l)return c.length&&this.length?c[0].aoData[this[0]]._details:l;if(!0===a)this.child.show();else if(!1===a)bb(this);else if(c.length&&this.length){var d=c[0],c=c[0].aoData[this[0]],e=[],f=function(a,b){if(a.nodeName&&"tr"===a.nodeName.toLowerCase())e.push(a);else{var c=h("<tr><td/></tr>").addClass(b);h("td",c).addClass(b).html(a)[0].colSpan=Z(d);e.push(c[0])}};if(h.isArray(a)||
a instanceof h)for(var g=0,j=a.length;g<j;g++)f(a[g],b);else f(a,b);c._details&&c._details.remove();c._details=h(e);c._detailsShow&&c._details.insertAfter(c.nTr)}return this});r(["row().child.show()","row().child().show()"],function(){Tb(this,!0);return this});r(["row().child.hide()","row().child().hide()"],function(){Tb(this,!1);return this});r(["row().child.remove()","row().child().remove()"],function(){bb(this);return this});r("row().child.isShown()",function(){var a=this.context;return a.length&&
this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var ac=/^(.*):(name|visIdx|visible)$/;r("columns()",function(a,b){a===l?a="":h.isPlainObject(a)&&(b=a,a="");var b=$a(b),c=this.iterator("table",function(b){var c=a,f=b.aoColumns,g=C(f,"sName"),j=C(f,"nTh");return Za(c,function(a){var c=Ob(a);if(a==="")return S(f.length);if(c!==null)return[c>=0?c:f.length+c];var e=typeof a==="string"?a.match(ac):"";if(e)switch(e[2]){case "visIdx":case "visible":a=parseInt(e[1],10);if(a<0){c=h.map(f,function(a,
b){return a.bVisible?b:null});return[c[c.length+a]]}return[ga(b,a)];case "name":return h.map(g,function(a,b){return a===e[1]?b:null})}else return h(j).filter(a).map(function(){return h.inArray(this,j)}).toArray()})});c.selector.cols=a;c.selector.opts=b;return c});v("columns().header()","column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh})});v("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf})});
v("columns().data()","column().data()",function(){return this.iterator("column-rows",function(a,b,c,d,e){for(var c=[],d=0,f=e.length;d<f;d++)c.push(A(a,e[d],b,""));return c})});v("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,f){return xa(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)})});v("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return xa(a.aoData,e,"anCells",b)})});v("columns().visible()",
"column().visible()",function(a){return this.iterator("column",function(b,c){var d;if(a===l)d=b.aoColumns[c].bVisible;else{var e=b.aoColumns;d=e[c];var f=b.aoData,g,j,i;if(a===l)d=d.bVisible;else{if(d.bVisible!==a){if(a){var o=h.inArray(!0,C(e,"bVisible"),c+1);g=0;for(j=f.length;g<j;g++)i=f[g].nTr,e=f[g].anCells,i&&i.insertBefore(e[c],e[o]||null)}else h(C(b.aoData,"anCells",c)).detach();d.bVisible=a;ba(b,b.aoHeader);ba(b,b.aoFooter);V(b);(b.oScroll.sX||b.oScroll.sY)&&W(b);u(b,null,"column-visibility",
[b,c,a]);ta(b)}d=void 0}}return d})});v("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===a?Y(b,c):c})});r("columns.adjust()",function(){return this.iterator("table",function(a){V(a)})});r("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return ga(c,b);if("fromData"===a||"toVisible"===a)return Y(c,b)}});r("column()",function(a,b){return ab(this.columns(a,b))});r("cells()",
function(a,b,c){h.isPlainObject(a)&&(typeof a.row!==l?(c=b,b=null):(c=a,a=null));h.isPlainObject(b)&&(c=b,b=null);if(null===b||b===l)return this.iterator("table",function(b){var d=a,e=$a(c),f=b.aoData,g=Ya(b,e),e=xa(f,g,"anCells"),i=h([].concat.apply([],e)),j,m=b.aoColumns.length,o,p,r,q;return Za(d,function(a){if(a===null||a===l){o=[];p=0;for(r=g.length;p<r;p++){j=g[p];for(q=0;q<m;q++)o.push({row:j,column:q})}return o}return h.isPlainObject(a)?[a]:i.filter(a).map(function(a,b){j=b.parentNode._DT_RowIndex;
return{row:j,column:h.inArray(b,f[j].anCells)}}).toArray()})});var d=this.columns(b,c),e=this.rows(a,c),f,g,j,i,o,m=this.iterator("table",function(a,b){f=[];g=0;for(j=e[b].length;g<j;g++){i=0;for(o=d[b].length;i<o;i++)f.push({row:e[b][g],column:d[b][i]})}return f});h.extend(m.selector,{cols:b,rows:a,opts:c});return m});v("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(a,b,c){return a.aoData[b].anCells[c]})});r("cells().data()",function(){return this.iterator("cell",
function(a,b,c){return A(a,b,c)})});v("cells().cache()","cell().cache()",function(a){a="search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,d){return b.aoData[c][a][d]})});v("cells().indexes()","cell().index()",function(){return this.iterator("cell",function(a,b,c){return{row:b,column:c,columnVisible:Y(a,c)}})});r(["cells().invalidate()","cell().invalidate()"],function(a){var b=this.selector;this.rows(b.rows,b.opts).invalidate(a);return this});r("cell()",function(a,b,
c){return ab(this.cells(a,b,c))});r("cell().data()",function(a){var b=this.context,c=this[0];if(a===l)return b.length&&c.length?A(b[0],c[0].row,c[0].column):l;Ea(b[0],c[0].row,c[0].column,a);la(b[0],c[0].row,"data",c[0].column);return this});r("order()",function(a,b){var c=this.context;if(a===l)return 0!==c.length?c[0].aaSorting:l;"number"===typeof a?a=[[a,b]]:h.isArray(a[0])||(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});r("order.listener()",
function(a,b,c){return this.iterator("table",function(d){Ka(d,a,b,c)})});r(["columns().order()","column().order()"],function(a){var b=this;return this.iterator("table",function(c,d){var e=[];h.each(b[d],function(b,c){e.push([c,a])});c.aaSorting=e})});r("search()",function(a,b,c,d){var e=this.context;return a===l?0!==e.length?e[0].oPreviousSearch.sSearch:l:this.iterator("table",function(e){e.oFeatures.bFilter&&ca(e,h.extend({},e.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:
c,bCaseInsensitive:null===d?!0:d}),1)})});r(["columns().search()","column().search()"],function(a,b,c,d){return this.iterator("column",function(e,f){var g=e.aoPreSearchCols;if(a===l)return g[f].sSearch;e.oFeatures.bFilter&&(h.extend(g[f],{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),ca(e,e.oPreviousSearch,1))})});r("state()",function(){return this.context.length?this.context[0].oSavedState:null});r("state.clear()",function(){return this.iterator("table",
function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});r("state.loaded()",function(){return this.context.length?this.context[0].oLoadedState:null});r("state.save()",function(){return this.iterator("table",function(a){ta(a)})});p.versionCheck=p.fnVersionCheck=function(a){for(var b=p.version.split("."),a=a.split("."),c,d,e=0,f=a.length;e<f;e++)if(c=parseInt(b[e],10)||0,d=parseInt(a[e],10)||0,c!==d)return c>d;return!0};p.isDataTable=p.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;h.each(p.settings,
function(a,e){if(e.nTable===b||e.nScrollHead===b||e.nScrollFoot===b)c=!0});return c};p.tables=p.fnTables=function(a){return jQuery.map(p.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable})};p.camelToHungarian=G;r("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){r(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0].match(/\.dt\b/)||(a[0]+=".dt");var d=
h(this.tables().nodes());d[b].apply(d,a);return this})});r("clear()",function(){return this.iterator("table",function(a){ja(a)})});r("settings()",function(){return new q(this.context,this.context)});r("data()",function(){return this.iterator("table",function(a){return C(a.aoData,"_aData")}).flatten()});r("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),l=h(b.nTableWrapper),
m=h.map(b.aoData,function(a){return a.nTr}),n;b.bDestroying=!0;u(b,"aoDestroyCallback","destroy",[b]);a||(new q(b)).columns().visible(!0);l.unbind(".DT").find(":not(tbody *)").unbind(".DT");h(za).unbind(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j));i.detach();l.detach();b.aaSorting=[];b.aaSortingFixed=[];sa(b);h(m).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+
" "+d.sSortableDesc+" "+d.sSortableNone);b.bJUI&&(h("th span."+d.sSortIcon+", td span."+d.sSortIcon,g).detach(),h("th, td",g).each(function(){var a=h("div."+d.sSortJUIWrapper,this);h(this).append(a.contents());a.detach()}));!a&&c&&c.insertBefore(e,b.nTableReinsertBefore);f.children().detach();f.append(m);i.css("width",b.sDestroyWidth).removeClass(d.sTable);(n=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%n])});c=h.inArray(b,p.settings);-1!==c&&p.settings.splice(c,
1)})});p.version="1.10.1";p.settings=[];p.models={};p.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};p.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null};p.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,
sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};p.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,
bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},
fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",
sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},p.models.oSearch),sAjaxDataProp:"data",
sAjaxSource:null,sDom:"lfrtip",sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null};T(p.defaults);p.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};T(p.defaults.column);p.models.oSettings={oFeatures:{bAutoWidth:null,
bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,
asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,
bAjaxDataGet:!0,jqXHR:null,json:l,oAjaxData:l,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==z(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==z(this)?1*this._iRecordsDisplay:
this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{}};p.ext=t={classes:{},errMode:"alert",feature:[],search:[],internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],
search:{},order:{}},_unique:0,fnVersionCheck:p.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:p.version};h.extend(t,{afnFiltering:t.search,aTypes:t.type.detect,ofnSearch:t.type.search,oSort:t.type.order,afnSortData:t.order,aoFeatures:t.feature,oApi:t.internal,oStdClasses:t.classes,oPagination:t.pager});h.extend(p.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",
sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",
sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var ya="",ya="",E=ya+"ui-state-default",ea=ya+"css_right ui-icon ui-icon-",Ub=ya+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";h.extend(p.ext.oJUIClasses,p.ext.classes,{sPageButton:"fg-button ui-button "+
E,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:E+" sorting_asc",sSortDesc:E+" sorting_desc",sSortable:E+" sorting",sSortableAsc:E+" sorting_asc_disabled",sSortableDesc:E+" sorting_desc_disabled",sSortableNone:E+" sorting_disabled",sSortJUIAsc:ea+"triangle-1-n",sSortJUIDesc:ea+"triangle-1-s",sSortJUI:ea+"carat-2-n-s",sSortJUIAscAllowed:ea+"carat-1-n",sSortJUIDescAllowed:ea+
"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+E,sScrollFoot:"dataTables_scrollFoot "+E,sHeaderTH:E,sFooterTH:E,sJUIHeader:Ub+" ui-corner-tl ui-corner-tr",sJUIFooter:Ub+" ui-corner-bl ui-corner-br"});var Lb=p.ext.pager;h.extend(Lb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},simple_numbers:function(a,b){return["previous",Ua(a,b),"next"]},full_numbers:function(a,b){return["first",
"previous",Ua(a,b),"next","last"]},_numbers:Ua,numbers_length:7});h.extend(!0,p.ext.renderer,{pageButton:{_:function(a,b,c,d,e,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i,l,m=0,n=function(b,d){var k,p,r,q,s=function(b){Ra(a,b.data.action,true)};k=0;for(p=d.length;k<p;k++){q=d[k];if(h.isArray(q)){r=h("<"+(q.DT_el||"div")+"/>").appendTo(b);n(r,q)}else{l=i="";switch(q){case "ellipsis":b.append("<span>&hellip;</span>");break;case "first":i=j.sFirst;l=q+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":i=
j.sPrevious;l=q+(e>0?"":" "+g.sPageButtonDisabled);break;case "next":i=j.sNext;l=q+(e<f-1?"":" "+g.sPageButtonDisabled);break;case "last":i=j.sLast;l=q+(e<f-1?"":" "+g.sPageButtonDisabled);break;default:i=q+1;l=e===q?g.sPageButtonActive:""}if(i){r=h("<a>",{"class":g.sPageButton+" "+l,"aria-controls":a.sTableId,"data-dt-idx":m,tabindex:a.iTabIndex,id:c===0&&typeof q==="string"?a.sTableId+"_"+q:null}).html(i).appendTo(b);Ta(r,{action:q},s);m++}}}};try{var k=h(O.activeElement).data("dt-idx");n(h(b).empty(),
d);k!==null&&h(b).find("[data-dt-idx="+k+"]").focus()}catch(p){}}}});var va=function(a,b,c,d){if(!a||"-"===a)return-Infinity;b&&(a=Pb(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(t.type.order,{"date-pre":function(a){return Date.parse(a)||0},"html-pre":function(a){return H(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return H(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,
b){return a<b?-1:a>b?1:0},"string-desc":function(a,b){return a<b?1:a>b?-1:0}});cb("");h.extend(p.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return Xa(a,c)?"num"+c:null},function(a){if(a&&(!Yb.test(a)||!Zb.test(a)))return null;var b=Date.parse(a);return null!==b&&!isNaN(b)||H(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return Xa(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Qb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Qb(a,
c,!0)?"html-num-fmt"+c:null},function(a){return H(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(p.ext.type.search,{html:function(a){return H(a)?a:"string"===typeof a?a.replace(Nb," ").replace(wa,""):""},string:function(a){return H(a)?a:"string"===typeof a?a.replace(Nb," "):a}});h.extend(!0,p.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?
d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,d){var e=c.idx;h("<div/>").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("<span/>").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);h(a.nTable).on("order.dt.DT",function(f,g,h,i){if(a===g){b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(i[e]=="asc"?d.sSortAsc:i[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+
" "+d.sSortJUIDescAllowed).addClass(i[e]=="asc"?d.sSortJUIAsc:i[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});p.render={number:function(a,b,c,d){return{display:function(e){var f=0>e?"-":"",e=Math.abs(parseFloat(e)),g=parseInt(e,10),e=c?b+(e-g).toFixed(c).substring(2):"";return f+(d||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+e}}}};h.extend(p.ext.internal,{_fnExternApiFunc:Mb,_fnBuildAjax:na,_fnAjaxUpdate:jb,_fnAjaxParameters:sb,_fnAjaxUpdateDraw:tb,_fnAjaxDataSrc:oa,_fnAddColumn:Aa,
_fnColumnOptions:fa,_fnAdjustColumnSizing:V,_fnVisibleToColumnIndex:ga,_fnColumnIndexToVisible:Y,_fnVisbleColumns:Z,_fnGetColumns:X,_fnColumnTypes:Da,_fnApplyColumnDefs:hb,_fnHungarianMap:T,_fnCamelToHungarian:G,_fnLanguageCompat:N,_fnBrowserDetect:fb,_fnAddData:I,_fnAddTr:ha,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==l?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:A,_fnSetCellData:Ea,_fnSplitObjNotation:Ga,_fnGetObjectDataFn:U,
_fnSetObjectDataFn:Ba,_fnGetDataMaster:Ha,_fnClearTable:ja,_fnDeleteIndex:ka,_fnInvalidateRow:la,_fnGetRowElements:ia,_fnCreateTr:Fa,_fnBuildHead:ib,_fnDrawHead:ba,_fnDraw:K,_fnReDraw:L,_fnAddOptionsHtml:lb,_fnDetectHeader:aa,_fnGetUniqueThs:ma,_fnFeatureHtmlFilter:nb,_fnFilterComplete:ca,_fnFilterCustom:wb,_fnFilterColumn:vb,_fnFilter:ub,_fnFilterCreateSearch:Na,_fnEscapeRegex:Oa,_fnFilterData:xb,_fnFeatureHtmlInfo:qb,_fnUpdateInfo:Ab,_fnInfoMacros:Bb,_fnInitialise:ra,_fnInitComplete:pa,_fnLengthChange:Pa,
_fnFeatureHtmlLength:mb,_fnFeatureHtmlPaginate:rb,_fnPageChange:Ra,_fnFeatureHtmlProcessing:ob,_fnProcessingDisplay:B,_fnFeatureHtmlTable:pb,_fnScrollDraw:W,_fnApplyToChildren:F,_fnCalculateColumnWidths:Ca,_fnThrottle:Ma,_fnConvertToWidth:Cb,_fnScrollingWidthAdjust:Eb,_fnGetWidestNode:Db,_fnGetMaxLenString:Fb,_fnStringToCss:s,_fnScrollBarWidth:Gb,_fnSortFlatten:R,_fnSort:kb,_fnSortAria:Ib,_fnSortListener:Sa,_fnSortAttachListener:Ka,_fnSortingClasses:sa,_fnSortData:Hb,_fnSaveState:ta,_fnLoadState:Jb,
_fnSettingsFromNode:ua,_fnLog:P,_fnMap:D,_fnBindAction:Ta,_fnCallbackReg:x,_fnCallbackFire:u,_fnLengthOverflow:Qa,_fnRenderer:La,_fnDataSource:z,_fnRowAttributes:Ia,_fnCalculateEnd:function(){}});h.fn.dataTable=p;h.fn.dataTableSettings=p.settings;h.fn.dataTableExt=p.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(p,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable};"function"===typeof define&&define.amd?define("datatables",["jquery"],N):"object"===typeof exports?N(require("jquery")):
jQuery&&!jQuery.fn.dataTable&&N(jQuery)})(window,document);

View File

@ -0,0 +1,23 @@
/*! jQuery JSON plugin 2.4.0 | code.google.com/p/jquery-json */
(function($){'use strict';var escape=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},hasOwn=Object.prototype.hasOwnProperty;$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';}
var pairs,k,name,val,type=$.type(o);if(type==='undefined'){return undefined;}
if(type==='number'||type==='boolean'){return String(o);}
if(type==='string'){return $.quoteString(o);}
if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());}
if(type==='date'){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;}
if(day<10){day='0'+day;}
if(hours<10){hours='0'+hours;}
if(minutes<10){minutes='0'+minutes;}
if(seconds<10){seconds='0'+seconds;}
if(milli<100){milli='0'+milli;}
if(milli<10){milli='0'+milli;}
return'"'+year+'-'+month+'-'+day+'T'+
hours+':'+minutes+':'+seconds+'.'+milli+'Z"';}
pairs=[];if($.isArray(o)){for(k=0;k<o.length;k++){pairs.push($.toJSON(o[k])||'null');}
return'['+pairs.join(',')+']';}
if(typeof o==='object'){for(k in o){if(hasOwn.call(o,k)){type=typeof k;if(type==='number'){name='"'+k+'"';}else if(type==='string'){name=$.quoteString(k);}else{continue;}
type=typeof o[k];if(type!=='function'&&type!=='undefined'){val=$.toJSON(o[k]);pairs.push(name+':'+val);}}}
return'{'+pairs.join(',')+'}';}};$.evalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){return eval('('+str+')');};$.secureEvalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){var filtered=str.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered)){return eval('('+str+')');}
throw new SyntaxError('Error parsing JSON, source is not valid.');};$.quoteString=function(str){if(str.match(escape)){return'"'+str.replace(escape,function(a){var c=meta[a];if(typeof c==='string'){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
return'"'+str+'"';};}(jQuery));

View File

@ -0,0 +1,716 @@
/*
* Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is jquery.jsonrpclient.js modified for Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
*
* The Initial Developer of the Original Code is
* Textalk AB http://textalk.se/
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
*
* jquery.jsonrpclient.js - JSON RPC client code
*
*/
/**
* This plugin requires jquery.json.js to be available, or at least the methods $.toJSON and
* $.parseJSON.
*
* The plan is to make use of websockets if they are available, but work just as well with only
* http if not.
*
* Usage example:
*
* var foo = new $.JsonRpcClient({ ajaxUrl: '/backend/jsonrpc' });
* foo.call(
* 'bar', [ 'A parameter', 'B parameter' ],
* function(result) { alert('Foo bar answered: ' + result.my_answer); },
* function(error) { console.log('There was an error', error); }
* );
*
* More examples are available in README.md
*/
(function($) {
/**
* @fn new
* @memberof $.JsonRpcClient
*
* @param options An object stating the backends:
* ajaxUrl A url (relative or absolute) to a http(s) backend.
* socketUrl A url (relative of absolute) to a ws(s) backend.
* onmessage A socket message handler for other messages (non-responses).
* getSocket A function returning a WebSocket or null.
* It must take an onmessage_cb and bind it to the onmessage event
* (or chain it before/after some other onmessage handler).
* Or, it could return null if no socket is available.
* The returned instance must have readyState <= 1, and if less than 1,
* react to onopen binding.
*/
$.JsonRpcClient = function(options) {
var self = this;
this.options = $.extend({
ajaxUrl : null,
socketUrl : null, ///< The ws-url for default getSocket.
onmessage : null, ///< Other onmessage-handler.
login : null, /// auth login
passwd : null, /// auth passwd
sessid : null,
loginParams : null,
userVariables : null,
getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); }
}, options);
self.ws_cnt = 0;
// Declare an instance version of the onmessage callback to wrap 'this'.
this.wsOnMessage = function(event) { self._wsOnMessage(event); };
};
/// Holding the WebSocket on default getsocket.
$.JsonRpcClient.prototype._ws_socket = null;
/// Object <id>: { success_cb: cb, error_cb: cb }
$.JsonRpcClient.prototype._ws_callbacks = {};
/// The next JSON-RPC request id.
$.JsonRpcClient.prototype._current_id = 1;
$.JsonRpcClient.prototype.speedTest = function (bytes, cb) {
var socket = this.options.getSocket(this.wsOnMessage);
if (socket !== null) {
this.speedCB = cb;
this.speedBytes = bytes;
socket.send("#SPU " + bytes);
var loops = bytes / 1024;
var rem = bytes % 1024;
var i;
var data = new Array(1024).join(".");
for (i = 0; i < loops; i++) {
socket.send("#SPB " + data);
}
if (rem) {
socket.send("#SPB " + data);
}
socket.send("#SPE");
}
};
/**
* @fn call
* @memberof $.JsonRpcClient
*
* @param method The method to run on JSON-RPC server.
* @param params The params; an array or object.
* @param success_cb A callback for successful request.
* @param error_cb A callback for error.
*/
$.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) {
// Construct the JSON-RPC 2.0 request.
if (!params) {
params = {};
}
if (this.options.sessid) {
params.sessid = this.options.sessid;
}
var request = {
jsonrpc : '2.0',
method : method,
params : params,
id : this._current_id++ // Increase the id counter to match request/response
};
if (!success_cb) {
success_cb = function(e){console.log("Success: ", e);};
}
if (!error_cb) {
error_cb = function(e){console.log("Error: ", e);};
}
// Try making a WebSocket call.
var socket = this.options.getSocket(this.wsOnMessage);
if (socket !== null) {
this._wsCall(socket, request, success_cb, error_cb);
return;
}
// No WebSocket, and no HTTP backend? This won't work.
if (this.options.ajaxUrl === null) {
throw "$.JsonRpcClient.call used with no websocket and no http endpoint.";
}
$.ajax({
type : 'POST',
url : this.options.ajaxUrl,
data : $.toJSON(request),
dataType : 'json',
cache : false,
success : function(data) {
if ('error' in data) error_cb(data.error, this);
success_cb(data.result, this);
},
// JSON-RPC Server could return non-200 on error
error : function(jqXHR, textStatus, errorThrown) {
try {
var response = $.parseJSON(jqXHR.responseText);
if ('console' in window) console.log(response);
error_cb(response.error, this);
} catch (err) {
// Perhaps the responseText wasn't really a jsonrpc-error.
error_cb({ error: jqXHR.responseText }, this);
}
}
});
};
/**
* Notify sends a command to the server that won't need a response. In http, there is probably
* an empty response - that will be dropped, but in ws there should be no response at all.
*
* This is very similar to call, but has no id and no handling of callbacks.
*
* @fn notify
* @memberof $.JsonRpcClient
*
* @param method The method to run on JSON-RPC server.
* @param params The params; an array or object.
*/
$.JsonRpcClient.prototype.notify = function(method, params) {
// Construct the JSON-RPC 2.0 request.
if (this.options.sessid) {
params.sessid = this.options.sessid;
}
var request = {
jsonrpc: '2.0',
method: method,
params: params
};
// Try making a WebSocket call.
var socket = this.options.getSocket(this.wsOnMessage);
if (socket !== null) {
this._wsCall(socket, request);
return;
}
// No WebSocket, and no HTTP backend? This won't work.
if (this.options.ajaxUrl === null) {
throw "$.JsonRpcClient.notify used with no websocket and no http endpoint.";
}
$.ajax({
type : 'POST',
url : this.options.ajaxUrl,
data : $.toJSON(request),
dataType : 'json',
cache : false
});
};
/**
* Make a batch-call by using a callback.
*
* The callback will get an object "batch" as only argument. On batch, you can call the methods
* "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be
* sent as a batch call then the callback is done.
*
* @fn batch
* @memberof $.JsonRpcClient
*
* @param callback The main function which will get a batch handler to run call and notify on.
* @param all_done_cb A callback function to call after all results have been handled.
* @param error_cb A callback function to call if there is an error from the server.
* Note, that batch calls should always get an overall success, and the
* only error
*/
$.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) {
var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb);
callback(batch);
batch._execute();
};
/**
* The default getSocket handler.
*
* @param onmessage_cb The callback to be bound to onmessage events on the socket.
*
* @fn _getSocket
* @memberof $.JsonRpcClient
*/
$.JsonRpcClient.prototype.socketReady = function() {
if (this._ws_socket === null || this._ws_socket.readyState > 1) {
return false;
}
return true;
};
$.JsonRpcClient.prototype.closeSocket = function() {
var self = this;
if (self.socketReady()) {
self._ws_socket.onclose = function (w) {console.log("Closing Socket");};
self._ws_socket.close();
}
};
$.JsonRpcClient.prototype.loginData = function(params) {
var self = this;
self.options.login = params.login;
self.options.passwd = params.passwd;
self.options.loginParams = params.loginParams;
self.options.userVariables = params.userVariables;
};
$.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) {
var self = this;
if (self.to) {
clearTimeout(self.to);
}
if (!self.socketReady()) {
self.authing = false;
if (self._ws_socket) {
delete self._ws_socket;
}
// No socket, or dying socket, let's get a new one.
self._ws_socket = new WebSocket(self.options.socketUrl);
if (self._ws_socket) {
// Set up onmessage handler.
self._ws_socket.onmessage = onmessage_cb;
self._ws_socket.onclose = function (w) {
if (!self.ws_sleep) {
self.ws_sleep = 1000;
}
if (self.options.onWSClose) {
self.options.onWSClose(self);
}
console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec");
self.to = setTimeout(function() {
console.log("Attempting Reconnection....");
self.connectSocket(onmessage_cb);
}, self.ws_sleep);
self.ws_cnt++;
if (self.ws_sleep < 3000 && (self.ws_cnt % 10) === 0) {
self.ws_sleep += 1000;
}
};
// Set up sending of message for when the socket is open.
self._ws_socket.onopen = function() {
if (self.to) {
clearTimeout(self.to);
}
self.ws_sleep = 1000;
self.ws_cnt = 0;
if (self.options.onWSConnect) {
self.options.onWSConnect(self);
}
var req;
// Send the requests.
while ((req = $.JsonRpcClient.q.pop())) {
self._ws_socket.send(req);
}
};
}
}
return self._ws_socket ? true : false;
};
$.JsonRpcClient.prototype._getSocket = function(onmessage_cb) {
// If there is no ws url set, we don't have a socket.
// Likewise, if there is no window.WebSocket.
if (this.options.socketUrl === null || !("WebSocket" in window)) return null;
this.connectSocket(onmessage_cb);
return this._ws_socket;
};
/**
* Queue to save messages delivered when websocket is not ready
*/
$.JsonRpcClient.q = [];
/**
* Internal handler to dispatch a JRON-RPC request through a websocket.
*
* @fn _wsCall
* @memberof $.JsonRpcClient
*/
$.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) {
var request_json = $.toJSON(request);
if (socket.readyState < 1) {
// The websocket is not open yet; we have to set sending of the message in onopen.
self = this; // In closure below, this is set to the WebSocket. Use self instead.
$.JsonRpcClient.q.push(request_json);
} else {
// We have a socket and it should be ready to send on.
socket.send(request_json);
}
// Setup callbacks. If there is an id, this is a call and not a notify.
if ('id' in request && typeof success_cb !== 'undefined') {
this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb };
}
};
/**
* Internal handler for the websocket messages. It determines if the message is a JSON-RPC
* response, and if so, tries to couple it with a given callback. Otherwise, it falls back to
* given external onmessage-handler, if any.
*
* @param event The websocket onmessage-event.
*/
$.JsonRpcClient.prototype._wsOnMessage = function(event) {
// Check if this could be a JSON RPC message.
var response;
// Special sub proto
if (event.data[0] == "#" && event.data[1] == "S" && event.data[2] == "P") {
if (event.data[3] == "U") {
this.up_dur = parseInt(event.data.substring(4));
} else if (this.speedCB && event.data[3] == "D") {
this.down_dur = parseInt(event.data.substring(4));
var up_kps = (((this.speedBytes * 8) / (this.up_dur / 1000)) / 1024).toFixed(0);
var down_kps = (((this.speedBytes * 8) / (this.down_dur / 1000)) / 1024).toFixed(0);
console.info("Speed Test: Up: " + up_kps + " Down: " + down_kps);
this.speedCB(event, { upDur: this.up_dur, downDur: this.down_dur, upKPS: up_kps, downKPS: down_kps });
this.speedCB = null;
}
return;
}
try {
response = $.parseJSON(event.data);
/// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends.
if (typeof response === 'object' &&
'jsonrpc' in response &&
response.jsonrpc === '2.0') {
/// @todo Handle bad response (without id).
// If this is an object with result, it is a response.
if ('result' in response && this._ws_callbacks[response.id]) {
// Get the success callback.
var success_cb = this._ws_callbacks[response.id].success_cb;
/*
// set the sessid if present
if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) {
this.options.sessid = response.result.sessid;
if (this.options.sessid) {
console.log("setting session UUID to: " + this.options.sessid);
}
}
*/
// Delete the callback from the storage.
delete this._ws_callbacks[response.id];
// Run callback with result as parameter.
success_cb(response.result, this);
return;
} else if ('error' in response && this._ws_callbacks[response.id]) {
// If this is an object with error, it is an error response.
// Get the error callback.
var error_cb = this._ws_callbacks[response.id].error_cb;
var orig_req = this._ws_callbacks[response.id].request;
// if this is an auth request, send the credentials and resend the failed request
if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) {
self.authing = true;
this.call("login", { login: self.options.login, passwd: self.options.passwd, loginParams: self.options.loginParams,
userVariables: self.options.userVariables},
this._ws_callbacks[response.id].request_obj.method == "login" ?
function(e) {
self.authing = false;
console.log("logged in");
delete self._ws_callbacks[response.id];
if (self.options.onWSLogin) {
self.options.onWSLogin(true, self);
}
}
:
function(e) {
self.authing = false;
console.log("logged in, resending request id: " + response.id);
var socket = self.options.getSocket(self.wsOnMessage);
if (socket !== null) {
socket.send(orig_req);
}
if (self.options.onWSLogin) {
self.options.onWSLogin(true, self);
}
},
function(e) {
console.log("error logging in, request id:", response.id);
delete self._ws_callbacks[response.id];
error_cb(response.error, this);
if (self.options.onWSLogin) {
self.options.onWSLogin(false, self);
}
});
return;
}
// Delete the callback from the storage.
delete this._ws_callbacks[response.id];
// Run callback with the error object as parameter.
error_cb(response.error, this);
return;
}
}
} catch (err) {
// Probably an error while parsing a non json-string as json. All real JSON-RPC cases are
// handled above, and the fallback method is called below.
console.log("ERROR: "+ err);
return;
}
// This is not a JSON-RPC response. Call the fallback message handler, if given.
if (typeof this.options.onmessage === 'function') {
event.eventData = response;
if (!event.eventData) {
event.eventData = {};
}
var reply = this.options.onmessage(event);
if (reply && typeof reply === "object" && event.eventData.id) {
var msg = {
jsonrpc: "2.0",
id: event.eventData.id,
result: reply
};
var socket = self.options.getSocket(self.wsOnMessage);
if (socket !== null) {
socket.send($.toJSON(msg));
}
}
}
};
/************************************************************************************************
* Batch object with methods
************************************************************************************************/
/**
* Handling object for batch calls.
*/
$.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) {
// Array of objects to hold the call and notify requests. Each objects will have the request
// object, and unless it is a notify, success_cb and error_cb.
this._requests = [];
this.jsonrpcclient = jsonrpcclient;
this.all_done_cb = all_done_cb;
this.error_cb = typeof error_cb === 'function' ? error_cb : function() {};
};
/**
* @sa $.JsonRpcClient.prototype.call
*/
$.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) {
if (!params) {
params = {};
}
if (this.options.sessid) {
params.sessid = this.options.sessid;
}
if (!success_cb) {
success_cb = function(e){console.log("Success: ", e);};
}
if (!error_cb) {
error_cb = function(e){console.log("Error: ", e);};
}
this._requests.push({
request : {
jsonrpc : '2.0',
method : method,
params : params,
id : this.jsonrpcclient._current_id++ // Use the client's id series.
},
success_cb : success_cb,
error_cb : error_cb
});
};
/**
* @sa $.JsonRpcClient.prototype.notify
*/
$.JsonRpcClient._batchObject.prototype.notify = function(method, params) {
if (this.options.sessid) {
params.sessid = this.options.sessid;
}
this._requests.push({
request : {
jsonrpc : '2.0',
method : method,
params : params
}
});
};
/**
* Executes the batched up calls.
*/
$.JsonRpcClient._batchObject.prototype._execute = function() {
var self = this;
if (this._requests.length === 0) return; // All done :P
// Collect all request data and sort handlers by request id.
var batch_request = [];
var handlers = {};
var i = 0;
var call;
var success_cb;
var error_cb;
// If we have a WebSocket, just send the requests individually like normal calls.
var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);
if (socket !== null) {
for (i = 0; i < this._requests.length; i++) {
call = this._requests[i];
success_cb = ('success_cb' in call) ? call.success_cb : undefined;
error_cb = ('error_cb' in call) ? call.error_cb : undefined;
self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb);
}
if (typeof all_done_cb === 'function') all_done_cb(result);
return;
}
for (i = 0; i < this._requests.length; i++) {
call = this._requests[i];
batch_request.push(call.request);
// If the request has an id, it should handle returns (otherwise it's a notify).
if ('id' in call.request) {
handlers[call.request.id] = {
success_cb : call.success_cb,
error_cb : call.error_cb
};
}
}
success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); };
// No WebSocket, and no HTTP backend? This won't work.
if (self.jsonrpcclient.options.ajaxUrl === null) {
throw "$.JsonRpcClient.batch used with no websocket and no http endpoint.";
}
// Send request
$.ajax({
url : self.jsonrpcclient.options.ajaxUrl,
data : $.toJSON(batch_request),
dataType : 'json',
cache : false,
type : 'POST',
// Batch-requests should always return 200
error : function(jqXHR, textStatus, errorThrown) {
self.error_cb(jqXHR, textStatus, errorThrown);
},
success : success_cb
});
};
/**
* Internal helper to match the result array from a batch call to their respective callbacks.
*
* @fn _batchCb
* @memberof $.JsonRpcClient
*/
$.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) {
for (var i = 0; i < result.length; i++) {
var response = result[i];
// Handle error
if ('error' in response) {
if (response.id === null || !(response.id in handlers)) {
// An error on a notify? Just log it to the console.
if ('console' in window) console.log(response);
} else {
handlers[response.id].error_cb(response.error, this);
}
} else {
// Here we should always have a correct id and no error.
if (!(response.id in handlers) && 'console' in window) {
console.log(response);
} else {
handlers[response.id].success_cb(response.result, this);
}
}
}
if (typeof all_done_cb === 'function') all_done_cb(result);
};
})(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
var __extends=this.__extends||function(b,d){function n(){this.constructor=b}for(var f in d)d.hasOwnProperty(f)&&(b[f]=d[f]);n.prototype=d.prototype;b.prototype=new n};
function JL(b){if(!b)return JL.__;Array.prototype.reduce||(Array.prototype.reduce=function(b,d){for(var l=d,g=0;g<this.length;g++)l=b(l,this[g],g,this);return l});var d="";return("."+b).split(".").reduce(function(b,f,l,g){d=d?d+("."+f):f;f=b["__"+d];void 0===f&&(JL.Logger.prototype=b,f=new JL.Logger(d),b["__"+d]=f);return f},JL.__)}
(function(b){function d(a,c,h){void 0!==c[a]&&(null===c[a]?delete h[a]:h[a]=c[a])}function n(a){if(null!=b.enabled&&!b.enabled||null!=b.maxMessages&&1>b.maxMessages)return!1;try{if(a.userAgentRegex&&!RegExp(a.userAgentRegex).test(navigator.userAgent))return!1}catch(c){}try{if(a.ipRegex&&b.clientIP&&!RegExp(a.ipRegex).test(b.clientIP))return!1}catch(h){}return!0}function f(a,c){try{if(a.disallow&&RegExp(a.disallow).test(c))return!1}catch(h){}return!0}function l(a){return"function"==typeof a?a instanceof
RegExp?a.toString():a():a}function g(a){a=l(a);switch(typeof a){case "string":return new m(a,null,a);case "number":return a=a.toString(),new m(a,null,a);case "boolean":return a=a.toString(),new m(a,null,a);case "undefined":return new m("undefined",null,"undefined");case "object":return a instanceof RegExp||a instanceof String||a instanceof Number||a instanceof Boolean?(a=a.toString(),new m(a,null,a)):new m(null,a,JSON.stringify(a));default:return new m("unknown",null,"unknown")}}b.enabled;b.maxMessages;
b.defaultAjaxUrl;b.clientIP;b.defaultBeforeSend;b.requestId="";var m=function(){return function(a,c,h){this.msg=a;this.meta=c;this.finalString=h}}();b.setOptions=function(a){d("enabled",a,this);d("maxMessages",a,this);d("defaultAjaxUrl",a,this);d("clientIP",a,this);d("requestId",a,this);d("defaultBeforeSend",a,this);return this};b.getAllLevel=function(){return-2147483648};b.getTraceLevel=function(){return 1E3};b.getDebugLevel=function(){return 2E3};b.getInfoLevel=function(){return 3E3};b.getWarnLevel=
function(){return 4E3};b.getErrorLevel=function(){return 5E3};b.getFatalLevel=function(){return 6E3};b.getOffLevel=function(){return 2147483647};var e=function(){return function(a,c){this.inner=c;this.name="JL.Exception";this.message=g(a).finalString}}();b.Exception=e;e.prototype=Error();var r=function(){return function(a,c,h,b){this.l=a;this.m=c;this.n=h;this.t=b}}();b.LogItem=r;e=function(){function a(c,a){this.appenderName=c;this.sendLogItems=a;this.level=b.getTraceLevel();this.sendWithBufferLevel=
2147483647;this.storeInBufferLevel=-2147483648;this.bufferSize=0;this.batchSize=1;this.buffer=[];this.batchBuffer=[]}a.prototype.setOptions=function(c){d("level",c,this);d("ipRegex",c,this);d("userAgentRegex",c,this);d("disallow",c,this);d("sendWithBufferLevel",c,this);d("storeInBufferLevel",c,this);d("bufferSize",c,this);d("batchSize",c,this);this.bufferSize<this.buffer.length&&(this.buffer.length=this.bufferSize);return this};a.prototype.log=function(c,a,b,d,k,e,g){!n(this)||!f(this,e)||k<this.storeInBufferLevel||
(c=new r(k,e,g,(new Date).getTime()),k<this.level?0<this.bufferSize&&(this.buffer.push(c),this.buffer.length>this.bufferSize&&this.buffer.shift()):(k<this.sendWithBufferLevel||!this.buffer.length||(this.batchBuffer=this.batchBuffer.concat(this.buffer),this.buffer.length=0),this.batchBuffer.push(c),this.batchBuffer.length>=this.batchSize&&this.sendBatch()))};a.prototype.sendBatch=function(){0==this.batchBuffer.length||null!=b.maxMessages&&1>b.maxMessages||(null!=b.maxMessages&&(b.maxMessages-=this.batchBuffer.length),
this.sendLogItems(this.batchBuffer),this.batchBuffer.length=0)};return a}();b.Appender=e;var p=function(a){function c(b){a.call(this,b,c.prototype.sendLogItemsAjax)}__extends(c,a);c.prototype.setOptions=function(c){d("url",c,this);d("beforeSend",c,this);a.prototype.setOptions.call(this,c);return this};c.prototype.sendLogItemsAjax=function(c){try{var a="/jsnlog.logger";null!=b.defaultAjaxUrl&&(a=b.defaultAjaxUrl);this.url&&(a=this.url);var d=JSON.stringify({r:b.requestId,lg:c}),k=this.getXhr(a);"function"===
typeof this.beforeSend?this.beforeSend(k):"function"===typeof b.defaultBeforeSend&&b.defaultBeforeSend(k);k.send(d)}catch(f){}};c.prototype.getXhr=function(c){var a=new XMLHttpRequest;if(!("withCredentials"in a)&&"undefined"!=typeof XDomainRequest)return a=new XDomainRequest,a.open("POST",c),a;a.open("POST",c);a.setRequestHeader("Content-Type","application/json");a.setRequestHeader("JSNLog-RequestId",b.requestId);return a};return c}(e);b.AjaxAppender=p;var q=function(a){function c(b){a.call(this,
b,c.prototype.sendLogItemsConsole)}__extends(c,a);c.prototype.clog=function(a){console.log(a)};c.prototype.cerror=function(a){console.error?console.error(a):this.clog(a)};c.prototype.cwarn=function(a){console.warn?console.warn(a):this.clog(a)};c.prototype.cinfo=function(a){console.info?console.info(a):this.clog(a)};c.prototype.cdebug=function(a){console.debug?console.debug(a):this.cinfo(a)};c.prototype.sendLogItemsConsole=function(a){try{if(console){var c;for(c=0;c<a.length;++c){var d=a[c],f=d.n+
": "+d.m;"undefined"===typeof window&&(f=new Date(d.t)+" | "+f);d.l<=b.getDebugLevel()?this.cdebug(f):d.l<=b.getInfoLevel()?this.cinfo(f):d.l<=b.getWarnLevel()?this.cwarn(f):this.cerror(f)}}}catch(e){}};return c}(e);b.ConsoleAppender=q;e=function(){function a(a){this.loggerName=a;this.seenRegexes=[]}a.prototype.setOptions=function(a){d("level",a,this);d("userAgentRegex",a,this);d("disallow",a,this);d("ipRegex",a,this);d("appenders",a,this);d("onceOnly",a,this);this.seenRegexes=[];return this};a.prototype.buildExceptionObject=
function(a){var b={};a.stack?b.stack=a.stack:b.e=a;a.message&&(b.message=a.message);a.name&&(b.name=a.name);a.data&&(b.data=a.data);a.inner&&(b.inner=this.buildExceptionObject(a.inner));return b};a.prototype.log=function(a,b,d){var e=0;if(!this.appenders)return this;if(a>=this.level&&n(this)&&(d?(e=this.buildExceptionObject(d),e.logData=l(b)):e=b,b=g(e),f(this,b.finalString))){if(this.onceOnly)for(e=this.onceOnly.length-1;0<=e;){if(RegExp(this.onceOnly[e]).test(b.finalString)){if(this.seenRegexes[e])return this;
this.seenRegexes[e]=!0}e--}b.meta=b.meta||{};b.meta.loggerName=this.loggerName;for(e=this.appenders.length-1;0<=e;)this.appenders[e].log(1E3>=a?"trace":2E3>=a?"debug":3E3>=a?"info":4E3>=a?"warn":5E3>=a?"error":"fatal",b.msg,b.meta,function(){},a,b.finalString,this.loggerName),e--}return this};a.prototype.trace=function(a){return this.log(1E3,a)};a.prototype.debug=function(a){return this.log(2E3,a)};a.prototype.info=function(a){return this.log(3E3,a)};a.prototype.warn=function(a){return this.log(4E3,
a)};a.prototype.error=function(a){return this.log(5E3,a)};a.prototype.fatal=function(a){return this.log(6E3,a)};a.prototype.fatalException=function(a,b){return this.log(6E3,a,b)};return a}();b.Logger=e;b.createAjaxAppender=function(a){return new p(a)};b.createConsoleAppender=function(a){return new q(a)};e=new p("");"undefined"===typeof window&&(e=new q(""));b.__=new b.Logger("");b.__.setOptions({level:b.getDebugLevel(),appenders:[e]})})(JL||(JL={}));var exports;
"undefined"!==typeof exports&&(exports.JL=JL);var define;"function"==typeof define&&define.amd&&define("jsnlog",[],function(){return JL});"function"==typeof __jsnlog_configure&&__jsnlog_configure(JL);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,404 @@
var callback = function(message){console.log(message);}; // holds the user's callback for a global scope
callbacks = {};
var callICEConnected = false;
var callPurposefullyEnded = false; // used to determine whether the user ended the call or the call was ended from somewhere else outside
var callTimeout = null; // function that will run if there is no call established
var toDisplayDisconnectCallback = true; // if a call is dropped only display the error the first time
var wasCallSuccessful = false; // when the websocket connection is closed this determines whether a call was ever successfully established
webcamStream = "webcamStream";
window[webcamStream] = null;
verto = null;
videoTag = null;
// receives either a string variable holding the name of an actionscript
// registered callback, or a javascript function object.
// The function will return either the function if it is a javascript Function
// or if it is an actionscript string it will return a javascript Function
// that when invokved will invoke the actionscript registered callback
// and passes along parameters
function normalizeCallback(callback) {
if (typeof callback == "function") {
return callback;
} else {
return function(args) {
document.getElementById("BigBlueButton")[callback](args);
};
}
}
// save a copy of the hangup function registered for the verto object
var oldHangup = $.verto.prototype.hangup;
// overwrite the verto hangup handler with my own handler
$.verto.prototype.hangup = function(callID, userCallback) {
console.log("call state callbacks - bye");
if (userCallback) {
callback = userCallback;
}
callActive = false;
if (cur_call) {
console.log('call ended ' + cur_call.audioStream.currentTime); // the duration of the call
if (callPurposefullyEnded === true) { // the user ended the call themself
callback({'status':'ended'});
} else {
callback({'status':'failed', 'errorcode': 1005}); // Call ended unexpectedly
}
clearTimeout(callTimeout);
cur_call = null;
} else {
console.log('bye event already received');
}
// call the original hangup procedure
return oldHangup.apply(this, arguments);
}
// main entry point to making a verto call
callIntoConference_verto = function(voiceBridge, conferenceUsername, conferenceIdNumber, userCallback, videoTag, options, vertoServerCredentials) {
window.videoTag = videoTag;
// stores the user's callback in the global scope
if (userCallback) {
callback = userCallback;
}
if(!isLoggedIntoVerto()) { // start the verto log in procedure
// runs when a web socket is disconnected
callbacks.onWSClose = function(v, success) {
if(wasCallSuccessful) { // a call was established through the websocket
if(toDisplayDisconnectCallback) { // will only display the error the first time
// the connection was dropped in an already established call
console.log("websocket disconnected");
callback({'status':'failed', 'errorcode': 1001}); // WebSocket disconnected
toDisplayDisconnectCallback = false;
}
} else {
// this callback was triggered and a call was never successfully established
console.log("websocket connection could not be established");
callback({'status':'failed', 'errorcode': 1002}); // Could not make a WebSocket connection
}
}
// runs when the websocket is successfully created
callbacks.onWSLogin = function(v, success) {
cur_call = null;
ringing = false;
console.log("Inside onWSLogin");
if (success) {
console.log("starting call");
toDisplayDisconnectCallback = true; // yes, display an error if the socket closes
wasCallSuccessful = true; // yes, a call was successfully established through the websocket
webrtc_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, callback, options);
} else {
callback({'status':'failed', 'errorcode': '10XX'}); // eror logging verto into freeswitch
}
}
// set up verto
// $.verto.init({}, init(videoTag));
init(videoTag, vertoServerCredentials);
} else {
console.log("already logged into verto, going straight to making a call");
webrtc_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, callback, options);
}
}
checkSupport = function(callback) {
if(!isWebRTCAvailable_verto()) {
callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
}
if (!navigator.getUserMedia) {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
}
if (!navigator.getUserMedia){
callback({'status': 'failed', 'errorcode': '10XX'}); // getUserMedia not supported in this browser
}
}
configStuns = function(callbacks, callback, videoTag, vertoServerCredentials) {
console.log("Fetching STUN/TURN server info for Verto initialization");
var stunsConfig = {};
$.ajax({
dataType: 'json',
url: '/bigbluebutton/api/stuns/'
}).done(function(data) {
console.log("ajax request done");
console.log(data);
if(data['response'] && data.response.returncode == "FAILED") {
console.error(data.response.message);
callback({'status':'failed', 'errorcode': data.response.message});
return;
}
stunsConfig['stunServers'] = ( data['stunServers'] ? data['stunServers'].map(function(data) {
return {'url': data['url']};
}) : [] );
stunsConfig['turnServers'] = ( data['turnServers'] ? data['turnServers'].map(function(data) {
return {
'urls': data['url'],
'username': data['username'],
'credential': data['password']
};
}) : [] );
stunsConfig = stunsConfig['stunServers'].concat(stunsConfig['turnServers']);
console.log("success got stun data, making verto");
makeVerto(callbacks, stunsConfig, videoTag, vertoServerCredentials);
}).fail(function(data, textStatus, errorThrown) {
// BBBLog.error("Could not fetch stun/turn servers", {error: textStatus, user: callerIdName, voiceBridge: conferenceVoiceBridge});
callback({'status':'failed', 'errorcode': 1009});
return;
});
}
docall_verto = function(extension, conferenceUsername, conferenceIdNumber, callbacks, options) {
console.log(extension + ", " + conferenceUsername + ", " + conferenceIdNumber);
if (cur_call) { // only allow for one call
console.log("Quitting: Call already in progress");
return;
}
// determine the resolution the user chose for webcam video
my_check_vid_res();
outgoingBandwidth = "default";
incomingBandwidth = "default";
var useVideo = useCamera = useMic = false;
// debugger;
if(options.watchOnly) {
window.watchOnly = true;
window.listenOnly = false;
window.joinAudio = false;
useVideo = true;
useCamera = false;
useMic = false;
} else if(options.listenOnly) {
window.listenOnly = true;
window.watchOnly = false;
window.joinAudio = false;
useVideo = false;
useCamera = false;
useMic = false;
} else if(options.joinAudio) {
window.joinAudio = true;
window.watchOnly = false;
window.listenOnly = false;
useVideo = false;
useCamera = false;
useMic = true;
}
cur_call = verto.newCall({
destination_number: extension,
caller_id_name: conferenceUsername,
caller_id_number: conferenceIdNumber,
outgoingBandwidth: outgoingBandwidth,
incomingBandwidth: incomingBandwidth,
useStereo: true,
useVideo: useVideo,
useCamera: useCamera,
useMic: useMic,
dedEnc: false,
mirrorInput: false
});
if (callbacks != null) { // add user supplied callbacks to the current call
cur_call.rtc.options.callbacks = $.extend(cur_call.rtc.options.callbacks, callbacks);
}
}
// check if logged into verto by seeing if there is a ready websocket connection
function isLoggedIntoVerto() {
return (verto != null ? (ref = verto.rpcClient) != null ? ref.socketReady() : void 0 : void 0);
}
// overwrite and substitute my own init function
init = function(videoTag, vertoServerCredentials) {
videoTag = window.videoTag;
cur_call = null;
share_call = null;
incomingBandwidth = "default";
configStuns(callbacks, callback, videoTag, vertoServerCredentials);
}
// checks whether Google Chrome or Firefox have the WebRTCPeerConnection object
function isWebRTCAvailable_verto() {
return (typeof window.webkitRTCPeerConnection !== 'undefined' || typeof window.mozRTCPeerConnection !== 'undefined');
}
// exit point for conference
function leaveWebRTCVoiceConference_verto() {
console.log("Leaving the voice conference");
webrtc_hangup_verto();
}
function make_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, userCallback, server, recall, options) {
if (userCallback) {
callback = userCallback;
}
callPurposefullyEnded = false;
// after 15 seconds if a call hasn't been established display error, hangup and logout of verto
callTimeout = setTimeout(function() {
console.log('Ten seconds without updates sending timeout code');
callback({'status':'failed', 'errorcode': 1006}); // Failure on call
if (verto != null) {
verto.hangup();
verto.logout();
verto = null;
}
cur_call = null;
}, 10000*1.5);
var myRTCCallbacks = {
onError: function(vertoErrorObject, errorMessage) {
console.error("custom callback: onError");
console.error(vertoErrorObject);
console.error("ERROR:");
console.error(errorMessage);
if(errorMessage.name === "PermissionDeniedError") { // user denied access to media peripherals
console.error("User denied permission/access to hardware");
console.error("getUserMedia: failure - ", errorMessage);
callback({'status': 'mediafail', 'cause': errorMessage});
}
cur_call.hangup({cause: "Device or Permission Error"});
clearTimeout(callTimeout);
},
onICEComplete: function(self, candidate) { // ICE candidate negotiation is complete
console.log("custom callback: onICEComplete");
console.log('Received ICE status changed to completed');
if (callICEConnected === false) {
callICEConnected = true;
if (callActive === true) {
callback({'status':'started'});
}
clearTimeout(callTimeout);
}
},
onStream: function(rtc, stream) { // call has been established
console.log("getUserMicMedia: success");
callback({'status':'mediasuccess'});
console.log("custom callback: stream started");
callActive = true;
console.log('BigBlueButton call accepted');
if (callICEConnected === true) {
callback({'status':'started'});
} else {
callback({'status':'waitingforice'});
}
clearTimeout(callTimeout);
}
};
if(isLoggedIntoVerto()) {
console.log("Verto is logged into FreeSWITCH, socket is available, making call");
callICEConnected = false;
docall_verto(voiceBridge, conferenceUsername, conferenceIdNumber, myRTCCallbacks, options);
if(recall === false) {
console.log('call connecting');
callback({'status': 'connecting'});
} else {
console.log('call connecting again');
}
callback({'status':'mediarequest'});
} else {
console.error("Verto is NOT logged into FreeSWITCH, socket is NOT available, abandoning call request");
}
}
function makeVerto(callbacks, stunsConfig, videoTag, vertoServerCredentials) {
var vertoPort = vertoServerCredentials.vertoPort;
var hostName = vertoServerCredentials.hostName;
var socketUrl = "wss://" + hostName + ":" + vertoPort;
var login = vertoServerCredentials.login;
var password = vertoServerCredentials.password;
var minWidth = "640";
var minHeight = "480";
var maxWidth = "1920";
var maxHeight = "1080";
console.log("stuns info is");
console.log(stunsConfig);
// debugger;
verto = new $.verto({
login: login,
passwd: password,
socketUrl: socketUrl,
tag: videoTag,
ringFile: "sounds/bell_ring2.wav",
loginParams: {foo: true, bar: "yes"},
useVideo: false,
useCamera: false,
iceServers: stunsConfig, // use user supplied stun configuration
// iceServers: true, // use stun, use default verto configuration
}, callbacks);
}
// sets verto to begin using the resolution that the user selected
my_check_vid_res = function() {
var selectedVideoConstraints = getChosenWebcamResolution();
my_real_size(selectedVideoConstraints);
if (verto) {
verto.videoParams({
"minWidth": selectedVideoConstraints.constraints.minWidth,
"minHeight": selectedVideoConstraints.constraints.minHeight,
"maxWidth": selectedVideoConstraints.constraints.maxWidth,
"maxHeight": selectedVideoConstraints.constraints.maxHeight,
"minFrameRate": selectedVideoConstraints.constraints.minFrameRate,
"vertoBestFrameRate": selectedVideoConstraints.constraints.vertoBestFrameRate
});
}
}
my_real_size = function(selectedVideoConstraints) {
$("#" + window.videoTag).height("100%");
$("#" + window.videoTag).width("100%");
}
var RTCPeerConnectionCallbacks = {
iceFailed: function(e) {
console.log('received ice negotiation failed');
callback({'status':'failed', 'errorcode': 1007}); // Failure on call
//
// TODO unless I do this, the call only lasts for a few seconds.
// When I comment out the lines below, it works fine indefinitely
// Anton Georgiev Dec 10 2015
//
//cur_call = null;
//verto.hangup();
//verto = null;
//clearTimeout(callTimeout);
}
};
this.RTCPeerConnectionCallbacks = RTCPeerConnectionCallbacks;
window.verto_afterStreamPublish = function() {}
function webrtc_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, userCallback, options) {
if (userCallback) {
callback = userCallback;
}
console.log("webrtc_call\n"+voiceBridge + ", " + conferenceUsername + ", " + conferenceIdNumber + ", " + callback);
if(!isWebRTCAvailable()) {
callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
return;
}
var server = window.document.location.hostname;
console.log("user " + conferenceUsername + " calling to " + voiceBridge);
if (isLoggedIntoVerto()) {
make_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, callback, "", false, options);
}
}
function webrtc_hangup_verto(userCallback) {
if (userCallback) {
callback = userCallback;
}
callPurposefullyEnded = true;
console.log("Hanging up current session");
if(verto) {
verto.hangup(false, callback);
}
}

View File

@ -0,0 +1,214 @@
var deskshareStream = "deskshareStream";
window[deskshareStream] = null;
this.share_call = null;
// final entry point for sharing from Chrome.
// already have the resolution and constraints chosen
var configDeskshareFromChrome = function(videoTag, callbacks, extensionId, resolutionConstruction) {
// do initial check for extension
getChromeExtensionStatus(extensionId, function(status) {
if (status != "installed-enabled") {
callbacks.onError({'status': 'failed', 'errorcode': 2001});
console.error("No chrome Extension");
return -1;
}
// bring up Chrome screen picker
getScreenConstraints(function(error, screen_constraints) {
if(error) {
callbacks.onError({'status': 'failed', 'errorcode': 2021});
return console.error(error);
}
screen_constraints = resolutionConstruction(screen_constraints);
window.firefoxDesksharePresent = false;
doCall(screen_constraints, videoTag, callbacks);
});
});
};
// entry point for Chrome HTML5 sharing
// connects with html5 client libraries to retrieve a selected resolution
var configDeskshareFromChromeHTML5 = function(videoTag, callbacks, extensionId) {
var resolutionConstruction = function(screen_constraints) {
console.log("modifying video quality");
var selectedDeskshareResolution = getChosenDeskshareResolution(); // this is the video profile the user chose
my_real_size(selectedDeskshareResolution);
var selectedDeskshareConstraints = getDeskshareConstraintsFromResolution(selectedDeskshareResolution, screen_constraints); // convert to a valid constraints object
console.log(selectedDeskshareConstraints);
return selectedDeskshareConstraints.video.mandatory;
};
configDeskshareFromChrome(videoTag, callbacks, extensionId, resolutionConstruction);
};
// entry point when desksharing using Google Chrome via the flash Client
// currently uses a default preset resolution in place of a resolution picker
// prepares the constraints and passes off to generic Chrome handler
var configDeskshareFromChromeFlash = function(videoTag, callbacks, extensionId) {
var resolutionConstruction = function(screen_constraints) {
// BigBlueButton low
var getDeskshareConstraints = function(constraints) {
return {
"audio": false,
"video": {
"mandatory": {
"maxWidth": 160,
"maxHeight": 120,
"chromeMediaSource": constraints.mandatory.chromeMediaSource,
"chromeMediaSourceId": constraints.mandatory.chromeMediaSourceId,
"minFrameRate": 10,
},
"optional": []
}
};
};
console.log("not modifying video quality");
var selectedDeskshareConstraints = getDeskshareConstraints(screen_constraints); // convert to a valid constraints object
console.log(selectedDeskshareConstraints);
return selectedDeskshareConstraints.video.mandatory;
};
configDeskshareFromChrome(videoTag, callbacks, extensionId, resolutionConstruction);
};
// final entry point for Firefox sharing
var configDeskshareFromFirefox = function(screen_constraints, videoTag, callbacks) {
// bypass all the default gUM calls inside jquery.FSRTC.js to use my own
window.firefoxDesksharePresent = true;
// the gUM args to invoke the Firefox screen picker
var screen_constraints = {
video: {
"mozMediaSource": 'window',
"mediaSource": 'window',
}
};
// register the callback to the window namespace to be available in jquery.FSRTC.js
window.firefoxDesksharePresentErrorCallback = callbacks.onError;
doCall(screen_constraints, videoTag, callbacks);
};
var configDeskshareFromFirefoxFlash = function(screen_constraints, videoTag, callbacks) {
console.log("deskshare from firefox flash");
configDeskshareFromFirefox(screen_constraints, videoTag, callbacks);
};
var configDeskshareFromFirefoxHTML5 = function(screen_constraints, videoTag, callbacks) {
console.log("deskshare from firefox html5");
configDeskshareFromFirefox(screen_constraints, videoTag, callbacks);
};
function endScreenshare(loggingCallback, onSuccess) {
console.log("endScreenshare");
if (share_call) {
console.log("a screenshare call is active. Hanging up");
share_call.hangup();
share_call = null;
normalizeCallback(onSuccess)();
} else {
console.log("a screenshare call is NOT active. Doing nothing");
}
normalizeCallback(loggingCallback)({'status':'success', 'message': 'screenshare ended'});
}
function startScreenshare(loggingCallback, videoTag, vertoServerCredentials, extensionId, modifyResolution, onSuccess, onFail) {
onSuccess = normalizeCallback(onSuccess);
onFail = normalizeCallback(onFail);
loggingCallback = normalizeCallback(loggingCallback);
console.log("startScreenshare");
if(!isLoggedIntoVerto()) { // start the verto log in procedure
// runs when the websocket is successfully created
callbacks.onWSLogin = function(v, success) {
startScreenshareAfterLogin(loggingCallback, videoTag, extensionId, modifyResolution, onSuccess, onFail);
loggingCallback({'status':'success', 'message': 'screenshare started'});
console.log("logged in. starting screenshare");
}
// set up verto
init(window.videoTag, vertoServerCredentials);
} else {
console.log("already logged into verto, going straight to making a call");
startScreenshareAfterLogin(loggingCallback, videoTag, extensionId, modifyResolution, onSuccess, onFail);
loggingCallback({'status':'success', 'message': 'screenshare started'});
}
}
function startScreenshareAfterLogin(loggingCallback, videoTag, extensionId, modifyResolution, onSuccess, onFail) {
if (share_call) {
return;
}
outgoingBandwidth = incomingBandwidth = "default";
var sharedev = "screen";
if (sharedev !== "screen") {
console.log("Attempting Screen Capture with non-screen device....");
BBB.getMyUserInfo(function (retData){
share_call = verto.newCall({
destination_number: retData.voiceBridge + "-screen",
caller_id_name: retData.myUsername + " (Screen)",
caller_id_number: retData.myUserID + " (screen)",
outgoingBandwidth: outgoingBandwidth,
incomingBandwidth: incomingBandwidth,
useCamera: sharedev,
useVideo: true,
screenShare: true,
dedEnc: false,
mirrorInput: false
});
});
return;
}
var callbacks = {
onError: normalizeCallback(onFail),
onICEComplete: function(self, candidate) { // ICE candidate negotiation is complete
console.log("custom callback: onICEComplete");
normalizeCallback(onSuccess)(candidate);
}
};
// determine if Firefox or Chrome
// for now the only difference is that html5 has a resolution dialog
if (!!navigator.mozGetUserMedia) {
if (modifyResolution) {
configDeskshareFromFirefoxHTML5(null, videoTag, callbacks);
} else {
configDeskshareFromFirefoxFlash(null, videoTag, callbacks);
}
} else if (!!window.chrome) {
if (modifyResolution) {
configDeskshareFromChromeHTML5(videoTag, callbacks, extensionId);
} else {
configDeskshareFromChromeFlash(videoTag, callbacks, extensionId);
}
}
}
function doCall(screen_constraints, videoTag, callbacks) {
console.log("\n\n\nhere are the screen_constraints\n\n\n");
console.log(screen_constraints);
window.listenOnly = false;
window.watchOnly = false;
window.joinAudio = true;
BBB.getMyUserInfo(function (retData){
var callParams = {
destination_number: retData.voiceBridge + "-screen",
caller_id_name: retData.myUsername + " (Screen)",
caller_id_number: retData.myUserID + " (screen)",
outgoingBandwidth: outgoingBandwidth,
incomingBandwidth: incomingBandwidth,
videoParams: screen_constraints,
useVideo: true,
screenShare: true,
dedEnc: true,
mirrorInput: true,
};
if (videoTag != null) {
callParams.tag = videoTag;
}
share_call = verto.newCall(callParams);
share_call.rtc.options.callbacks = $.extend(share_call.rtc.options.callbacks, callbacks);
});
}

View File

@ -0,0 +1,105 @@
//
// Regular Expression for URL validation
//
// Author: Diego Perini
// Updated: 2010/12/05
// License: MIT
//
// Copyright (c) 2010-2013 Diego Perini (http://www.iport.it)
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// the regular expression composed & commented
// could be easily tweaked for RFC compliance,
// it was expressly modified to fit & satisfy
// these test for an URL shortener:
//
// http://mathiasbynens.be/demo/url-regex
//
// Notes on possible differences from a standard/generic validation:
//
// - utf-8 char class take in consideration the full Unicode range
// - TLDs have been made mandatory so single names like "localhost" fails
// - protocols have been restricted to ftp, http and https only as requested
//
// Changes:
//
// - IP address dotted notation validation, range: 1.0.0.0 - 223.255.255.255
// first and last IP address of each class is considered invalid
// (since they are broadcast/network addresses)
//
// - Added exclusion of private, reserved and/or local networks ranges
//
// Compressed one-line versions:
//
// Javascript version
//
// /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/i
//
// PHP version
//
// _^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]-*)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]-*)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/\S*)?$_iuS
//
var re_weburl = new RegExp(
// protocol identifier
"(?:(?:https?|ftp)://)" +
// user:pass authentication
"(?:\\S+(?::\\S*)?@)?" +
"(?:" +
// IP address exclusion
// private & local networks
"(?!(?:10|127)(?:\\.\\d{1,3}){3})" +
"(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +
"(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
// IP address dotted notation octets
// excludes loopback network 0.0.0.0
// excludes reserved space >= 224.0.0.0
// excludes network & broacast addresses
// (first & last IP address of each class)
"(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
"(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
"(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
"|" +
// host name
"(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
// domain name
"(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
// TLD identifier
"(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
")" +
// port number
"(?::\\d{2,5})?" +
// resource path
"(?:/\\S*)?", "gi"
);
function checkURLRegex(message) {
return re_weburl.match(message);
}
function parseURLs(message) {
return String(message).replace(re_weburl, linkify);
}
function linkify(match) {
return '<a href="event:' + match + '"> <u>' + match + '</u></a>';
}

View File

@ -0,0 +1,54 @@
<?xml version="1.0" ?>
<locales>
<locale code="ar_SY" name="Arabic (Syria)"/>
<locale code="az_AZ" name="Azerbaijani"/>
<locale code="eu_EU" name="Basque" />
<locale code="bn_BN" name="Bengali" />
<locale code="bg_BG" name="Bulgarian" />
<locale code="ca_ES" name="Catalan" />
<locale code="zh_CN" name="Chinese (Simplified)"/>
<locale code="zh_TW" name="Chinese (Traditional)"/>
<locale code="hr_HR" name="Croatian" />
<locale code="cs_CZ" name="Czech" />
<locale code="da_DK" name="Danish" />
<locale code="nl_NL" name="Dutch" />
<locale code="en_US" name="English"/>
<locale code="et_EE" name="Estonian"/>
<locale code="fa_IR" name="Farsi" />
<locale code="fi_FI" name="Finnish"/>
<locale code="fr_FR" name="French"/>
<locale code="fr_CA" name="French (Canadian)"/>
<locale code="ff_SN" name="Fulah"/>
<locale code="de_DE" name="German"/>
<locale code="el_GR" name="Greek"/>
<locale code="he_IL" name="Hebrew"/>
<locale code="hu_HU" name="Hungarian"/>
<locale code="id_ID" name="Indonesian"/>
<locale code="it_IT" name="Italian"/>
<locale code="ja_JP" name="Japanese"/>
<locale code="ko_KR" name="Korean"/>
<locale code="lv_LV" name="Latvian"/>
<locale code="lt_LT" name="Lithuania"/>
<locale code="mn_MN" name="Mongolian"/>
<locale code="ne_NE" name="Nepali"/>
<locale code="no_NO" name="Norwegian"/>
<locale code="oc" name="Occitan"/>
<locale code="pl_PL" name="Polish"/>
<locale code="pt_BR" name="Portuguese (Brazilian)"/>
<locale code="pt_PT" name="Portuguese"/>
<locale code="ro_RO" name="Romanian"/>
<locale code="ru_RU" name="Russian"/>
<locale code="sr_SR" name="Serbian (Cyrillic)"/>
<locale code="sr_RS" name="Serbian (Latin)"/>
<locale code="si_LK" name="Sinhala"/>
<locale code="sk_SK" name="Slovak"/>
<locale code="sl_SL" name="Slovenian"/>
<locale code="es_ES" name="Spanish"/>
<locale code="es_LA" name="Spanish (Latin American)"/>
<locale code="sv_SE" name="Swedish"/>
<locale code="th_TH" name="Thai"/>
<locale code="tr_TR" name="Turkish"/>
<locale code="uk_UA" name="Ukrainian"/>
<locale code="vi_VN" name="Vietnamese"/>
<locale code="cy_GB" name="Welsh"/>
</locales>

View File

@ -0,0 +1,78 @@
<?xml version="1.0"?>
<profiles fallbackLocale="en_US">
<profile id="low">
<locale>
<en_US>Low quality</en_US>
<pt_BR>Baixa qualidade</pt_BR>
</locale>
<width>160</width>
<height>120</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>10</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>true</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
<profile id="medium" default="true">
<locale>
<en_US>Medium quality</en_US>
<pt_BR>Média qualidade</pt_BR>
</locale>
<width>320</width>
<height>240</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>10</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>true</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
<profile id="high">
<locale>
<en_US>High quality</en_US>
<pt_BR>Alta qualidade</pt_BR>
</locale>
<width>640</width>
<height>480</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>15</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>true</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
<profile id="wide">
<locale>
<en_US>Widescreen</en_US>
<pt_BR>Panorâmico</pt_BR>
</locale>
<width>1280</width>
<height>720</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>15</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>true</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
<profile id="lowlatency">
<locale>
<en_US>Low Latency</en_US>
<pt_BR>Baixa Latência</pt_BR>
</locale>
<width>640</width>
<height>480</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>15</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>false</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
</profiles>

File diff suppressed because one or more lines are too long