").html(f.clone()).html(),c=b.indexOf(" type=")>-1,d=c?/\s+type=["']?\w+['"]?/:/\/?>/,e=' type="'+h+'" data-'+a.mobile.ns+'type="'+g+'"'+(c?"":">"),f.replaceWith(b.replace(d,e)))})}}(a),function(a,b,c){a.widget("mobile.page",a.mobile.page,{options:{closeBtn:"left",closeBtnText:"Close",overlayTheme:"a",corners:!0,dialog:!1},_create:function(){this._super(),this.options.dialog&&(a.extend(this,{_inner:this.element.children(),_headerCloseButton:null}),this.options.enhanced||this._setCloseBtn(this.options.closeBtn))},_enhance:function(){this._super(),this.options.dialog&&this.element.addClass("ui-dialog").wrapInner(a("
",{role:"dialog","class":"ui-dialog-contain ui-overlay-shadow"+(this.options.corners?" ui-corner-all":"")}))},_setOptions:function(b){var d,e,f=this.options;b.corners!==c&&this._inner.toggleClass("ui-corner-all",!!b.corners),b.overlayTheme!==c&&a.mobile.activePage[0]===this.element[0]&&(f.overlayTheme=b.overlayTheme,this._handlePageBeforeShow()),b.closeBtnText!==c&&(d=f.closeBtn,e=b.closeBtnText),b.closeBtn!==c&&(d=b.closeBtn),d&&this._setCloseBtn(d,e),this._super(b)},_handlePageBeforeShow:function(){this.options.overlayTheme&&this.options.dialog?(this.removeContainerBackground(),this.setContainerBackground(this.options.overlayTheme)):this._super()},_setCloseBtn:function(b,c){var d,e=this._headerCloseButton;b="left"===b?"left":"right"===b?"right":"none","none"===b?e&&(e.remove(),e=null):e?(e.removeClass("ui-btn-left ui-btn-right").addClass("ui-btn-"+b),c&&e.text(c)):(d=this._inner.find(":jqmData(role='header')").first(),e=a("
",{href:"#","class":"ui-btn ui-corner-all ui-icon-delete ui-btn-icon-notext ui-btn-"+b}).attr("data-"+a.mobile.ns+"rel","back").text(c||this.options.closeBtnText||"").prependTo(d)),this._headerCloseButton=e}})}(a,this),function(a,b,c){a.widget("mobile.dialog",{options:{closeBtn:"left",closeBtnText:"Close",overlayTheme:"a",corners:!0},_handlePageBeforeShow:function(){this._isCloseable=!0,this.options.overlayTheme&&this.element.page("removeContainerBackground").page("setContainerBackground",this.options.overlayTheme)},_handlePageBeforeHide:function(){this._isCloseable=!1},_handleVClickSubmit:function(b){var c,d=a(b.target).closest("vclick"===b.type?"a":"form");d.length&&!d.jqmData("transition")&&(c={},c["data-"+a.mobile.ns+"transition"]=(a.mobile.navigate.history.getActive()||{}).transition||a.mobile.defaultDialogTransition,c["data-"+a.mobile.ns+"direction"]="reverse",d.attr(c))},_create:function(){var b=this.element,c=this.options;b.addClass("ui-dialog").wrapInner(a("
",{role:"dialog","class":"ui-dialog-contain ui-overlay-shadow"+(c.corners?" ui-corner-all":"")})),a.extend(this,{_isCloseable:!1,_inner:b.children(),_headerCloseButton:null}),this._on(b,{vclick:"_handleVClickSubmit",submit:"_handleVClickSubmit",pagebeforeshow:"_handlePageBeforeShow",pagebeforehide:"_handlePageBeforeHide"}),this._setCloseBtn(c.closeBtn)},_setOptions:function(b){var d,e,f=this.options;b.corners!==c&&this._inner.toggleClass("ui-corner-all",!!b.corners),b.overlayTheme!==c&&a.mobile.activePage[0]===this.element[0]&&(f.overlayTheme=b.overlayTheme,this._handlePageBeforeShow()),b.closeBtnText!==c&&(d=f.closeBtn,e=b.closeBtnText),b.closeBtn!==c&&(d=b.closeBtn),d&&this._setCloseBtn(d,e),this._super(b)},_setCloseBtn:function(b,c){var d,e=this._headerCloseButton;b="left"===b?"left":"right"===b?"right":"none","none"===b?e&&(e.remove(),e=null):e?(e.removeClass("ui-btn-left ui-btn-right").addClass("ui-btn-"+b),c&&e.text(c)):(d=this._inner.find(":jqmData(role='header')").first(),e=a("
",{role:"button",href:"#","class":"ui-btn ui-corner-all ui-icon-delete ui-btn-icon-notext ui-btn-"+b}).text(c||this.options.closeBtnText||"").prependTo(d),this._on(e,{click:"close"})),this._headerCloseButton=e},close:function(){var b=a.mobile.navigate.history;this._isCloseable&&(this._isCloseable=!1,a.mobile.hashListeningEnabled&&b.activeIndex>0?a.mobile.back():a.mobile.pageContainer.pagecontainer("back"))}})}(a,this),function(a,b){var c=/([A-Z])/g,d=function(a){return"ui-btn-icon-"+(null===a?"left":a)};a.widget("mobile.collapsible",{options:{enhanced:!1,expandCueText:null,collapseCueText:null,collapsed:!0,heading:"h1,h2,h3,h4,h5,h6,legend",collapsedIcon:null,expandedIcon:null,iconpos:null,theme:null,contentTheme:null,inset:null,corners:null,mini:null},_create:function(){var b=this.element,c={accordion:b.closest(":jqmData(role='collapsible-set'),:jqmData(role='collapsibleset')"+(a.mobile.collapsibleset?", :mobile-collapsibleset":"")).addClass("ui-collapsible-set")};this._ui=c,this._renderedOptions=this._getOptions(this.options),this.options.enhanced?(c.heading=a(".ui-collapsible-heading",this.element[0]),c.content=c.heading.next(),c.anchor=a("a",c.heading[0]).first(),c.status=c.anchor.children(".ui-collapsible-heading-status")):this._enhance(b,c),this._on(c.heading,{tap:function(){c.heading.find("a").first().addClass(a.mobile.activeBtnClass)},click:function(a){this._handleExpandCollapse(!c.heading.hasClass("ui-collapsible-heading-collapsed")),a.preventDefault(),a.stopPropagation()}})},_getOptions:function(b){var d,e=this._ui.accordion,f=this._ui.accordionWidget;b=a.extend({},b),e.length&&!f&&(this._ui.accordionWidget=f=e.data("mobile-collapsibleset"));for(d in b)b[d]=null!=b[d]?b[d]:f?f.options[d]:e.length?a.mobile.getAttribute(e[0],d.replace(c,"-$1").toLowerCase()):null,null==b[d]&&(b[d]=a.mobile.collapsible.defaults[d]);return b},_themeClassFromOption:function(a,b){return b?"none"===b?"":a+b:""},_enhance:function(b,c){var e,f=this._renderedOptions,g=this._themeClassFromOption("ui-body-",f.contentTheme);return b.addClass("ui-collapsible "+(f.inset?"ui-collapsible-inset ":"")+(f.inset&&f.corners?"ui-corner-all ":"")+(g?"ui-collapsible-themed-content ":"")),c.originalHeading=b.children(this.options.heading).first(),c.content=b.wrapInner("
").children(".ui-collapsible-content"),c.heading=c.originalHeading,c.heading.is("legend")&&(c.heading=a("
"+c.heading.html()+"
"),c.placeholder=a("
").insertBefore(c.originalHeading),c.originalHeading.remove()),e=f.collapsed?f.collapsedIcon?"ui-icon-"+f.collapsedIcon:"":f.expandedIcon?"ui-icon-"+f.expandedIcon:"",c.status=a("
"),c.anchor=c.heading.detach().addClass("ui-collapsible-heading").append(c.status).wrapInner("
").find("a").first().addClass("ui-btn "+(e?e+" ":"")+(e?d(f.iconpos)+" ":"")+this._themeClassFromOption("ui-btn-",f.theme)+" "+(f.mini?"ui-mini ":"")),c.heading.insertBefore(c.content),this._handleExpandCollapse(this.options.collapsed),c},refresh:function(){this._applyOptions(this.options),this._renderedOptions=this._getOptions(this.options)},_applyOptions:function(a){var c,e,f,g,h,i=this.element,j=this._renderedOptions,k=this._ui,l=k.anchor,m=k.status,n=this._getOptions(a);a.collapsed!==b&&this._handleExpandCollapse(a.collapsed),c=i.hasClass("ui-collapsible-collapsed"),c?n.expandCueText!==b&&m.text(n.expandCueText):n.collapseCueText!==b&&m.text(n.collapseCueText),h=n.collapsedIcon!==b?n.collapsedIcon!==!1:j.collapsedIcon!==!1,(n.iconpos!==b||n.collapsedIcon!==b||n.expandedIcon!==b)&&(l.removeClass([d(j.iconpos)].concat(j.expandedIcon?["ui-icon-"+j.expandedIcon]:[]).concat(j.collapsedIcon?["ui-icon-"+j.collapsedIcon]:[]).join(" ")),h&&l.addClass([d(n.iconpos!==b?n.iconpos:j.iconpos)].concat(c?["ui-icon-"+(n.collapsedIcon!==b?n.collapsedIcon:j.collapsedIcon)]:["ui-icon-"+(n.expandedIcon!==b?n.expandedIcon:j.expandedIcon)]).join(" "))),n.theme!==b&&(f=this._themeClassFromOption("ui-btn-",j.theme),e=this._themeClassFromOption("ui-btn-",n.theme),l.removeClass(f).addClass(e)),n.contentTheme!==b&&(f=this._themeClassFromOption("ui-body-",j.contentTheme),e=this._themeClassFromOption("ui-body-",n.contentTheme),k.content.removeClass(f).addClass(e)),n.inset!==b&&(i.toggleClass("ui-collapsible-inset",n.inset),g=!(!n.inset||!n.corners&&!j.corners)),n.corners!==b&&(g=!(!n.corners||!n.inset&&!j.inset)),g!==b&&i.toggleClass("ui-corner-all",g),n.mini!==b&&l.toggleClass("ui-mini",n.mini)},_setOptions:function(a){this._applyOptions(a),this._super(a),this._renderedOptions=this._getOptions(this.options)},_handleExpandCollapse:function(b){var c=this._renderedOptions,d=this._ui;d.status.text(b?c.expandCueText:c.collapseCueText),d.heading.toggleClass("ui-collapsible-heading-collapsed",b).find("a").first().toggleClass("ui-icon-"+c.expandedIcon,!b).toggleClass("ui-icon-"+c.collapsedIcon,b||c.expandedIcon===c.collapsedIcon).removeClass(a.mobile.activeBtnClass),this.element.toggleClass("ui-collapsible-collapsed",b),d.content.toggleClass("ui-collapsible-content-collapsed",b).attr("aria-hidden",b).trigger("updatelayout"),this.options.collapsed=b,this._trigger(b?"collapse":"expand")},expand:function(){this._handleExpandCollapse(!1)},collapse:function(){this._handleExpandCollapse(!0)},_destroy:function(){var a=this._ui,b=this.options;b.enhanced||(a.placeholder?(a.originalHeading.insertBefore(a.placeholder),a.placeholder.remove(),a.heading.remove()):(a.status.remove(),a.heading.removeClass("ui-collapsible-heading ui-collapsible-heading-collapsed").children().contents().unwrap()),a.anchor.contents().unwrap(),a.content.contents().unwrap(),this.element.removeClass("ui-collapsible ui-collapsible-collapsed ui-collapsible-themed-content ui-collapsible-inset ui-corner-all"))}}),a.mobile.collapsible.defaults={expandCueText:" click to expand contents",collapseCueText:" click to collapse contents",collapsedIcon:"plus",contentTheme:"inherit",expandedIcon:"minus",iconpos:"left",inset:!0,corners:!0,theme:"inherit",mini:!1}}(a),function(a){function b(b){var d,e=b.length,f=[];for(d=0;e>d;d++)b[d].className.match(c)||f.push(b[d]);return a(f)}var c=/\bui-screen-hidden\b/;a.mobile.behaviors.addFirstLastClasses={_getVisibles:function(a,c){var d;return c?d=b(a):(d=a.filter(":visible"),0===d.length&&(d=b(a))),d},_addFirstLastClasses:function(a,b,c){a.removeClass("ui-first-child ui-last-child"),b.eq(0).addClass("ui-first-child").end().last().addClass("ui-last-child"),c||this.element.trigger("updatelayout")},_removeFirstLastClasses:function(a){a.removeClass("ui-first-child ui-last-child")}}}(a),function(a,b){var c=":mobile-collapsible, "+a.mobile.collapsible.initSelector;a.widget("mobile.collapsibleset",a.extend({initSelector:":jqmData(role='collapsible-set'),:jqmData(role='collapsibleset')",options:a.extend({enhanced:!1},a.mobile.collapsible.defaults),_handleCollapsibleExpand:function(b){var c=a(b.target).closest(".ui-collapsible");c.parent().is(":mobile-collapsibleset, :jqmData(role='collapsible-set')")&&c.siblings(".ui-collapsible:not(.ui-collapsible-collapsed)").collapsible("collapse")},_create:function(){var b=this.element,c=this.options;a.extend(this,{_classes:""}),c.enhanced||(b.addClass("ui-collapsible-set "+this._themeClassFromOption("ui-group-theme-",c.theme)+" "+(c.corners&&c.inset?"ui-corner-all ":"")),this.element.find(a.mobile.collapsible.initSelector).collapsible()),this._on(b,{collapsibleexpand:"_handleCollapsibleExpand"})},_themeClassFromOption:function(a,b){return b?"none"===b?"":a+b:""},_init:function(){this._refresh(!0),this.element.children(c).filter(":jqmData(collapsed='false')").collapsible("expand")},_setOptions:function(a){var c,d,e=this.element,f=this._themeClassFromOption("ui-group-theme-",a.theme);return f&&e.removeClass(this._themeClassFromOption("ui-group-theme-",this.options.theme)).addClass(f),a.inset!==b&&(d=!(!a.inset||!a.corners&&!this.options.corners)),a.corners!==b&&(d=!(!a.corners||!a.inset&&!this.options.inset)),d!==b&&e.toggleClass("ui-corner-all",d),c=this._super(a),this.element.children(":mobile-collapsible").collapsible("refresh"),c},_destroy:function(){var a=this.element;this._removeFirstLastClasses(a.children(c)),a.removeClass("ui-collapsible-set ui-corner-all "+this._themeClassFromOption("ui-group-theme-",this.options.theme)).children(":mobile-collapsible").collapsible("destroy")},_refresh:function(b){var d=this.element.children(c);this.element.find(a.mobile.collapsible.initSelector).not(".ui-collapsible").collapsible(),this._addFirstLastClasses(d,this._getVisibles(d,b),b)},refresh:function(){this._refresh(!1)}},a.mobile.behaviors.addFirstLastClasses))}(a),function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain")}}(a),function(a){a.fn.grid=function(b){return this.each(function(){var c,d,e=a(this),f=a.extend({grid:null},b),g=e.children(),h={solo:1,a:2,b:3,c:4,d:5},i=f.grid;if(!i)if(g.length<=5)for(d in h)h[d]===g.length&&(i=d);else i="a",e.addClass("ui-grid-duo");c=h[i],e.addClass("ui-grid-"+i),g.filter(":nth-child("+c+"n+1)").addClass("ui-block-a"),c>1&&g.filter(":nth-child("+c+"n+2)").addClass("ui-block-b"),c>2&&g.filter(":nth-child("+c+"n+3)").addClass("ui-block-c"),c>3&&g.filter(":nth-child("+c+"n+4)").addClass("ui-block-d"),c>4&&g.filter(":nth-child("+c+"n+5)").addClass("ui-block-e")})}}(a),function(a,b){a.widget("mobile.navbar",{options:{iconpos:"top",grid:null},_create:function(){var d=this.element,e=d.find("a"),f=e.filter(":jqmData(icon)").length?this.options.iconpos:b;d.addClass("ui-navbar").attr("role","navigation").find("ul").jqmEnhanceable().grid({grid:this.options.grid}),e.each(function(){var b=a.mobile.getAttribute(this,"icon"),c=a.mobile.getAttribute(this,"theme"),d="ui-btn";c&&(d+=" ui-btn-"+c),b&&(d+=" ui-icon-"+b+" ui-btn-icon-"+f),a(this).addClass(d)}),d.delegate("a","vclick",function(){var b=a(this);b.hasClass("ui-state-disabled")||b.hasClass("ui-disabled")||b.hasClass(a.mobile.activeBtnClass)||(e.removeClass(a.mobile.activeBtnClass),b.addClass(a.mobile.activeBtnClass),a(c).one("pagehide",function(){b.removeClass(a.mobile.activeBtnClass)}))}),d.closest(".ui-page").bind("pagebeforeshow",function(){e.filter(".ui-state-persist").addClass(a.mobile.activeBtnClass)})}})}(a),function(a){var b=a.mobile.getAttribute;a.widget("mobile.listview",a.extend({options:{theme:null,countTheme:null,dividerTheme:null,icon:"carat-r",splitIcon:"carat-r",splitTheme:null,corners:!0,shadow:!0,inset:!1},_create:function(){var a=this,b="";b+=a.options.inset?" ui-listview-inset":"",a.options.inset&&(b+=a.options.corners?" ui-corner-all":"",b+=a.options.shadow?" ui-shadow":""),a.element.addClass(" ui-listview"+b),a.refresh(!0)},_findFirstElementByTagName:function(a,b,c,d){var e={};for(e[c]=e[d]=!0;a;){if(e[a.nodeName])return a;a=a[b]}return null},_addThumbClasses:function(b){var c,d,e=b.length;for(c=0;e>c;c++)d=a(this._findFirstElementByTagName(b[c].firstChild,"nextSibling","img","IMG")),d.length&&a(this._findFirstElementByTagName(d[0].parentNode,"parentNode","li","LI")).addClass(d.hasClass("ui-li-icon")?"ui-li-has-icon":"ui-li-has-thumb")},_getChildrenByTagName:function(b,c,d){var e=[],f={};for(f[c]=f[d]=!0,b=b.firstChild;b;)f[b.nodeName]&&e.push(b),b=b.nextSibling;return a(e)},_beforeListviewRefresh:a.noop,_afterListviewRefresh:a.noop,refresh:function(c){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x=this.options,y=this.element,z=!!a.nodeName(y[0],"ol"),A=y.attr("start"),B={},C=y.find(".ui-li-count"),D=b(y[0],"counttheme")||this.options.countTheme,E=D?"ui-body-"+D:"ui-body-inherit";for(x.theme&&y.addClass("ui-group-theme-"+x.theme),z&&(A||0===A)&&(n=parseInt(A,10)-1,y.css("counter-reset","listnumbering "+n)),this._beforeListviewRefresh(),w=this._getChildrenByTagName(y[0],"li","LI"),e=0,f=w.length;f>e;e++)g=w.eq(e),h="",(c||g[0].className.search(/\bui-li-static\b|\bui-li-divider\b/)<0)&&(l=this._getChildrenByTagName(g[0],"a","A"),m="list-divider"===b(g[0],"role"),p=g.attr("value"),i=b(g[0],"theme"),l.length&&l[0].className.search(/\bui-btn\b/)<0&&!m?(j=b(g[0],"icon"),k=j===!1?!1:j||x.icon,l.removeClass("ui-link"),d="ui-btn",i&&(d+=" ui-btn-"+i),l.length>1?(h="ui-li-has-alt",q=l.last(),r=b(q[0],"theme")||x.splitTheme||b(g[0],"theme",!0),s=r?" ui-btn-"+r:"",t=b(q[0],"icon")||b(g[0],"icon")||x.splitIcon,u="ui-btn ui-btn-icon-notext ui-icon-"+t+s,q.attr("title",a.trim(q.getEncodedText())).addClass(u).empty(),l=l.first()):k&&(d+=" ui-btn-icon-right ui-icon-"+k),l.addClass(d)):m?(v=b(g[0],"theme")||x.dividerTheme||x.theme,h="ui-li-divider ui-bar-"+(v?v:"inherit"),g.attr("role","heading")):l.length<=0&&(h="ui-li-static ui-body-"+(i?i:"inherit")),z&&p&&(o=parseInt(p,10)-1,g.css("counter-reset","listnumbering "+o))),B[h]||(B[h]=[]),B[h].push(g[0]);for(h in B)a(B[h]).addClass(h);C.each(function(){a(this).closest("li").addClass("ui-li-has-count")}),E&&C.not("[class*='ui-body-']").addClass(E),this._addThumbClasses(w),this._addThumbClasses(w.find(".ui-btn")),this._afterListviewRefresh(),this._addFirstLastClasses(w,this._getVisibles(w,c),c)}},a.mobile.behaviors.addFirstLastClasses))}(a),function(a){function b(b){var c=a.trim(b.text())||null;return c?c=c.slice(0,1).toUpperCase():null}a.widget("mobile.listview",a.mobile.listview,{options:{autodividers:!1,autodividersSelector:b},_beforeListviewRefresh:function(){this.options.autodividers&&(this._replaceDividers(),this._superApply(arguments))},_replaceDividers:function(){var b,d,e,f,g,h=null,i=this.element;for(i.children("li:jqmData(role='list-divider')").remove(),d=i.children("li"),b=0;b
-1;d--)e=a[d],e.className.match(b)?(f&&(e.className=e.className+" ui-screen-hidden"),f=!0):e.className.match(c)||(f=!1)}})}(a),function(a){a.mobile.nojs=function(b){a(":jqmData(role='nojs')",b).addClass("ui-nojs")}}(a),function(a){a.mobile.behaviors.formReset={_handleFormReset:function(){this._on(this.element.closest("form"),{reset:function(){this._delay("_reset")}})}}}(a),function(a,b){var c=a.mobile.path.hashToSelector;a.widget("mobile.checkboxradio",a.extend({initSelector:"input:not( :jqmData(role='flipswitch' ) )[type='checkbox'],input[type='radio']:not( :jqmData(role='flipswitch' ))",options:{theme:"inherit",mini:!1,wrapperClass:null,enhanced:!1,iconpos:"left"},_create:function(){var b=this.element,c=this.options,d=function(a,b){return a.jqmData(b)||a.closest("form, fieldset").jqmData(b)},e=this.options.enhanced?{element:this.element.siblings("label"),isParent:!1}:this._findLabel(),f=b[0].type,g="ui-"+f+"-on",h="ui-"+f+"-off";("checkbox"===f||"radio"===f)&&(this.element[0].disabled&&(this.options.disabled=!0),c.iconpos=d(b,"iconpos")||e.element.attr("data-"+a.mobile.ns+"iconpos")||c.iconpos,c.mini=d(b,"mini")||c.mini,a.extend(this,{input:b,label:e.element,labelIsParent:e.isParent,inputtype:f,checkedClass:g,uncheckedClass:h}),this.options.enhanced||this._enhance(),this._on(e.element,{vmouseover:"_handleLabelVMouseOver",vclick:"_handleLabelVClick"}),this._on(b,{vmousedown:"_cacheVals",vclick:"_handleInputVClick",focus:"_handleInputFocus",blur:"_handleInputBlur"}),this._handleFormReset(),this.refresh())},_findLabel:function(){var b,d,e,f=this.element,g=f[0].labels;return g&&g.length>0?(d=a(g[0]),e=a.contains(d[0],f[0])):(b=f.closest("label"),e=b.length>0,d=e?b:a(this.document[0].getElementsByTagName("label")).filter("[for='"+c(f[0].id)+"']").first()),{element:d,isParent:e}},_enhance:function(){this.label.addClass("ui-btn ui-corner-all"),this.labelIsParent?this.input.add(this.label).wrapAll(this._wrapper()):(this.element.wrap(this._wrapper()),this.element.parent().prepend(this.label)),this._setOptions({theme:this.options.theme,iconpos:this.options.iconpos,mini:this.options.mini})},_wrapper:function(){return a("")},_handleInputFocus:function(){this.label.addClass(a.mobile.focusClass)},_handleInputBlur:function(){this.label.removeClass(a.mobile.focusClass)},_handleInputVClick:function(){this.element.prop("checked",this.element.is(":checked")),this._getInputSet().not(this.element).prop("checked",!1),this._updateAll(!0)},_handleLabelVMouseOver:function(a){this.label.parent().hasClass("ui-state-disabled")&&a.stopPropagation()},_handleLabelVClick:function(a){var b=this.element;return b.is(":disabled")?void a.preventDefault():(this._cacheVals(),b.prop("checked","radio"===this.inputtype&&!0||!b.prop("checked")),b.triggerHandler("click"),this._getInputSet().not(b).prop("checked",!1),this._updateAll(),!1)},_cacheVals:function(){this._getInputSet().each(function(){a(this).attr("data-"+a.mobile.ns+"cacheVal",this.checked)})},_getInputSet:function(){var b,d,e=this.element[0],f=e.name,g=e.form,h=this.element.parents().last().get(0),i=this.element;return f&&"radio"===this.inputtype&&h&&(b="input[type='radio'][name='"+c(f)+"']",g?(d=g.getAttribute("id"),d&&(i=a(b+"[form='"+c(d)+"']",h)),i=a(g).find(b).filter(function(){return this.form===g}).add(i)):i=a(b,h).filter(function(){return!this.form})),i},_updateAll:function(b){var c=this;this._getInputSet().each(function(){var d=a(this);!this.checked&&"checkbox"!==c.inputtype||b||d.trigger("change")}).checkboxradio("refresh")},_reset:function(){this.refresh()},_hasIcon:function(){var b,c,d=a.mobile.controlgroup;return d&&(b=this.element.closest(":mobile-controlgroup,"+d.prototype.initSelector),b.length>0)?(c=a.data(b[0],"mobile-controlgroup"),"horizontal"!==(c?c.options.type:b.attr("data-"+a.mobile.ns+"type"))):!0},refresh:function(){var b=this._hasIcon(),c=this.element[0].checked,d=a.mobile.activeBtnClass,e="ui-btn-icon-"+this.options.iconpos,f=[],g=[];b?(g.push(d),f.push(e)):(g.push(e),(c?f:g).push(d)),c?(f.push(this.checkedClass),g.push(this.uncheckedClass)):(f.push(this.uncheckedClass),g.push(this.checkedClass)),this.label.addClass(f.join(" ")).removeClass(g.join(" "))},widget:function(){return this.label.parent()},_setOptions:function(a){var c=this.label,d=this.options,e=this.widget(),f=this._hasIcon();a.disabled!==b&&(this.input.prop("disabled",!!a.disabled),e.toggleClass("ui-state-disabled",!!a.disabled)),a.mini!==b&&e.toggleClass("ui-mini",!!a.mini),a.theme!==b&&c.removeClass("ui-btn-"+d.theme).addClass("ui-btn-"+a.theme),a.wrapperClass!==b&&e.removeClass(d.wrapperClass).addClass(a.wrapperClass),a.iconpos!==b&&f?c.removeClass("ui-btn-icon-"+d.iconpos).addClass("ui-btn-icon-"+a.iconpos):f||c.removeClass("ui-btn-icon-"+d.iconpos),this._super(a)}},a.mobile.behaviors.formReset))}(a),function(a,b){a.widget("mobile.button",{initSelector:"input[type='button'], input[type='submit'], input[type='reset']",options:{theme:null,icon:null,iconpos:"left",iconshadow:!1,corners:!0,shadow:!0,inline:null,mini:null,wrapperClass:null,enhanced:!1},_create:function(){this.element.is(":disabled")&&(this.options.disabled=!0),this.options.enhanced||this._enhance(),a.extend(this,{wrapper:this.element.parent()}),this._on({focus:function(){this.widget().addClass(a.mobile.focusClass)},blur:function(){this.widget().removeClass(a.mobile.focusClass)}}),this.refresh(!0)},_enhance:function(){this.element.wrap(this._button())},_button:function(){var b=this.options,c=this._getIconClasses(this.options);return a(""+this.element.val()+"
")},widget:function(){return this.wrapper},_destroy:function(){this.element.insertBefore(this.button),this.button.remove()},_getIconClasses:function(a){return a.icon?"ui-icon-"+a.icon+(a.iconshadow?" ui-shadow-icon":"")+" ui-btn-icon-"+a.iconpos:""},_setOptions:function(c){var d=this.widget();c.theme!==b&&d.removeClass(this.options.theme).addClass("ui-btn-"+c.theme),c.corners!==b&&d.toggleClass("ui-corner-all",c.corners),c.shadow!==b&&d.toggleClass("ui-shadow",c.shadow),c.inline!==b&&d.toggleClass("ui-btn-inline",c.inline),c.mini!==b&&d.toggleClass("ui-mini",c.mini),c.disabled!==b&&(this.element.prop("disabled",c.disabled),d.toggleClass("ui-state-disabled",c.disabled)),(c.icon!==b||c.iconshadow!==b||c.iconpos!==b)&&d.removeClass(this._getIconClasses(this.options)).addClass(this._getIconClasses(a.extend({},this.options,c))),this._super(c)},refresh:function(b){var c,d=this.element.prop("disabled");this.options.icon&&"notext"===this.options.iconpos&&this.element.attr("title")&&this.element.attr("title",this.element.val()),b||(c=this.element.detach(),a(this.wrapper).text(this.element.val()).append(c)),this.options.disabled!==d&&this._setOptions({disabled:d})}})}(a),function(a){var b=a("meta[name=viewport]"),c=b.attr("content"),d=c+",maximum-scale=1, user-scalable=no",e=c+",maximum-scale=10, user-scalable=yes",f=/(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test(c);a.mobile.zoom=a.extend({},{enabled:!f,locked:!1,disable:function(c){f||a.mobile.zoom.locked||(b.attr("content",d),a.mobile.zoom.enabled=!1,a.mobile.zoom.locked=c||!1)},enable:function(c){f||a.mobile.zoom.locked&&c!==!0||(b.attr("content",e),a.mobile.zoom.enabled=!0,a.mobile.zoom.locked=!1)},restore:function(){f||(b.attr("content",c),a.mobile.zoom.enabled=!0)}})}(a),function(a,b){a.widget("mobile.textinput",{initSelector:"input[type='text'],input[type='search'],:jqmData(type='search'),input[type='number'],:jqmData(type='number'),input[type='password'],input[type='email'],input[type='url'],input[type='tel'],textarea,input[type='time'],input[type='date'],input[type='month'],input[type='week'],input[type='datetime'],input[type='datetime-local'],input[type='color'],input:not([type]),input[type='file']",options:{theme:null,corners:!0,mini:!1,preventFocusZoom:/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1,wrapperClass:"",enhanced:!1},_create:function(){var b=this.options,c=this.element.is("[type='search'], :jqmData(type='search')"),d="TEXTAREA"===this.element[0].tagName,e=this.element.is("[data-"+(a.mobile.ns||"")+"type='range']"),f=(this.element.is("input")||this.element.is("[data-"+(a.mobile.ns||"")+"type='search']"))&&!e;this.element.prop("disabled")&&(b.disabled=!0),a.extend(this,{classes:this._classesFromOptions(),isSearch:c,isTextarea:d,isRange:e,inputNeedsWrap:f}),this._autoCorrect(),b.enhanced||this._enhance(),this._on({focus:"_handleFocus",blur:"_handleBlur"})},refresh:function(){this.setOptions({disabled:this.element.is(":disabled")})},_enhance:function(){var a=[];this.isTextarea&&a.push("ui-input-text"),(this.isTextarea||this.isRange)&&a.push("ui-shadow-inset"),this.inputNeedsWrap?this.element.wrap(this._wrap()):a=a.concat(this.classes),this.element.addClass(a.join(" "))},widget:function(){return this.inputNeedsWrap?this.element.parent():this.element},_classesFromOptions:function(){var a=this.options,b=[];return b.push("ui-body-"+(null===a.theme?"inherit":a.theme)),a.corners&&b.push("ui-corner-all"),a.mini&&b.push("ui-mini"),a.disabled&&b.push("ui-state-disabled"),a.wrapperClass&&b.push(a.wrapperClass),b},_wrap:function(){return a("")},_autoCorrect:function(){"undefined"==typeof this.element[0].autocorrect||a.support.touchOverflow||(this.element[0].setAttribute("autocorrect","off"),this.element[0].setAttribute("autocomplete","off"))
+},_handleBlur:function(){this.widget().removeClass(a.mobile.focusClass),this.options.preventFocusZoom&&a.mobile.zoom.enable(!0)},_handleFocus:function(){this.options.preventFocusZoom&&a.mobile.zoom.disable(!0),this.widget().addClass(a.mobile.focusClass)},_setOptions:function(a){var c=this.widget();this._super(a),(a.disabled!==b||a.mini!==b||a.corners!==b||a.theme!==b||a.wrapperClass!==b)&&(c.removeClass(this.classes.join(" ")),this.classes=this._classesFromOptions(),c.addClass(this.classes.join(" "))),a.disabled!==b&&this.element.prop("disabled",!!a.disabled)},_destroy:function(){this.options.enhanced||(this.inputNeedsWrap&&this.element.unwrap(),this.element.removeClass("ui-input-text "+this.classes.join(" ")))}})}(a),function(a,d){a.widget("mobile.slider",a.extend({initSelector:"input[type='range'], :jqmData(type='range'), :jqmData(role='slider')",widgetEventPrefix:"slide",options:{theme:null,trackTheme:null,corners:!0,mini:!1,highlight:!1},_create:function(){var e,f,g,h,i,j,k,l,m,n,o=this,p=this.element,q=this.options.trackTheme||a.mobile.getAttribute(p[0],"theme"),r=q?" ui-bar-"+q:" ui-bar-inherit",s=this.options.corners||p.jqmData("corners")?" ui-corner-all":"",t=this.options.mini||p.jqmData("mini")?" ui-mini":"",u=p[0].nodeName.toLowerCase(),v="select"===u,w=p.parent().is(":jqmData(role='rangeslider')"),x=v?"ui-slider-switch":"",y=p.attr("id"),z=a("[for='"+y+"']"),A=z.attr("id")||y+"-label",B=v?0:parseFloat(p.attr("min")),C=v?p.find("option").length-1:parseFloat(p.attr("max")),D=b.parseFloat(p.attr("step")||1),E=c.createElement("a"),F=a(E),G=c.createElement("div"),H=a(G),I=this.options.highlight&&!v?function(){var b=c.createElement("div");return b.className="ui-slider-bg "+a.mobile.activeBtnClass,a(b).prependTo(H)}():!1;if(z.attr("id",A),this.isToggleSwitch=v,E.setAttribute("href","#"),G.setAttribute("role","application"),G.className=[this.isToggleSwitch?"ui-slider ui-slider-track ui-shadow-inset ":"ui-slider-track ui-shadow-inset ",x,r,s,t].join(""),E.className="ui-slider-handle",G.appendChild(E),F.attr({role:"slider","aria-valuemin":B,"aria-valuemax":C,"aria-valuenow":this._value(),"aria-valuetext":this._value(),title:this._value(),"aria-labelledby":A}),a.extend(this,{slider:H,handle:F,control:p,type:u,step:D,max:C,min:B,valuebg:I,isRangeslider:w,dragging:!1,beforeStart:null,userModified:!1,mouseMoved:!1}),v){for(k=p.attr("tabindex"),k&&F.attr("tabindex",k),p.attr("tabindex","-1").focus(function(){a(this).blur(),F.focus()}),f=c.createElement("div"),f.className="ui-slider-inneroffset",g=0,h=G.childNodes.length;h>g;g++)f.appendChild(G.childNodes[g]);for(G.appendChild(f),F.addClass("ui-slider-handle-snapping"),e=p.find("option"),i=0,j=e.length;j>i;i++)l=i?"a":"b",m=i?" "+a.mobile.activeBtnClass:"",n=c.createElement("span"),n.className=["ui-slider-label ui-slider-label-",l,m].join(""),n.setAttribute("role","img"),n.appendChild(c.createTextNode(e[i].innerHTML)),a(n).prependTo(H);o._labels=a(".ui-slider-label",H)}p.addClass(v?"ui-slider-switch":"ui-slider-input"),this._on(p,{change:"_controlChange",keyup:"_controlKeyup",blur:"_controlBlur",vmouseup:"_controlVMouseUp"}),H.bind("vmousedown",a.proxy(this._sliderVMouseDown,this)).bind("vclick",!1),this._on(c,{vmousemove:"_preventDocumentDrag"}),this._on(H.add(c),{vmouseup:"_sliderVMouseUp"}),H.insertAfter(p),v||w||(f=this.options.mini?"":"
",p.add(H).wrapAll(f)),this._on(this.handle,{vmousedown:"_handleVMouseDown",keydown:"_handleKeydown",keyup:"_handleKeyup"}),this.handle.bind("vclick",!1),this._handleFormReset(),this.refresh(d,d,!0)},_setOptions:function(a){a.theme!==d&&this._setTheme(a.theme),a.trackTheme!==d&&this._setTrackTheme(a.trackTheme),a.corners!==d&&this._setCorners(a.corners),a.mini!==d&&this._setMini(a.mini),a.highlight!==d&&this._setHighlight(a.highlight),a.disabled!==d&&this._setDisabled(a.disabled),this._super(a)},_controlChange:function(a){return this._trigger("controlchange",a)===!1?!1:void(this.mouseMoved||this.refresh(this._value(),!0))},_controlKeyup:function(){this.refresh(this._value(),!0,!0)},_controlBlur:function(){this.refresh(this._value(),!0)},_controlVMouseUp:function(){this._checkedRefresh()},_handleVMouseDown:function(){this.handle.focus()},_handleKeydown:function(b){var c=this._value();if(!this.options.disabled){switch(b.keyCode){case a.mobile.keyCode.HOME:case a.mobile.keyCode.END:case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:b.preventDefault(),this._keySliding||(this._keySliding=!0,this.handle.addClass("ui-state-active"))}switch(b.keyCode){case a.mobile.keyCode.HOME:this.refresh(this.min);break;case a.mobile.keyCode.END:this.refresh(this.max);break;case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:this.refresh(c+this.step);break;case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:this.refresh(c-this.step)}}},_handleKeyup:function(){this._keySliding&&(this._keySliding=!1,this.handle.removeClass("ui-state-active"))},_sliderVMouseDown:function(a){return this.options.disabled||1!==a.which&&0!==a.which&&a.which!==d?!1:this._trigger("beforestart",a)===!1?!1:(this.dragging=!0,this.userModified=!1,this.mouseMoved=!1,this.isToggleSwitch&&(this.beforeStart=this.element[0].selectedIndex),this.refresh(a),this._trigger("start"),!1)},_sliderVMouseUp:function(){return this.dragging?(this.dragging=!1,this.isToggleSwitch&&(this.handle.addClass("ui-slider-handle-snapping"),this.refresh(this.mouseMoved?this.userModified?0===this.beforeStart?1:0:this.beforeStart:0===this.beforeStart?1:0)),this.mouseMoved=!1,this._trigger("stop"),!1):void 0},_preventDocumentDrag:function(a){return this._trigger("drag",a)===!1?!1:this.dragging&&!this.options.disabled?(this.mouseMoved=!0,this.isToggleSwitch&&this.handle.removeClass("ui-slider-handle-snapping"),this.refresh(a),this.userModified=this.beforeStart!==this.element[0].selectedIndex,!1):void 0},_checkedRefresh:function(){this.value!==this._value()&&this.refresh(this._value())},_value:function(){return this.isToggleSwitch?this.element[0].selectedIndex:parseFloat(this.element.val())},_reset:function(){this.refresh(d,!1,!0)},refresh:function(b,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z=this,A=a.mobile.getAttribute(this.element[0],"theme"),B=this.options.theme||A,C=B?" ui-btn-"+B:"",D=this.options.trackTheme||A,E=D?" ui-bar-"+D:" ui-bar-inherit",F=this.options.corners?" ui-corner-all":"",G=this.options.mini?" ui-mini":"";if(z.slider[0].className=[this.isToggleSwitch?"ui-slider ui-slider-switch ui-slider-track ui-shadow-inset":"ui-slider-track ui-shadow-inset",E,F,G].join(""),(this.options.disabled||this.element.prop("disabled"))&&this.disable(),this.value=this._value(),this.options.highlight&&!this.isToggleSwitch&&0===this.slider.find(".ui-slider-bg").length&&(this.valuebg=function(){var b=c.createElement("div");return b.className="ui-slider-bg "+a.mobile.activeBtnClass,a(b).prependTo(z.slider)}()),this.handle.addClass("ui-btn"+C+" ui-shadow"),l=this.element,m=!this.isToggleSwitch,n=m?[]:l.find("option"),o=m?parseFloat(l.attr("min")):0,p=m?parseFloat(l.attr("max")):n.length-1,q=m&&parseFloat(l.attr("step"))>0?parseFloat(l.attr("step")):1,"object"==typeof b){if(h=b,i=8,f=this.slider.offset().left,g=this.slider.width(),j=g/((p-o)/q),!this.dragging||h.pageX
f+g+i)return;k=j>1?(h.pageX-f)/g*100:Math.round((h.pageX-f)/g*100)}else null==b&&(b=m?parseFloat(l.val()||0):l[0].selectedIndex),k=(parseFloat(b)-o)/(p-o)*100;if(!isNaN(k)&&(r=k/100*(p-o)+o,s=(r-o)%q,t=r-s,2*Math.abs(s)>=q&&(t+=s>0?q:-q),u=100/((p-o)/q),r=parseFloat(t.toFixed(5)),"undefined"==typeof j&&(j=g/((p-o)/q)),j>1&&m&&(k=(r-o)*u*(1/q)),0>k&&(k=0),k>100&&(k=100),o>r&&(r=o),r>p&&(r=p),this.handle.css("left",k+"%"),this.handle[0].setAttribute("aria-valuenow",m?r:n.eq(r).attr("value")),this.handle[0].setAttribute("aria-valuetext",m?r:n.eq(r).getEncodedText()),this.handle[0].setAttribute("title",m?r:n.eq(r).getEncodedText()),this.valuebg&&this.valuebg.css("width",k+"%"),this._labels&&(v=this.handle.width()/this.slider.width()*100,w=k&&v+(100-v)*k/100,x=100===k?0:Math.min(v+100-w,100),this._labels.each(function(){var b=a(this).hasClass("ui-slider-label-a");a(this).width((b?w:x)+"%")})),!e)){if(y=!1,m?(y=l.val()!==r,l.val(r)):(y=l[0].selectedIndex!==r,l[0].selectedIndex=r),this._trigger("beforechange",b)===!1)return!1;!d&&y&&l.trigger("change")}},_setHighlight:function(a){a=!!a,a?(this.options.highlight=!!a,this.refresh()):this.valuebg&&(this.valuebg.remove(),this.valuebg=!1)},_setTheme:function(a){this.handle.removeClass("ui-btn-"+this.options.theme).addClass("ui-btn-"+a);var b=this.options.theme?this.options.theme:"inherit",c=a?a:"inherit";this.control.removeClass("ui-body-"+b).addClass("ui-body-"+c)},_setTrackTheme:function(a){var b=this.options.trackTheme?this.options.trackTheme:"inherit",c=a?a:"inherit";this.slider.removeClass("ui-body-"+b).addClass("ui-body-"+c)},_setMini:function(a){a=!!a,this.isToggleSwitch||this.isRangeslider||(this.slider.parent().toggleClass("ui-mini",a),this.element.toggleClass("ui-mini",a)),this.slider.toggleClass("ui-mini",a)},_setCorners:function(a){this.slider.toggleClass("ui-corner-all",a),this.isToggleSwitch||this.control.toggleClass("ui-corner-all",a)},_setDisabled:function(a){a=!!a,this.element.prop("disabled",a),this.slider.toggleClass("ui-state-disabled",a).attr("aria-disabled",a)}},a.mobile.behaviors.formReset))}(a),function(a){function b(){return c||(c=a("",{"class":"ui-slider-popup ui-shadow ui-corner-all"})),c.clone()}var c;a.widget("mobile.slider",a.mobile.slider,{options:{popupEnabled:!1,showValue:!1},_create:function(){this._super(),a.extend(this,{_currentValue:null,_popup:null,_popupVisible:!1}),this._setOption("popupEnabled",this.options.popupEnabled),this._on(this.handle,{vmousedown:"_showPopup"}),this._on(this.slider.add(this.document),{vmouseup:"_hidePopup"}),this._refresh()},_positionPopup:function(){var a=this.handle.offset();this._popup.offset({left:a.left+(this.handle.width()-this._popup.width())/2,top:a.top-this._popup.outerHeight()-5})},_setOption:function(a,c){this._super(a,c),"showValue"===a?this.handle.html(c&&!this.options.mini?this._value():""):"popupEnabled"===a&&c&&!this._popup&&(this._popup=b().addClass("ui-body-"+(this.options.theme||"a")).hide().insertBefore(this.element))},refresh:function(){this._super.apply(this,arguments),this._refresh()},_refresh:function(){var a,b=this.options;b.popupEnabled&&this.handle.removeAttr("title"),a=this._value(),a!==this._currentValue&&(this._currentValue=a,b.popupEnabled&&this._popup&&(this._positionPopup(),this._popup.html(a)),b.showValue&&!this.options.mini&&this.handle.html(a))},_showPopup:function(){this.options.popupEnabled&&!this._popupVisible&&(this.handle.html(""),this._popup.show(),this._positionPopup(),this._popupVisible=!0)},_hidePopup:function(){var a=this.options;a.popupEnabled&&this._popupVisible&&(a.showValue&&!a.mini&&this.handle.html(this._value()),this._popup.hide(),this._popupVisible=!1)}})}(a),function(a,b){a.widget("mobile.flipswitch",a.extend({options:{onText:"On",offText:"Off",theme:null,enhanced:!1,wrapperClass:null,corners:!0,mini:!1},_create:function(){this.options.enhanced?a.extend(this,{flipswitch:this.element.parent(),on:this.element.find(".ui-flipswitch-on").eq(0),off:this.element.find(".ui-flipswitch-off").eq(0),type:this.element.get(0).tagName}):this._enhance(),this._handleFormReset(),this._originalTabIndex=this.element.attr("tabindex"),null!=this._originalTabIndex&&this.on.attr("tabindex",this._originalTabIndex),this.element.attr("tabindex","-1"),this._on({focus:"_handleInputFocus"}),this.element.is(":disabled")&&this._setOptions({disabled:!0}),this._on(this.flipswitch,{click:"_toggle",swipeleft:"_left",swiperight:"_right"}),this._on(this.on,{keydown:"_keydown"}),this._on({change:"refresh"})},_handleInputFocus:function(){this.on.focus()},widget:function(){return this.flipswitch},_left:function(){this.flipswitch.removeClass("ui-flipswitch-active"),"SELECT"===this.type?this.element.get(0).selectedIndex=0:this.element.prop("checked",!1),this.element.trigger("change")},_right:function(){this.flipswitch.addClass("ui-flipswitch-active"),"SELECT"===this.type?this.element.get(0).selectedIndex=1:this.element.prop("checked",!0),this.element.trigger("change")},_enhance:function(){var b=a(""),c=this.options,d=this.element,e=c.theme?c.theme:"inherit",f=a("
",{href:"#"}),g=a("
"),h=d.get(0).tagName,i="INPUT"===h?c.onText:d.find("option").eq(1).text(),j="INPUT"===h?c.offText:d.find("option").eq(0).text();f.addClass("ui-flipswitch-on ui-btn ui-shadow ui-btn-inherit").text(i),g.addClass("ui-flipswitch-off").text(j),b.addClass("ui-flipswitch ui-shadow-inset ui-bar-"+e+" "+(c.wrapperClass?c.wrapperClass:"")+" "+(d.is(":checked")||d.find("option").eq(1).is(":selected")?"ui-flipswitch-active":"")+(d.is(":disabled")?" ui-state-disabled":"")+(c.corners?" ui-corner-all":"")+(c.mini?" ui-mini":"")).append(f,g),d.addClass("ui-flipswitch-input").after(b).appendTo(b),a.extend(this,{flipswitch:b,on:f,off:g,type:h})},_reset:function(){this.refresh()},refresh:function(){var a,b=this.flipswitch.hasClass("ui-flipswitch-active")?"_right":"_left";a="SELECT"===this.type?this.element.get(0).selectedIndex>0?"_right":"_left":this.element.prop("checked")?"_right":"_left",a!==b&&this[a]()},_toggle:function(){var a=this.flipswitch.hasClass("ui-flipswitch-active")?"_left":"_right";this[a]()},_keydown:function(b){b.which===a.mobile.keyCode.LEFT?this._left():b.which===a.mobile.keyCode.RIGHT?this._right():b.which===a.mobile.keyCode.SPACE&&(this._toggle(),b.preventDefault())},_setOptions:function(a){if(a.theme!==b){var c=a.theme?a.theme:"inherit",d=a.theme?a.theme:"inherit";this.widget().removeClass("ui-bar-"+c).addClass("ui-bar-"+d)}a.onText!==b&&this.on.text(a.onText),a.offText!==b&&this.off.text(a.offText),a.disabled!==b&&this.widget().toggleClass("ui-state-disabled",a.disabled),a.mini!==b&&this.widget().toggleClass("ui-mini",a.mini),a.corners!==b&&this.widget().toggleClass("ui-corner-all",a.corners),this._super(a)},_destroy:function(){this.options.enhanced||(null!=this._originalTabIndex?this.element.attr("tabindex",this._originalTabIndex):this.element.removeAttr("tabindex"),this.on.remove(),this.off.remove(),this.element.unwrap(),this.flipswitch.remove(),this.removeClass("ui-flipswitch-input"))}},a.mobile.behaviors.formReset))}(a),function(a,b){a.widget("mobile.rangeslider",a.extend({options:{theme:null,trackTheme:null,corners:!0,mini:!1,highlight:!0},_create:function(){var b=this.element,c=this.options.mini?"ui-rangeslider ui-mini":"ui-rangeslider",d=b.find("input").first(),e=b.find("input").last(),f=b.find("label").first(),g=a.data(d.get(0),"mobile-slider")||a.data(d.slider().get(0),"mobile-slider"),h=a.data(e.get(0),"mobile-slider")||a.data(e.slider().get(0),"mobile-slider"),i=g.slider,j=h.slider,k=g.handle,l=a("
").appendTo(b);d.addClass("ui-rangeslider-first"),e.addClass("ui-rangeslider-last"),b.addClass(c),i.appendTo(l),j.appendTo(l),f.insertBefore(b),k.prependTo(j),a.extend(this,{_inputFirst:d,_inputLast:e,_sliderFirst:i,_sliderLast:j,_label:f,_targetVal:null,_sliderTarget:!1,_sliders:l,_proxy:!1}),this.refresh(),this._on(this.element.find("input.ui-slider-input"),{slidebeforestart:"_slidebeforestart",slidestop:"_slidestop",slidedrag:"_slidedrag",slidebeforechange:"_change",blur:"_change",keyup:"_change"}),this._on({mousedown:"_change"}),this._on(this.element.closest("form"),{reset:"_handleReset"}),this._on(k,{vmousedown:"_dragFirstHandle"})},_handleReset:function(){var a=this;setTimeout(function(){a._updateHighlight()},0)},_dragFirstHandle:function(b){return a.data(this._inputFirst.get(0),"mobile-slider").dragging=!0,a.data(this._inputFirst.get(0),"mobile-slider").refresh(b),!1},_slidedrag:function(b){var c=a(b.target).is(this._inputFirst),d=c?this._inputLast:this._inputFirst;return this._sliderTarget=!1,"first"===this._proxy&&c||"last"===this._proxy&&!c?(a.data(d.get(0),"mobile-slider").dragging=!0,a.data(d.get(0),"mobile-slider").refresh(b),!1):void 0},_slidestop:function(b){var c=a(b.target).is(this._inputFirst);this._proxy=!1,this.element.find("input").trigger("vmouseup"),this._sliderFirst.css("z-index",c?1:"")},_slidebeforestart:function(b){this._sliderTarget=!1,a(b.originalEvent.target).hasClass("ui-slider-track")&&(this._sliderTarget=!0,this._targetVal=a(b.target).val())},_setOptions:function(a){a.theme!==b&&this._setTheme(a.theme),a.trackTheme!==b&&this._setTrackTheme(a.trackTheme),a.mini!==b&&this._setMini(a.mini),a.highlight!==b&&this._setHighlight(a.highlight),this._super(a),this.refresh()},refresh:function(){var a=this.element,b=this.options;(this._inputFirst.is(":disabled")||this._inputLast.is(":disabled"))&&(this.options.disabled=!0),a.find("input").slider({theme:b.theme,trackTheme:b.trackTheme,disabled:b.disabled,corners:b.corners,mini:b.mini,highlight:b.highlight}).slider("refresh"),this._updateHighlight()},_change:function(b){if("keyup"===b.type)return this._updateHighlight(),!1;var c=this,d=parseFloat(this._inputFirst.val(),10),e=parseFloat(this._inputLast.val(),10),f=a(b.target).hasClass("ui-rangeslider-first"),g=f?this._inputFirst:this._inputLast,h=f?this._inputLast:this._inputFirst;if(this._inputFirst.val()>this._inputLast.val()&&"mousedown"===b.type&&!a(b.target).hasClass("ui-slider-handle"))g.blur();else if("mousedown"===b.type)return;return d>e&&!this._sliderTarget?(g.val(f?e:d).slider("refresh"),this._trigger("normalize")):d>e&&(g.val(this._targetVal).slider("refresh"),setTimeout(function(){h.val(f?d:e).slider("refresh"),a.data(h.get(0),"mobile-slider").handle.focus(),c._sliderFirst.css("z-index",f?"":1),c._trigger("normalize")},0),this._proxy=f?"first":"last"),d===e?(a.data(g.get(0),"mobile-slider").handle.css("z-index",1),a.data(h.get(0),"mobile-slider").handle.css("z-index",0)):(a.data(h.get(0),"mobile-slider").handle.css("z-index",""),a.data(g.get(0),"mobile-slider").handle.css("z-index","")),this._updateHighlight(),d>=e?!1:void 0},_updateHighlight:function(){var b=parseInt(a.data(this._inputFirst.get(0),"mobile-slider").handle.get(0).style.left,10),c=parseInt(a.data(this._inputLast.get(0),"mobile-slider").handle.get(0).style.left,10),d=c-b;this.element.find(".ui-slider-bg").css({"margin-left":b+"%",width:d+"%"})},_setTheme:function(a){this._inputFirst.slider("option","theme",a),this._inputLast.slider("option","theme",a)},_setTrackTheme:function(a){this._inputFirst.slider("option","trackTheme",a),this._inputLast.slider("option","trackTheme",a)},_setMini:function(a){this._inputFirst.slider("option","mini",a),this._inputLast.slider("option","mini",a),this.element.toggleClass("ui-mini",!!a)},_setHighlight:function(a){this._inputFirst.slider("option","highlight",a),this._inputLast.slider("option","highlight",a)},_destroy:function(){this._label.prependTo(this.element),this.element.removeClass("ui-rangeslider ui-mini"),this._inputFirst.after(this._sliderFirst),this._inputLast.after(this._sliderLast),this._sliders.remove(),this.element.find("input").removeClass("ui-rangeslider-first ui-rangeslider-last").slider("destroy")}},a.mobile.behaviors.formReset))}(a),function(a,b){a.widget("mobile.textinput",a.mobile.textinput,{options:{clearBtn:!1,clearBtnText:"Clear text"},_create:function(){this._super(),(this.options.clearBtn||this.isSearch)&&this._addClearBtn()},clearButton:function(){return a("
"+this.options.clearBtnText+"")},_clearBtnClick:function(a){this.element.val("").focus().trigger("change"),this._clearBtn.addClass("ui-input-clear-hidden"),a.preventDefault()},_addClearBtn:function(){this.options.enhanced||this._enhanceClear(),a.extend(this,{_clearBtn:this.widget().find("a.ui-input-clear")}),this._bindClearEvents(),this._toggleClear()},_enhanceClear:function(){this.clearButton().appendTo(this.widget()),this.widget().addClass("ui-input-has-clear")},_bindClearEvents:function(){this._on(this._clearBtn,{click:"_clearBtnClick"}),this._on({keyup:"_toggleClear",change:"_toggleClear",input:"_toggleClear",focus:"_toggleClear",blur:"_toggleClear",cut:"_toggleClear",paste:"_toggleClear"})},_unbindClear:function(){this._off(this._clearBtn,"click"),this._off(this.element,"keyup change input focus blur cut paste")},_setOptions:function(a){this._super(a),a.clearBtn===b||this.element.is("textarea, :jqmData(type='range')")||(a.clearBtn?this._addClearBtn():this._destroyClear()),a.clearBtnText!==b&&this._clearBtn!==b&&this._clearBtn.text(a.clearBtnText).attr("title",a.clearBtnText)},_toggleClear:function(){this._delay("_toggleClearClass",0)},_toggleClearClass:function(){this._clearBtn.toggleClass("ui-input-clear-hidden",!this.element.val())},_destroyClear:function(){this.widget().removeClass("ui-input-has-clear"),this._unbindClear(),this._clearBtn.remove()},_destroy:function(){this._super(),this._destroyClear()}})}(a),function(a,b){a.widget("mobile.textinput",a.mobile.textinput,{options:{autogrow:!0,keyupTimeoutBuffer:100},_create:function(){this._super(),this.options.autogrow&&this.isTextarea&&this._autogrow()},_autogrow:function(){this.element.addClass("ui-textinput-autogrow"),this._on({keyup:"_timeout",change:"_timeout",input:"_timeout",paste:"_timeout"}),this._on(!0,this.document,{pageshow:"_handleShow",popupbeforeposition:"_handleShow",updatelayout:"_handleShow",panelopen:"_handleShow"})},_handleShow:function(b){a.contains(b.target,this.element[0])&&this.element.is(":visible")&&("popupbeforeposition"!==b.type&&this.element.addClass("ui-textinput-autogrow-resize").animationComplete(a.proxy(function(){this.element.removeClass("ui-textinput-autogrow-resize")},this),"transition"),this._timeout())},_unbindAutogrow:function(){this.element.removeClass("ui-textinput-autogrow"),this._off(this.element,"keyup change input paste"),this._off(this.document,"pageshow popupbeforeposition updatelayout panelopen")},keyupTimeout:null,_prepareHeightUpdate:function(a){this.keyupTimeout&&clearTimeout(this.keyupTimeout),a===b?this._updateHeight():this.keyupTimeout=this._delay("_updateHeight",a)},_timeout:function(){this._prepareHeightUpdate(this.options.keyupTimeoutBuffer)},_updateHeight:function(){var a,b,c,d,e,f,g,h,i,j=this.window.scrollTop();this.keyupTimeout=0,"onpage"in this.element[0]||this.element.css({height:0,"min-height":0,"max-height":0}),d=this.element[0].scrollHeight,e=this.element[0].clientHeight,f=parseFloat(this.element.css("border-top-width")),g=parseFloat(this.element.css("border-bottom-width")),h=f+g,i=d+h+15,0===e&&(a=parseFloat(this.element.css("padding-top")),b=parseFloat(this.element.css("padding-bottom")),c=a+b,i+=c),this.element.css({height:i,"min-height":"","max-height":""}),this.window.scrollTop(j)},refresh:function(){this.options.autogrow&&this.isTextarea&&this._updateHeight()},_setOptions:function(a){this._super(a),a.autogrow!==b&&this.isTextarea&&(a.autogrow?this._autogrow():this._unbindAutogrow())}})}(a),function(a){a.widget("mobile.selectmenu",a.extend({initSelector:"select:not( :jqmData(role='slider')):not( :jqmData(role='flipswitch') )",options:{theme:null,icon:"carat-d",iconpos:"right",inline:!1,corners:!0,shadow:!0,iconshadow:!1,overlayTheme:null,dividerTheme:null,hidePlaceholderMenuItems:!0,closeText:"Close",nativeMenu:!0,preventFocusZoom:/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1,mini:!1},_button:function(){return a("
")},_setDisabled:function(a){return this.element.attr("disabled",a),this.button.attr("aria-disabled",a),this._setOption("disabled",a)},_focusButton:function(){var a=this;setTimeout(function(){a.button.focus()},40)},_selectOptions:function(){return this.select.find("option")},_preExtension:function(){var b=this.options.inline||this.element.jqmData("inline"),c=this.options.mini||this.element.jqmData("mini"),d="";~this.element[0].className.indexOf("ui-btn-left")&&(d=" ui-btn-left"),~this.element[0].className.indexOf("ui-btn-right")&&(d=" ui-btn-right"),b&&(d+=" ui-btn-inline"),c&&(d+=" ui-mini"),this.select=this.element.removeClass("ui-btn-left ui-btn-right").wrap("
"),this.selectId=this.select.attr("id")||"select-"+this.uuid,this.buttonId=this.selectId+"-button",this.label=a("label[for='"+this.selectId+"']"),this.isMultiple=this.select[0].multiple},_destroy:function(){var a=this.element.parents(".ui-select");a.length>0&&(a.is(".ui-btn-left, .ui-btn-right")&&this.element.addClass(a.hasClass("ui-btn-left")?"ui-btn-left":"ui-btn-right"),this.element.insertAfter(a),a.remove())},_create:function(){this._preExtension(),this.button=this._button();var c=this,d=this.options,e=d.icon?d.iconpos||this.select.jqmData("iconpos"):!1,f=this.button.insertBefore(this.select).attr("id",this.buttonId).addClass("ui-btn"+(d.icon?" ui-icon-"+d.icon+" ui-btn-icon-"+e+(d.iconshadow?" ui-shadow-icon":""):"")+(d.theme?" ui-btn-"+d.theme:"")+(d.corners?" ui-corner-all":"")+(d.shadow?" ui-shadow":""));this.setButtonText(),d.nativeMenu&&b.opera&&b.opera.version&&f.addClass("ui-select-nativeonly"),this.isMultiple&&(this.buttonCount=a("
").addClass("ui-li-count ui-body-inherit").hide().appendTo(f.addClass("ui-li-has-count"))),(d.disabled||this.element.attr("disabled"))&&this.disable(),this.select.change(function(){c.refresh(),d.nativeMenu&&this.blur()}),this._handleFormReset(),this._on(this.button,{keydown:"_handleKeydown"}),this.build()},build:function(){var b=this;this.select.appendTo(b.button).bind("vmousedown",function(){b.button.addClass(a.mobile.activeBtnClass)}).bind("focus",function(){b.button.addClass(a.mobile.focusClass)}).bind("blur",function(){b.button.removeClass(a.mobile.focusClass)}).bind("focus vmouseover",function(){b.button.trigger("vmouseover")}).bind("vmousemove",function(){b.button.removeClass(a.mobile.activeBtnClass)}).bind("change blur vmouseout",function(){b.button.trigger("vmouseout").removeClass(a.mobile.activeBtnClass)}),b.button.bind("vmousedown",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.label.bind("click focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.select.bind("focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.button.bind("mouseup",function(){b.options.preventFocusZoom&&setTimeout(function(){a.mobile.zoom.enable(!0)},0)}),b.select.bind("blur",function(){b.options.preventFocusZoom&&a.mobile.zoom.enable(!0)})},selected:function(){return this._selectOptions().filter(":selected")},selectedIndices:function(){var a=this;return this.selected().map(function(){return a._selectOptions().index(this)}).get()},setButtonText:function(){var b=this,d=this.selected(),e=this.placeholder,f=a(c.createElement("span"));this.button.children("span").not(".ui-li-count").remove().end().end().prepend(function(){return e=d.length?d.map(function(){return a(this).text()}).get().join(", "):b.placeholder,e?f.text(e):f.html(" "),f.addClass(b.select.attr("class")).addClass(d.attr("class")).removeClass("ui-screen-hidden")}())},setButtonCount:function(){var a=this.selected();this.isMultiple&&this.buttonCount[a.length>1?"show":"hide"]().text(a.length)},_handleKeydown:function(){this._delay("_refreshButton")},_reset:function(){this.refresh()},_refreshButton:function(){this.setButtonText(),this.setButtonCount()},refresh:function(){this._refreshButton()},open:a.noop,close:a.noop,disable:function(){this._setDisabled(!0),this.button.addClass("ui-state-disabled")},enable:function(){this._setDisabled(!1),this.button.removeClass("ui-state-disabled")}},a.mobile.behaviors.formReset))}(a),function(a){a.mobile.links=function(b){a(b).find("a").jqmEnhanceable().filter(":jqmData(rel='popup')[href][href!='']").each(function(){var a=this,b=a.getAttribute("href").substring(1);b&&(a.setAttribute("aria-haspopup",!0),a.setAttribute("aria-owns",b),a.setAttribute("aria-expanded",!1))}).end().not(".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')").addClass("ui-link")}}(a),function(a,c){function d(a,b,c,d){var e=d;return e=b>a?c+(a-b)/2:Math.min(Math.max(c,d-b/2),c+a-b)}function e(a){return{x:a.scrollLeft(),y:a.scrollTop(),cx:a[0].innerWidth||a.width(),cy:a[0].innerHeight||a.height()}}a.widget("mobile.popup",{options:{wrapperClass:null,theme:null,overlayTheme:null,shadow:!0,corners:!0,transition:"none",positionTo:"origin",tolerance:null,closeLinkSelector:"a:jqmData(rel='back')",closeLinkEvents:"click.popup",navigateEvents:"navigate.popup",closeEvents:"navigate.popup pagebeforechange.popup",dismissible:!0,enhanced:!1,history:!a.mobile.browser.oldIE},_handleDocumentVmousedown:function(b){this._isOpen&&a.contains(this._ui.container[0],b.target)&&this._ignoreResizeEvents()},_create:function(){var b=this.element,c=b.attr("id"),d=this.options;d.history=d.history&&a.mobile.ajaxEnabled&&a.mobile.hashListeningEnabled,this._on(this.document,{vmousedown:"_handleDocumentVmousedown"}),a.extend(this,{_scrollTop:0,_page:b.closest(".ui-page"),_ui:null,_fallbackTransition:"",_currentTransition:!1,_prerequisites:null,_isOpen:!1,_tolerance:null,_resizeData:null,_ignoreResizeTo:0,_orientationchangeInProgress:!1}),0===this._page.length&&(this._page=a("body")),d.enhanced?this._ui={container:b.parent(),screen:b.parent().prev(),placeholder:a(this.document[0].getElementById(c+"-placeholder"))}:(this._ui=this._enhance(b,c),this._applyTransition(d.transition)),this._setTolerance(d.tolerance)._ui.focusElement=this._ui.container,this._on(this._ui.screen,{vclick:"_eatEventAndClose"}),this._on(this.window,{orientationchange:a.proxy(this,"_handleWindowOrientationchange"),resize:a.proxy(this,"_handleWindowResize"),keyup:a.proxy(this,"_handleWindowKeyUp")}),this._on(this.document,{focusin:"_handleDocumentFocusIn"})},_enhance:function(b,c){var d=this.options,e=d.wrapperClass,f={screen:a(""),placeholder:a(""),container:a("")},g=this.document[0].createDocumentFragment();return g.appendChild(f.screen[0]),g.appendChild(f.container[0]),c&&(f.screen.attr("id",c+"-screen"),f.container.attr("id",c+"-popup"),f.placeholder.attr("id",c+"-placeholder").html("")),this._page[0].appendChild(g),f.placeholder.insertAfter(b),b.detach().addClass("ui-popup "+this._themeClassFromOption("ui-body-",d.theme)+" "+(d.shadow?"ui-overlay-shadow ":"")+(d.corners?"ui-corner-all ":"")).appendTo(f.container),f},_eatEventAndClose:function(a){return a.preventDefault(),a.stopImmediatePropagation(),this.options.dismissible&&this.close(),!1},_resizeScreen:function(){var a=this._ui.screen,b=this._ui.container.outerHeight(!0),c=a.removeAttr("style").height(),d=this.document.height()-1;d>c?a.height(d):b>c&&a.height(b)},_handleWindowKeyUp:function(b){return this._isOpen&&b.keyCode===a.mobile.keyCode.ESCAPE?this._eatEventAndClose(b):void 0},_expectResizeEvent:function(){var a=e(this.window);if(this._resizeData){if(a.x===this._resizeData.windowCoordinates.x&&a.y===this._resizeData.windowCoordinates.y&&a.cx===this._resizeData.windowCoordinates.cx&&a.cy===this._resizeData.windowCoordinates.cy)return!1;clearTimeout(this._resizeData.timeoutId)}return this._resizeData={timeoutId:this._delay("_resizeTimeout",200),windowCoordinates:a},!0},_resizeTimeout:function(){this._isOpen?this._expectResizeEvent()||(this._ui.container.hasClass("ui-popup-hidden")&&(this._ui.container.removeClass("ui-popup-hidden ui-popup-truncate"),this.reposition({positionTo:"window"}),this._ignoreResizeEvents()),this._resizeScreen(),this._resizeData=null,this._orientationchangeInProgress=!1):(this._resizeData=null,this._orientationchangeInProgress=!1)},_stopIgnoringResizeEvents:function(){this._ignoreResizeTo=0
+},_ignoreResizeEvents:function(){this._ignoreResizeTo&&clearTimeout(this._ignoreResizeTo),this._ignoreResizeTo=this._delay("_stopIgnoringResizeEvents",1e3)},_handleWindowResize:function(){this._isOpen&&0===this._ignoreResizeTo&&(!this._expectResizeEvent()&&!this._orientationchangeInProgress||this._ui.container.hasClass("ui-popup-hidden")||this._ui.container.addClass("ui-popup-hidden ui-popup-truncate").removeAttr("style"))},_handleWindowOrientationchange:function(){!this._orientationchangeInProgress&&this._isOpen&&0===this._ignoreResizeTo&&(this._expectResizeEvent(),this._orientationchangeInProgress=!0)},_handleDocumentFocusIn:function(b){var c,d=b.target,e=this._ui;if(this._isOpen){if(d!==e.container[0]){if(c=a(d),0===c.parents().filter(e.container[0]).length)return a(this.document[0].activeElement).one("focus",function(){c.blur()}),e.focusElement.focus(),b.preventDefault(),b.stopImmediatePropagation(),!1;e.focusElement[0]===e.container[0]&&(e.focusElement=c)}this._ignoreResizeEvents()}},_themeClassFromOption:function(a,b){return b?"none"===b?"":a+b:a+"inherit"},_applyTransition:function(b){return b&&(this._ui.container.removeClass(this._fallbackTransition),"none"!==b&&(this._fallbackTransition=a.mobile._maybeDegradeTransition(b),"none"===this._fallbackTransition&&(this._fallbackTransition=""),this._ui.container.addClass(this._fallbackTransition))),this},_setOptions:function(a){var b=this.options,d=this.element,e=this._ui.screen;return a.wrapperClass!==c&&this._ui.container.removeClass(b.wrapperClass).addClass(a.wrapperClass),a.theme!==c&&d.removeClass(this._themeClassFromOption("ui-body-",b.theme)).addClass(this._themeClassFromOption("ui-body-",a.theme)),a.overlayTheme!==c&&(e.removeClass(this._themeClassFromOption("ui-overlay-",b.overlayTheme)).addClass(this._themeClassFromOption("ui-overlay-",a.overlayTheme)),this._isOpen&&e.addClass("in")),a.shadow!==c&&d.toggleClass("ui-overlay-shadow",a.shadow),a.corners!==c&&d.toggleClass("ui-corner-all",a.corners),a.transition!==c&&(this._currentTransition||this._applyTransition(a.transition)),a.tolerance!==c&&this._setTolerance(a.tolerance),a.disabled!==c&&a.disabled&&this.close(),this._super(a)},_setTolerance:function(b){var d,e={t:30,r:15,b:30,l:15};if(b!==c)switch(d=String(b).split(","),a.each(d,function(a,b){d[a]=parseInt(b,10)}),d.length){case 1:isNaN(d[0])||(e.t=e.r=e.b=e.l=d[0]);break;case 2:isNaN(d[0])||(e.t=e.b=d[0]),isNaN(d[1])||(e.l=e.r=d[1]);break;case 4:isNaN(d[0])||(e.t=d[0]),isNaN(d[1])||(e.r=d[1]),isNaN(d[2])||(e.b=d[2]),isNaN(d[3])||(e.l=d[3])}return this._tolerance=e,this},_clampPopupWidth:function(a){var b,c=e(this.window),d={x:this._tolerance.l,y:c.y+this._tolerance.t,cx:c.cx-this._tolerance.l-this._tolerance.r,cy:c.cy-this._tolerance.t-this._tolerance.b};return a||this._ui.container.css("max-width",d.cx),b={cx:this._ui.container.outerWidth(!0),cy:this._ui.container.outerHeight(!0)},{rc:d,menuSize:b}},_calculateFinalLocation:function(a,b){var c,e=b.rc,f=b.menuSize;return c={left:d(e.cx,f.cx,e.x,a.x),top:d(e.cy,f.cy,e.y,a.y)},c.top=Math.max(0,c.top),c.top-=Math.min(c.top,Math.max(0,c.top+f.cy-this.document.height())),c},_placementCoords:function(a){return this._calculateFinalLocation(a,this._clampPopupWidth())},_createPrerequisites:function(b,c,d){var e,f=this;e={screen:a.Deferred(),container:a.Deferred()},e.screen.then(function(){e===f._prerequisites&&b()}),e.container.then(function(){e===f._prerequisites&&c()}),a.when(e.screen,e.container).done(function(){e===f._prerequisites&&(f._prerequisites=null,d())}),f._prerequisites=e},_animate:function(b){return this._ui.screen.removeClass(b.classToRemove).addClass(b.screenClassToAdd),b.prerequisites.screen.resolve(),b.transition&&"none"!==b.transition&&(b.applyTransition&&this._applyTransition(b.transition),this._fallbackTransition)?void this._ui.container.addClass(b.containerClassToAdd).removeClass(b.classToRemove).animationComplete(a.proxy(b.prerequisites.container,"resolve")):(this._ui.container.removeClass(b.classToRemove),void b.prerequisites.container.resolve())},_desiredCoords:function(b){var c,d=null,f=e(this.window),g=b.x,h=b.y,i=b.positionTo;if(i&&"origin"!==i)if("window"===i)g=f.cx/2+f.x,h=f.cy/2+f.y;else{try{d=a(i)}catch(j){d=null}d&&(d.filter(":visible"),0===d.length&&(d=null))}return d&&(c=d.offset(),g=c.left+d.outerWidth()/2,h=c.top+d.outerHeight()/2),("number"!==a.type(g)||isNaN(g))&&(g=f.cx/2+f.x),("number"!==a.type(h)||isNaN(h))&&(h=f.cy/2+f.y),{x:g,y:h}},_reposition:function(a){a={x:a.x,y:a.y,positionTo:a.positionTo},this._trigger("beforeposition",c,a),this._ui.container.offset(this._placementCoords(this._desiredCoords(a)))},reposition:function(a){this._isOpen&&this._reposition(a)},_openPrerequisitesComplete:function(){var a=this.element.attr("id");this._ui.container.addClass("ui-popup-active"),this._isOpen=!0,this._resizeScreen(),this._ui.container.attr("tabindex","0").focus(),this._ignoreResizeEvents(),a&&this.document.find("[aria-haspopup='true'][aria-owns='"+a+"']").attr("aria-expanded",!0),this._trigger("afteropen")},_open:function(b){var c=a.extend({},this.options,b),d=function(){var a=navigator.userAgent,b=a.match(/AppleWebKit\/([0-9\.]+)/),c=!!b&&b[1],d=a.match(/Android (\d+(?:\.\d+))/),e=!!d&&d[1],f=a.indexOf("Chrome")>-1;return null!==d&&"4.0"===e&&c&&c>534.13&&!f?!0:!1}();this._createPrerequisites(a.noop,a.noop,a.proxy(this,"_openPrerequisitesComplete")),this._currentTransition=c.transition,this._applyTransition(c.transition),this._ui.screen.removeClass("ui-screen-hidden"),this._ui.container.removeClass("ui-popup-truncate"),this._reposition(c),this._ui.container.removeClass("ui-popup-hidden"),this.options.overlayTheme&&d&&this.element.closest(".ui-page").addClass("ui-popup-open"),this._animate({additionalCondition:!0,transition:c.transition,classToRemove:"",screenClassToAdd:"in",containerClassToAdd:"in",applyTransition:!1,prerequisites:this._prerequisites})},_closePrerequisiteScreen:function(){this._ui.screen.removeClass("out").addClass("ui-screen-hidden")},_closePrerequisiteContainer:function(){this._ui.container.removeClass("reverse out").addClass("ui-popup-hidden ui-popup-truncate").removeAttr("style")},_closePrerequisitesDone:function(){var b=this._ui.container,d=this.element.attr("id");b.removeAttr("tabindex"),a.mobile.popup.active=c,a(":focus",b[0]).add(b[0]).blur(),d&&this.document.find("[aria-haspopup='true'][aria-owns='"+d+"']").attr("aria-expanded",!1),this._trigger("afterclose")},_close:function(b){this._ui.container.removeClass("ui-popup-active"),this._page.removeClass("ui-popup-open"),this._isOpen=!1,this._createPrerequisites(a.proxy(this,"_closePrerequisiteScreen"),a.proxy(this,"_closePrerequisiteContainer"),a.proxy(this,"_closePrerequisitesDone")),this._animate({additionalCondition:this._ui.screen.hasClass("in"),transition:b?"none":this._currentTransition,classToRemove:"in",screenClassToAdd:"out",containerClassToAdd:"reverse out",applyTransition:!0,prerequisites:this._prerequisites})},_unenhance:function(){this.options.enhanced||(this._setOptions({theme:a.mobile.popup.prototype.options.theme}),this.element.detach().insertAfter(this._ui.placeholder).removeClass("ui-popup ui-overlay-shadow ui-corner-all ui-body-inherit"),this._ui.screen.remove(),this._ui.container.remove(),this._ui.placeholder.remove())},_destroy:function(){return a.mobile.popup.active===this?(this.element.one("popupafterclose",a.proxy(this,"_unenhance")),this.close()):this._unenhance(),this},_closePopup:function(c,d){var e,f,g=this.options,h=!1;c&&c.isDefaultPrevented()||a.mobile.popup.active!==this||(b.scrollTo(0,this._scrollTop),c&&"pagebeforechange"===c.type&&d&&(e="string"==typeof d.toPage?d.toPage:d.toPage.jqmData("url"),e=a.mobile.path.parseUrl(e),f=e.pathname+e.search+e.hash,this._myUrl!==a.mobile.path.makeUrlAbsolute(f)?h=!0:c.preventDefault()),this.window.off(g.closeEvents),this.element.undelegate(g.closeLinkSelector,g.closeLinkEvents),this._close(h))},_bindContainerClose:function(){this.window.on(this.options.closeEvents,a.proxy(this,"_closePopup"))},widget:function(){return this._ui.container},open:function(b){var c,d,e,f,g,h,i=this,j=this.options;return a.mobile.popup.active||j.disabled?this:(a.mobile.popup.active=this,this._scrollTop=this.window.scrollTop(),j.history?(h=a.mobile.navigate.history,d=a.mobile.dialogHashKey,e=a.mobile.activePage,f=e?e.hasClass("ui-dialog"):!1,this._myUrl=c=h.getActive().url,(g=c.indexOf(d)>-1&&!f&&h.activeIndex>0)?(i._open(b),i._bindContainerClose(),this):(-1!==c.indexOf(d)||f?c=a.mobile.path.parseLocation().hash+d:c+=c.indexOf("#")>-1?d:"#"+d,0===h.activeIndex&&c===h.initialDst&&(c+=d),this.window.one("beforenavigate",function(a){a.preventDefault(),i._open(b),i._bindContainerClose()}),this.urlAltered=!0,a.mobile.navigate(c,{role:"dialog"}),this)):(i._open(b),i._bindContainerClose(),i.element.delegate(j.closeLinkSelector,j.closeLinkEvents,function(a){i.close(),a.preventDefault()}),this))},close:function(){return a.mobile.popup.active!==this?this:(this._scrollTop=this.window.scrollTop(),this.options.history&&this.urlAltered?(a.mobile.back(),this.urlAltered=!1):this._closePopup(),this)}}),a.mobile.popup.handleLink=function(b){var c,d=a.mobile.path,e=a(d.hashToSelector(d.parseUrl(b.attr("href")).hash)).first();e.length>0&&e.data("mobile-popup")&&(c=b.offset(),e.popup("open",{x:c.left+b.outerWidth()/2,y:c.top+b.outerHeight()/2,transition:b.jqmData("transition"),positionTo:b.jqmData("position-to")})),setTimeout(function(){b.removeClass(a.mobile.activeBtnClass)},300)},a.mobile.document.on("pagebeforechange",function(b,c){"popup"===c.options.role&&(a.mobile.popup.handleLink(c.options.link),b.preventDefault())})}(a),function(a,b){var d=".ui-disabled,.ui-state-disabled,.ui-li-divider,.ui-screen-hidden,:jqmData(role='placeholder')",e=function(a,b,c){var e=a[c+"All"]().not(d).first();e.length&&(b.blur().attr("tabindex","-1"),e.find("a").first().focus())};a.widget("mobile.selectmenu",a.mobile.selectmenu,{_create:function(){var a=this.options;return a.nativeMenu=a.nativeMenu||this.element.parents(":jqmData(role='popup'),:mobile-popup").length>0,this._super()},_handleSelectFocus:function(){this.element.blur(),this.button.focus()},_handleKeydown:function(a){this._super(a),this._handleButtonVclickKeydown(a)},_handleButtonVclickKeydown:function(b){this.options.disabled||this.isOpen||this.options.nativeMenu||("vclick"===b.type||b.keyCode&&(b.keyCode===a.mobile.keyCode.ENTER||b.keyCode===a.mobile.keyCode.SPACE))&&(this._decideFormat(),"overlay"===this.menuType?this.button.attr("href","#"+this.popupId).attr("data-"+(a.mobile.ns||"")+"rel","popup"):this.button.attr("href","#"+this.dialogId).attr("data-"+(a.mobile.ns||"")+"rel","dialog"),this.isOpen=!0)},_handleListFocus:function(b){var c="focusin"===b.type?{tabindex:"0",event:"vmouseover"}:{tabindex:"-1",event:"vmouseout"};a(b.target).attr("tabindex",c.tabindex).trigger(c.event)},_handleListKeydown:function(b){var c=a(b.target),d=c.closest("li");switch(b.keyCode){case 38:return e(d,c,"prev"),!1;case 40:return e(d,c,"next"),!1;case 13:case 32:return c.trigger("click"),!1}},_handleMenuPageHide:function(){this._delayedTrigger(),this.thisPage.page("bindRemove")},_handleHeaderCloseClick:function(){return"overlay"===this.menuType?(this.close(),!1):void 0},_handleListItemClick:function(b){var c=a(b.target).closest("li"),d=this.select[0].selectedIndex,e=a.mobile.getAttribute(c,"option-index"),f=this._selectOptions().eq(e)[0];f.selected=this.isMultiple?!f.selected:!0,this.isMultiple&&c.find("a").toggleClass("ui-checkbox-on",f.selected).toggleClass("ui-checkbox-off",!f.selected),this.isMultiple||d===e||(this._triggerChange=!0),this.isMultiple?(this.select.trigger("change"),this.list.find("li:not(.ui-li-divider)").eq(e).find("a").first().focus()):this.close(),b.preventDefault()},build:function(){var c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=this.options;return v.nativeMenu?this._super():(c=this.selectId,d=c+"-listbox",e=c+"-dialog",f=this.label,g=this.element.closest(".ui-page"),h=this.element[0].multiple,i=c+"-menu",j=v.theme?" data-"+a.mobile.ns+"theme='"+v.theme+"'":"",k=v.overlayTheme||v.theme||null,l=k?" data-"+a.mobile.ns+"overlay-theme='"+k+"'":"",m=v.dividerTheme&&h?" data-"+a.mobile.ns+"divider-theme='"+v.dividerTheme+"'":"",n=a(""),o=a("").insertAfter(this.select).popup(),p=a("").appendTo(o),q=a("").prependTo(o),r=a("").appendTo(q),this.isMultiple&&(u=a("",{role:"button",text:v.closeText,href:"#","class":"ui-btn ui-corner-all ui-btn-left ui-btn-icon-notext ui-icon-delete"}).appendTo(q)),a.extend(this,{selectId:c,menuId:i,popupId:d,dialogId:e,thisPage:g,menuPage:n,label:f,isMultiple:h,theme:v.theme,listbox:o,list:p,header:q,headerTitle:r,headerClose:u,menuPageContent:s,menuPageClose:t,placeholder:""}),this.refresh(),this._origTabIndex===b&&(this._origTabIndex=null===this.select[0].getAttribute("tabindex")?!1:this.select.attr("tabindex")),this.select.attr("tabindex","-1"),this._on(this.select,{focus:"_handleSelectFocus"}),this._on(this.button,{vclick:"_handleButtonVclickKeydown"}),this.list.attr("role","listbox"),this._on(this.list,{focusin:"_handleListFocus",focusout:"_handleListFocus",keydown:"_handleListKeydown","click li:not(.ui-disabled,.ui-state-disabled,.ui-li-divider)":"_handleListItemClick"}),this._on(this.menuPage,{pagehide:"_handleMenuPageHide"}),this._on(this.listbox,{popupafterclose:"_popupClosed"}),this.isMultiple&&this._on(this.headerClose,{click:"_handleHeaderCloseClick"}),this)},_popupClosed:function(){this.close(),this._delayedTrigger()},_delayedTrigger:function(){this._triggerChange&&this.element.trigger("change"),this._triggerChange=!1},_isRebuildRequired:function(){var a=this.list.find("li"),b=this._selectOptions().not(".ui-screen-hidden");return b.text()!==a.text()},selected:function(){return this._selectOptions().filter(":selected:not( :jqmData(placeholder='true') )")},refresh:function(b){var c,d;return this.options.nativeMenu?this._super(b):(c=this,(b||this._isRebuildRequired())&&c._buildList(),d=this.selectedIndices(),c.setButtonText(),c.setButtonCount(),void c.list.find("li:not(.ui-li-divider)").find("a").removeClass(a.mobile.activeBtnClass).end().attr("aria-selected",!1).each(function(b){if(a.inArray(b,d)>-1){var e=a(this);e.attr("aria-selected",!0),c.isMultiple?e.find("a").removeClass("ui-checkbox-off").addClass("ui-checkbox-on"):e.hasClass("ui-screen-hidden")?e.next().find("a").addClass(a.mobile.activeBtnClass):e.find("a").addClass(a.mobile.activeBtnClass)}}))},close:function(){if(!this.options.disabled&&this.isOpen){var a=this;"page"===a.menuType?(a.menuPage.dialog("close"),a.list.appendTo(a.listbox)):a.listbox.popup("close"),a._focusButton(),a.isOpen=!1}},open:function(){this.button.click()},_focusMenuItem:function(){var b=this.list.find("a."+a.mobile.activeBtnClass);0===b.length&&(b=this.list.find("li:not("+d+") a.ui-btn")),b.first().focus()},_decideFormat:function(){var b=this,c=this.window,d=b.list.parent(),e=d.outerHeight(),f=c.scrollTop(),g=b.button.offset().top,h=c.height();e>h-80||!a.support.scrollTop?(b.menuPage.appendTo(a.mobile.pageContainer).page(),b.menuPageContent=b.menuPage.find(".ui-content"),b.menuPageClose=b.menuPage.find(".ui-header a"),b.thisPage.unbind("pagehide.remove"),0===f&&g>h&&b.thisPage.one("pagehide",function(){a(this).jqmData("lastScroll",g)}),b.menuPage.one({pageshow:a.proxy(this,"_focusMenuItem"),pagehide:a.proxy(this,"close")}),b.menuType="page",b.menuPageContent.append(b.list),b.menuPage.find("div .ui-title").text(b.label.getEncodedText()||b.placeholder)):(b.menuType="overlay",b.listbox.one({popupafteropen:a.proxy(this,"_focusMenuItem")}))},_buildList:function(){var b,d,e,f,g,h,i,j,k,l,m,n,o,p,q=this,r=this.options,s=this.placeholder,t=!0,u="false",v="data-"+a.mobile.ns,w=v+"option-index",x=v+"icon",y=v+"role",z=v+"placeholder",A=c.createDocumentFragment(),B=!1;for(q.list.empty().filter(".ui-listview").listview("destroy"),b=this._selectOptions(),d=b.length,e=this.select[0],g=0;d>g;g++,B=!1)h=b[g],i=a(h),i.hasClass("ui-screen-hidden")||(j=h.parentNode,k=i.getEncodedText(),l=c.createElement("a"),m=[],l.setAttribute("href","#"),l.appendChild(c.createTextNode(k)),j!==e&&"optgroup"===j.nodeName.toLowerCase()&&(n=j.getAttribute("label"),n!==f&&(o=c.createElement("li"),o.setAttribute(y,"list-divider"),o.setAttribute("role","option"),o.setAttribute("tabindex","-1"),o.appendChild(c.createTextNode(n)),A.appendChild(o),f=n)),!t||h.getAttribute("value")&&0!==k.length&&!i.jqmData("placeholder")||(t=!1,B=!0,null===h.getAttribute(z)&&(this._removePlaceholderAttr=!0),h.setAttribute(z,!0),r.hidePlaceholderMenuItems&&m.push("ui-screen-hidden"),s!==k&&(s=q.placeholder=k)),p=c.createElement("li"),h.disabled&&(m.push("ui-state-disabled"),p.setAttribute("aria-disabled",!0)),p.setAttribute(w,g),p.setAttribute(x,u),B&&p.setAttribute(z,!0),p.className=m.join(" "),p.setAttribute("role","option"),l.setAttribute("tabindex","-1"),this.isMultiple&&a(l).addClass("ui-btn ui-checkbox-off ui-btn-icon-right"),p.appendChild(l),A.appendChild(p));q.list[0].appendChild(A),this.isMultiple||s.length?this.headerTitle.text(this.placeholder):this.header.addClass("ui-screen-hidden"),q.list.listview()},_button:function(){return this.options.nativeMenu?this._super():a("",{href:"#",role:"button",id:this.buttonId,"aria-haspopup":"true","aria-owns":this.menuId})},_destroy:function(){this.options.nativeMenu||(this.close(),this._origTabIndex!==b&&(this._origTabIndex!==!1?this.select.attr("tabindex",this._origTabIndex):this.select.removeAttr("tabindex")),this._removePlaceholderAttr&&this._selectOptions().removeAttr("data-"+a.mobile.ns+"placeholder"),this.listbox.remove(),this.menuPage.remove()),this._super()}})}(a),function(a,b){function c(a,b){var c=b?b:[];return c.push("ui-btn"),a.theme&&c.push("ui-btn-"+a.theme),a.icon&&(c=c.concat(["ui-icon-"+a.icon,"ui-btn-icon-"+a.iconpos]),a.iconshadow&&c.push("ui-shadow-icon")),a.inline&&c.push("ui-btn-inline"),a.shadow&&c.push("ui-shadow"),a.corners&&c.push("ui-corner-all"),a.mini&&c.push("ui-mini"),c}function d(a){var c,d,e,g=!1,h=!0,i={icon:"",inline:!1,shadow:!1,corners:!1,iconshadow:!1,mini:!1},j=[];for(a=a.split(" "),c=0;c a, .ui-bar > :jqmData(role='controlgroup') > a, button"})}(a),function(a,b){a.widget("mobile.controlgroup",a.extend({options:{enhanced:!1,theme:null,shadow:!1,corners:!0,excludeInvisible:!0,type:"vertical",mini:!1},_create:function(){var b=this.element,c=this.options;a.fn.buttonMarkup&&this.element.find(a.fn.buttonMarkup.initSelector).buttonMarkup(),a.each(this._childWidgets,a.proxy(function(b,c){a.mobile[c]&&this.element.find(a.mobile[c].initSelector).not(a.mobile.page.prototype.keepNativeSelector())[c]()},this)),a.extend(this,{_ui:null,_initialRefresh:!0}),this._ui=c.enhanced?{groupLegend:b.children(".ui-controlgroup-label").children(),childWrapper:b.children(".ui-controlgroup-controls")}:this._enhance()},_childWidgets:["checkboxradio","selectmenu","button"],_themeClassFromOption:function(a){return a?"none"===a?"":"ui-group-theme-"+a:""},_enhance:function(){var b=this.element,c=this.options,d={groupLegend:b.children("legend"),childWrapper:b.addClass("ui-controlgroup ui-controlgroup-"+("horizontal"===c.type?"horizontal":"vertical")+" "+this._themeClassFromOption(c.theme)+" "+(c.corners?"ui-corner-all ":"")+(c.mini?"ui-mini ":"")).wrapInner("").children()};return d.groupLegend.length>0&&a("").append(d.groupLegend).prependTo(b),d},_init:function(){this.refresh()},_setOptions:function(a){var c,d,e=this.element;return a.type!==b&&(e.removeClass("ui-controlgroup-horizontal ui-controlgroup-vertical").addClass("ui-controlgroup-"+("horizontal"===a.type?"horizontal":"vertical")),c=!0),a.theme!==b&&e.removeClass(this._themeClassFromOption(this.options.theme)).addClass(this._themeClassFromOption(a.theme)),a.corners!==b&&e.toggleClass("ui-corner-all",a.corners),a.mini!==b&&e.toggleClass("ui-mini",a.mini),a.shadow!==b&&this._ui.childWrapper.toggleClass("ui-shadow",a.shadow),a.excludeInvisible!==b&&(this.options.excludeInvisible=a.excludeInvisible,c=!0),d=this._super(a),c&&this.refresh(),d},container:function(){return this._ui.childWrapper},refresh:function(){var b=this.container(),c=b.find(".ui-btn").not(".ui-slider-handle"),d=this._initialRefresh;a.mobile.checkboxradio&&b.find(":mobile-checkboxradio").checkboxradio("refresh"),this._addFirstLastClasses(c,this.options.excludeInvisible?this._getVisibles(c,d):c,d),this._initialRefresh=!1},_destroy:function(){var a,b,c=this.options;return c.enhanced?this:(a=this._ui,b=this.element.removeClass("ui-controlgroup ui-controlgroup-horizontal ui-controlgroup-vertical ui-corner-all ui-mini "+this._themeClassFromOption(c.theme)).find(".ui-btn").not(".ui-slider-handle"),this._removeFirstLastClasses(b),a.groupLegend.unwrap(),void a.childWrapper.children().unwrap())}},a.mobile.behaviors.addFirstLastClasses))}(a),function(a,b){a.widget("mobile.toolbar",{initSelector:":jqmData(role='footer'), :jqmData(role='header')",options:{theme:null,addBackBtn:!1,backBtnTheme:null,backBtnText:"Back"},_create:function(){var b,c,d=this.element.is(":jqmData(role='header')")?"header":"footer",e=this.element.closest(".ui-page");0===e.length&&(e=!1,this._on(this.document,{pageshow:"refresh"})),a.extend(this,{role:d,page:e,leftbtn:b,rightbtn:c}),this.element.attr("role","header"===d?"banner":"contentinfo").addClass("ui-"+d),this.refresh(),this._setOptions(this.options)},_setOptions:function(a){if(a.addBackBtn!==b&&this._updateBackButton(),null!=a.backBtnTheme&&this.element.find(".ui-toolbar-back-btn").addClass("ui-btn ui-btn-"+a.backBtnTheme),a.backBtnText!==b&&this.element.find(".ui-toolbar-back-btn .ui-btn-text").text(a.backBtnText),a.theme!==b){var c=this.options.theme?this.options.theme:"inherit",d=a.theme?a.theme:"inherit";this.element.removeClass("ui-bar-"+c).addClass("ui-bar-"+d)}this._super(a)},refresh:function(){"header"===this.role&&this._addHeaderButtonClasses(),this.page||(this._setRelative(),"footer"===this.role?this.element.appendTo("body"):"header"===this.role&&this._updateBackButton()),this._addHeadingClasses(),this._btnMarkup()},_setRelative:function(){a("[data-"+a.mobile.ns+"role='page']").css({position:"relative"})},_btnMarkup:function(){this.element.children("a").filter(":not([data-"+a.mobile.ns+"role='none'])").attr("data-"+a.mobile.ns+"role","button"),this.element.trigger("create")},_addHeaderButtonClasses:function(){var a=this.element.children("a, button");this.leftbtn=a.hasClass("ui-btn-left")&&!a.hasClass("ui-toolbar-back-btn"),this.rightbtn=a.hasClass("ui-btn-right"),this.leftbtn=this.leftbtn||a.eq(0).not(".ui-btn-right,.ui-toolbar-back-btn").addClass("ui-btn-left").length,this.rightbtn=this.rightbtn||a.eq(1).addClass("ui-btn-right").length},_updateBackButton:function(){var b,c=this.options,d=c.backBtnTheme||c.theme;b=this._backButton=this._backButton||{},this.options.addBackBtn&&"header"===this.role&&a(".ui-page").length>1&&(this.page?this.page[0].getAttribute("data-"+a.mobile.ns+"url")!==a.mobile.path.stripHash(location.hash):a.mobile.navigate&&a.mobile.navigate.history&&a.mobile.navigate.history.activeIndex>0)&&!this.leftbtn?b.attached||(b.element=(b.element||a(""+c.backBtnText+"")).prependTo(this.element),b.attached=!0):b.element&&(b.element.detach(),b.attached=!1)},_addHeadingClasses:function(){this.element.children("h1, h2, h3, h4, h5, h6").addClass("ui-title").attr({role:"heading","aria-level":"1"})}})}(a),function(a,b){a.widget("mobile.toolbar",a.mobile.toolbar,{options:{position:null,visibleOnPageShow:!0,disablePageZoom:!0,transition:"slide",fullscreen:!1,tapToggle:!0,tapToggleBlacklist:"a, button, input, select, textarea, .ui-header-fixed, .ui-footer-fixed, .ui-flipswitch, .ui-popup, .ui-panel, .ui-panel-dismiss-open",hideDuringFocus:"input, textarea, select",updatePagePadding:!0,trackPersistentToolbars:!0,supportBlacklist:function(){return!a.support.fixedPosition}},_create:function(){this._super(),"fixed"!==this.options.position||this.options.supportBlacklist()||this._makeFixed()},_makeFixed:function(){this.element.addClass("ui-"+this.role+"-fixed"),this.updatePagePadding(),this._addTransitionClass(),this._bindPageEvents(),this._bindToggleHandlers()},_setOptions:function(c){if("fixed"===c.position&&"fixed"!==this.options.position&&this._makeFixed(),"fixed"===this.options.position&&!this.options.supportBlacklist()){var d=this.page?this.page:a(".ui-page-active").length>0?a(".ui-page-active"):a(".ui-page").eq(0);c.fullscreen!==b&&(c.fullscreen?(this.element.addClass("ui-"+this.role+"-fullscreen"),d.addClass("ui-page-"+this.role+"-fullscreen")):(this.element.removeClass("ui-"+this.role+"-fullscreen"),d.removeClass("ui-page-"+this.role+"-fullscreen").addClass("ui-page-"+this.role+"-fixed")))}this._super(c)},_addTransitionClass:function(){var a=this.options.transition;a&&"none"!==a&&("slide"===a&&(a=this.element.hasClass("ui-header")?"slidedown":"slideup"),this.element.addClass(a))},_bindPageEvents:function(){var a=this.page?this.element.closest(".ui-page"):this.document;this._on(a,{pagebeforeshow:"_handlePageBeforeShow",webkitAnimationStart:"_handleAnimationStart",animationstart:"_handleAnimationStart",updatelayout:"_handleAnimationStart",pageshow:"_handlePageShow",pagebeforehide:"_handlePageBeforeHide"})},_handlePageBeforeShow:function(){var b=this.options;b.disablePageZoom&&a.mobile.zoom.disable(!0),b.visibleOnPageShow||this.hide(!0)},_handleAnimationStart:function(){this.options.updatePagePadding&&this.updatePagePadding(this.page?this.page:".ui-page-active")},_handlePageShow:function(){this.updatePagePadding(this.page?this.page:".ui-page-active"),this.options.updatePagePadding&&this._on(this.window,{throttledresize:"updatePagePadding"})},_handlePageBeforeHide:function(b,c){var d,e,f,g,h=this.options;h.disablePageZoom&&a.mobile.zoom.enable(!0),h.updatePagePadding&&this._off(this.window,"throttledresize"),h.trackPersistentToolbars&&(d=a(".ui-footer-fixed:jqmData(id)",this.page),e=a(".ui-header-fixed:jqmData(id)",this.page),f=d.length&&c.nextPage&&a(".ui-footer-fixed:jqmData(id='"+d.jqmData("id")+"')",c.nextPage)||a(),g=e.length&&c.nextPage&&a(".ui-header-fixed:jqmData(id='"+e.jqmData("id")+"')",c.nextPage)||a(),(f.length||g.length)&&(f.add(g).appendTo(a.mobile.pageContainer),c.nextPage.one("pageshow",function(){g.prependTo(this),f.appendTo(this)})))},_visible:!0,updatePagePadding:function(c){var d=this.element,e="header"===this.role,f=parseFloat(d.css(e?"top":"bottom"));this.options.fullscreen||(c=c&&c.type===b&&c||this.page||d.closest(".ui-page"),c=this.page?this.page:".ui-page-active",a(c).css("padding-"+(e?"top":"bottom"),d.outerHeight()+f))},_useTransition:function(b){var c=this.window,d=this.element,e=c.scrollTop(),f=d.height(),g=this.page?d.closest(".ui-page").height():a(".ui-page-active").height(),h=a.mobile.getScreenHeight();return!b&&(this.options.transition&&"none"!==this.options.transition&&("header"===this.role&&!this.options.fullscreen&&e>f||"footer"===this.role&&!this.options.fullscreen&&g-f>e+h)||this.options.fullscreen)},show:function(a){var b="ui-fixed-hidden",c=this.element;this._useTransition(a)?c.removeClass("out "+b).addClass("in").animationComplete(function(){c.removeClass("in")}):c.removeClass(b),this._visible=!0},hide:function(a){var b="ui-fixed-hidden",c=this.element,d="out"+("slide"===this.options.transition?" reverse":"");this._useTransition(a)?c.addClass(d).removeClass("in").animationComplete(function(){c.addClass(b).removeClass(d)}):c.addClass(b).removeClass(d),this._visible=!1},toggle:function(){this[this._visible?"hide":"show"]()},_bindToggleHandlers:function(){var b,c,d=this,e=d.options,f=!0,g=this.page?this.page:a(".ui-page");g.bind("vclick",function(b){e.tapToggle&&!a(b.target).closest(e.tapToggleBlacklist).length&&d.toggle()}).bind("focusin focusout",function(g){screen.width<1025&&a(g.target).is(e.hideDuringFocus)&&!a(g.target).closest(".ui-header-fixed, .ui-footer-fixed").length&&("focusout"!==g.type||f?"focusin"===g.type&&f&&(clearTimeout(b),f=!1,c=setTimeout(function(){d.hide()},0)):(f=!0,clearTimeout(c),b=setTimeout(function(){d.show()},0)))})},_setRelative:function(){"fixed"!==this.options.position&&a("[data-"+a.mobile.ns+"role='page']").css({position:"relative"})},_destroy:function(){var a=this.element,b=a.hasClass("ui-header");a.closest(".ui-page").css("padding-"+(b?"top":"bottom"),""),a.removeClass("ui-header-fixed ui-footer-fixed ui-header-fullscreen ui-footer-fullscreen in out fade slidedown slideup ui-fixed-hidden"),a.closest(".ui-page").removeClass("ui-page-header-fixed ui-page-footer-fixed ui-page-header-fullscreen ui-page-footer-fullscreen")}})}(a),function(a){a.widget("mobile.toolbar",a.mobile.toolbar,{_makeFixed:function(){this._super(),this._workarounds()},_workarounds:function(){var a=navigator.userAgent,b=navigator.platform,c=a.match(/AppleWebKit\/([0-9]+)/),d=!!c&&c[1],e=null,f=this;if(b.indexOf("iPhone")>-1||b.indexOf("iPad")>-1||b.indexOf("iPod")>-1)e="ios";else{if(!(a.indexOf("Android")>-1))return;e="android"}if("ios"===e)f._bindScrollWorkaround();else{if(!("android"===e&&d&&534>d))return;f._bindScrollWorkaround(),f._bindListThumbWorkaround()}},_viewportOffset:function(){var a=this.element,b=a.hasClass("ui-header"),c=Math.abs(a.offset().top-this.window.scrollTop());return b||(c=Math.round(c-this.window.height()+a.outerHeight())-60),c},_bindScrollWorkaround:function(){var a=this;this._on(this.window,{scrollstop:function(){var b=a._viewportOffset();b>2&&a._visible&&a._triggerRedraw()}})},_bindListThumbWorkaround:function(){this.element.closest(".ui-page").addClass("ui-android-2x-fixed")},_triggerRedraw:function(){var b=parseFloat(a(".ui-page-active").css("padding-bottom"));a(".ui-page-active").css("padding-bottom",b+1+"px"),setTimeout(function(){a(".ui-page-active").css("padding-bottom",b+"px")},0)},destroy:function(){this._super(),this.element.closest(".ui-page-active").removeClass("ui-android-2x-fix")}})}(a),function(a,b){function c(){var a=e.clone(),b=a.eq(0),c=a.eq(1),d=c.children();return{arEls:c.add(b),gd:b,ct:c,ar:d}
+}var d=a.mobile.browser.oldIE&&a.mobile.browser.oldIE<=8,e=a("");a.widget("mobile.popup",a.mobile.popup,{options:{arrow:""},_create:function(){var a,b=this._super();return this.options.arrow&&(this._ui.arrow=a=this._addArrow()),b},_addArrow:function(){var a,b=this.options,d=c();return a=this._themeClassFromOption("ui-body-",b.theme),d.ar.addClass(a+(b.shadow?" ui-overlay-shadow":"")),d.arEls.hide().appendTo(this.element),d},_unenhance:function(){var a=this._ui.arrow;return a&&a.arEls.remove(),this._super()},_tryAnArrow:function(a,b,c,d,e){var f,g,h,i={},j={};return d.arFull[a.dimKey]>d.guideDims[a.dimKey]?e:(i[a.fst]=c[a.fst]+(d.arHalf[a.oDimKey]+d.menuHalf[a.oDimKey])*a.offsetFactor-d.contentBox[a.fst]+(d.clampInfo.menuSize[a.oDimKey]-d.contentBox[a.oDimKey])*a.arrowOffsetFactor,i[a.snd]=c[a.snd],f=d.result||this._calculateFinalLocation(i,d.clampInfo),g={x:f.left,y:f.top},j[a.fst]=g[a.fst]+d.contentBox[a.fst]+a.tipOffset,j[a.snd]=Math.max(f[a.prop]+d.guideOffset[a.prop]+d.arHalf[a.dimKey],Math.min(f[a.prop]+d.guideOffset[a.prop]+d.guideDims[a.dimKey]-d.arHalf[a.dimKey],c[a.snd])),h=Math.abs(c.x-j.x)+Math.abs(c.y-j.y),(!e||h0?c:!1,_openedPage:null,_page:this._getPage,_panelInner:this._getPanelInner(),_fixedToolbars:this._getFixedToolbars}),"overlay"!==this.options.display&&this._getWrapper(),this._addPanelClasses(),a.support.cssTransform3d&&this.options.animate&&this.element.addClass(this.options.classes.animate),this._bindUpdateLayout(),this._bindCloseEvents(),this._bindLinkListeners(),this._bindPageEvents(),this.options.dismissible&&this._createModal(),this._bindSwipeEvents()},_getPanelInner:function(){var a=this.element.find("."+this.options.classes.panelInner);return 0===a.length&&(a=this.element.children().wrapAll("").parent()),a},_createModal:function(){var b=this,c=b._parentPage?b._parentPage.parent():b.element.parent();b._modal=a("").on("mousedown",function(){b.close()}).appendTo(c)},_getPage:function(){var b=this._openedPage||this._parentPage||a("."+a.mobile.activePageClass);return b},_getWrapper:function(){var a=this._page().find("."+this.options.classes.pageWrapper);0===a.length&&(a=this._page().children(".ui-header:not(.ui-header-fixed), .ui-content:not(.ui-popup), .ui-footer:not(.ui-footer-fixed)").wrapAll("").parent()),this._wrapper=a},_getFixedToolbars:function(){var b=a("body").children(".ui-header-fixed, .ui-footer-fixed"),c=this._page().find(".ui-header-fixed, .ui-footer-fixed"),d=b.add(c).addClass(this.options.classes.pageFixedToolbar);return d},_getPosDisplayClasses:function(a){return a+"-position-"+this.options.position+" "+a+"-display-"+this.options.display},_getPanelClasses:function(){var a=this.options.classes.panel+" "+this._getPosDisplayClasses(this.options.classes.panel)+" "+this.options.classes.panelClosed+" ui-body-"+(this.options.theme?this.options.theme:"inherit");return this.options.positionFixed&&(a+=" "+this.options.classes.panelFixed),a},_addPanelClasses:function(){this.element.addClass(this._getPanelClasses())},_handleCloseClick:function(a){a.isDefaultPrevented()||this.close()},_bindCloseEvents:function(){this._on(this._closeLink,{click:"_handleCloseClick"}),this._on({"click a:jqmData(ajax='false')":"_handleCloseClick"})},_positionPanel:function(b){var c=this,d=c._panelInner.outerHeight(),e=d>a.mobile.getScreenHeight();e||!c.options.positionFixed?(e&&(c._unfixPanel(),a.mobile.resetActivePageHeight(d)),b&&this.window[0].scrollTo(0,a.mobile.defaultHomeScroll)):c._fixPanel()},_bindFixListener:function(){this._on(a(b),{throttledresize:"_positionPanel"})},_unbindFixListener:function(){this._off(a(b),"throttledresize")},_unfixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.removeClass(this.options.classes.panelFixed)},_fixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.addClass(this.options.classes.panelFixed)},_bindUpdateLayout:function(){var a=this;a.element.on("updatelayout",function(){a._open&&a._positionPanel()})},_bindLinkListeners:function(){this._on("body",{"click a":"_handleClick"})},_handleClick:function(b){var d,e=this.element.attr("id");b.currentTarget.href.split("#")[1]===e&&e!==c&&(b.preventDefault(),d=a(b.target),d.hasClass("ui-btn")&&(d.addClass(a.mobile.activeBtnClass),this.element.one("panelopen panelclose",function(){d.removeClass(a.mobile.activeBtnClass)})),this.toggle())},_bindSwipeEvents:function(){var a=this,b=a._modal?a.element.add(a._modal):a.element;a.options.swipeClose&&("left"===a.options.position?b.on("swipeleft.panel",function(){a.close()}):b.on("swiperight.panel",function(){a.close()}))},_bindPageEvents:function(){var a=this;this.document.on("panelbeforeopen",function(b){a._open&&b.target!==a.element[0]&&a.close()}).on("keyup.panel",function(b){27===b.keyCode&&a._open&&a.close()}),this._parentPage||"overlay"===this.options.display||this._on(this.document,{pageshow:"_getWrapper"}),a._parentPage?this.document.on("pagehide",":jqmData(role='page')",function(){a._open&&a.close(!0)}):this.document.on("pagebeforehide",function(){a._open&&a.close(!0)})},_open:!1,_pageContentOpenClasses:null,_modalOpenClasses:null,open:function(b){if(!this._open){var c=this,d=c.options,e=function(){c._off(c.document,"panelclose"),c._page().jqmData("panel","open"),a.support.cssTransform3d&&d.animate&&"overlay"!==d.display&&(c._wrapper.addClass(d.classes.animate),c._fixedToolbars().addClass(d.classes.animate)),!b&&a.support.cssTransform3d&&d.animate?(c._wrapper||c.element).animationComplete(f,"transition"):setTimeout(f,0),d.theme&&"overlay"!==d.display&&c._page().parent().addClass(d.classes.pageContainer+"-themed "+d.classes.pageContainer+"-"+d.theme),c.element.removeClass(d.classes.panelClosed).addClass(d.classes.panelOpen),c._positionPanel(!0),c._pageContentOpenClasses=c._getPosDisplayClasses(d.classes.pageContentPrefix),"overlay"!==d.display&&(c._page().parent().addClass(d.classes.pageContainer),c._wrapper.addClass(c._pageContentOpenClasses),c._fixedToolbars().addClass(c._pageContentOpenClasses)),c._modalOpenClasses=c._getPosDisplayClasses(d.classes.modal)+" "+d.classes.modalOpen,c._modal&&c._modal.addClass(c._modalOpenClasses).height(Math.max(c._modal.height(),c.document.height()))},f=function(){c._open&&("overlay"!==d.display&&(c._wrapper.addClass(d.classes.pageContentPrefix+"-open"),c._fixedToolbars().addClass(d.classes.pageContentPrefix+"-open")),c._bindFixListener(),c._trigger("open"),c._openedPage=c._page())};c._trigger("beforeopen"),"open"===c._page().jqmData("panel")?c._on(c.document,{panelclose:e}):e(),c._open=!0}},close:function(b){if(this._open){var c=this,d=this.options,e=function(){c.element.removeClass(d.classes.panelOpen),"overlay"!==d.display&&(c._wrapper.removeClass(c._pageContentOpenClasses),c._fixedToolbars().removeClass(c._pageContentOpenClasses)),!b&&a.support.cssTransform3d&&d.animate?(c._wrapper||c.element).animationComplete(f,"transition"):setTimeout(f,0),c._modal&&c._modal.removeClass(c._modalOpenClasses).height("")},f=function(){d.theme&&"overlay"!==d.display&&c._page().parent().removeClass(d.classes.pageContainer+"-themed "+d.classes.pageContainer+"-"+d.theme),c.element.addClass(d.classes.panelClosed),"overlay"!==d.display&&(c._page().parent().removeClass(d.classes.pageContainer),c._wrapper.removeClass(d.classes.pageContentPrefix+"-open"),c._fixedToolbars().removeClass(d.classes.pageContentPrefix+"-open")),a.support.cssTransform3d&&d.animate&&"overlay"!==d.display&&(c._wrapper.removeClass(d.classes.animate),c._fixedToolbars().removeClass(d.classes.animate)),c._fixPanel(),c._unbindFixListener(),a.mobile.resetActivePageHeight(),c._page().jqmRemoveData("panel"),c._trigger("close"),c._openedPage=null};c._trigger("beforeclose"),e(),c._open=!1}},toggle:function(){this[this._open?"close":"open"]()},_destroy:function(){var b,c=this.options,d=a("body > :mobile-panel").length+a.mobile.activePage.find(":mobile-panel").length>1;"overlay"!==c.display&&(b=a("body > :mobile-panel").add(a.mobile.activePage.find(":mobile-panel")),0===b.not(".ui-panel-display-overlay").not(this.element).length&&this._wrapper.children().unwrap(),this._open&&(this._fixedToolbars().removeClass(c.classes.pageContentPrefix+"-open"),a.support.cssTransform3d&&c.animate&&this._fixedToolbars().removeClass(c.classes.animate),this._page().parent().removeClass(c.classes.pageContainer),c.theme&&this._page().parent().removeClass(c.classes.pageContainer+"-themed "+c.classes.pageContainer+"-"+c.theme))),d||this.document.off("panelopen panelclose"),this._open&&this._page().jqmRemoveData("panel"),this._panelInner.children().unwrap(),this.element.removeClass([this._getPanelClasses(),c.classes.panelOpen,c.classes.animate].join(" ")).off("swipeleft.panel swiperight.panel").off("panelbeforeopen").off("panelhide").off("keyup.panel").off("updatelayout"),this._modal&&this._modal.remove()}})}(a),function(a,b){a.widget("mobile.table",{options:{classes:{table:"ui-table"},enhanced:!1},_create:function(){this.options.enhanced||this.element.addClass(this.options.classes.table),a.extend(this,{headers:b,allHeaders:b}),this._refresh(!0)},_setHeaders:function(){var a=this.element.find("thead tr");this.headers=this.element.find("tr:eq(0)").children(),this.allHeaders=this.headers.add(a.children())},refresh:function(){this._refresh()},rebuild:a.noop,_refresh:function(){var b=this.element,c=b.find("thead tr");this._setHeaders(),c.each(function(){var d=0;a(this).children().each(function(){var e,f=parseInt(this.getAttribute("colspan"),10),g=":nth-child("+(d+1)+")";if(this.setAttribute("data-"+a.mobile.ns+"colstart",d+1),f)for(e=0;f-1>e;e++)d++,g+=", :nth-child("+(d+1)+")";a(this).jqmData("cells",b.find("tr").not(c.eq(0)).not(this).children(g)),d++})})}})}(a),function(a){a.widget("mobile.table",a.mobile.table,{options:{mode:"columntoggle",columnBtnTheme:null,columnPopupTheme:null,columnBtnText:"Columns...",classes:a.extend(a.mobile.table.prototype.options.classes,{popup:"ui-table-columntoggle-popup",columnBtn:"ui-table-columntoggle-btn",priorityPrefix:"ui-table-priority-",columnToggleTable:"ui-table-columntoggle"})},_create:function(){this._super(),"columntoggle"===this.options.mode&&(a.extend(this,{_menu:null}),this.options.enhanced?(this._menu=a(this.document[0].getElementById(this._id()+"-popup")).children().first(),this._addToggles(this._menu,!0)):(this._menu=this._enhanceColToggle(),this.element.addClass(this.options.classes.columnToggleTable)),this._setupEvents(),this._setToggleState())},_id:function(){return this.element.attr("id")||this.widgetName+this.uuid},_setupEvents:function(){this._on(this.window,{throttledresize:"_setToggleState"}),this._on(this._menu,{"change input":"_menuInputChange"})},_addToggles:function(b,c){var d,e=0,f=this.options,g=b.controlgroup("container");c?d=b.find("input"):g.empty(),this.headers.not("td").each(function(){var b,h,i=a(this),j=a.mobile.getAttribute(this,"priority");j&&(h=i.add(i.jqmData("cells")),h.addClass(f.classes.priorityPrefix+j),b=(c?d.eq(e++):a("").appendTo(g).children(0).checkboxradio({theme:f.columnPopupTheme})).jqmData("header",i).jqmData("cells",h),i.jqmData("input",b))}),c||b.controlgroup("refresh")},_menuInputChange:function(b){var c=a(b.target),d=c[0].checked;c.jqmData("cells").toggleClass("ui-table-cell-hidden",!d).toggleClass("ui-table-cell-visible",d)},_unlockCells:function(a){a.removeClass("ui-table-cell-hidden ui-table-cell-visible")},_enhanceColToggle:function(){var b,c,d,e,f=this.element,g=this.options,h=a.mobile.ns,i=this.document[0].createDocumentFragment();return b=this._id()+"-popup",c=a(""+g.columnBtnText+""),d=a(""),e=a("").controlgroup(),this._addToggles(e,!1),e.appendTo(d),i.appendChild(d[0]),i.appendChild(c[0]),f.before(i),d.popup(),e},rebuild:function(){this._super(),"columntoggle"===this.options.mode&&this._refresh(!1)},_refresh:function(b){var c,d,e;if(this._super(b),!b&&"columntoggle"===this.options.mode)for(c=this.headers,d=[],this._menu.find("input").each(function(){var b=a(this),e=b.jqmData("header"),f=c.index(e[0]);f>-1&&!b.prop("checked")&&d.push(f)}),this._unlockCells(this.element.find(".ui-table-cell-hidden, .ui-table-cell-visible")),this._addToggles(this._menu,b),e=d.length-1;e>-1;e--)c.eq(d[e]).jqmData("input").prop("checked",!1).checkboxradio("refresh").trigger("change")},_setToggleState:function(){this._menu.find("input").each(function(){var b=a(this);this.checked="table-cell"===b.jqmData("cells").eq(0).css("display"),b.checkboxradio("refresh")})},_destroy:function(){this._super()}})}(a),function(a){a.widget("mobile.table",a.mobile.table,{options:{mode:"reflow",classes:a.extend(a.mobile.table.prototype.options.classes,{reflowTable:"ui-table-reflow",cellLabels:"ui-table-cell-label"})},_create:function(){this._super(),"reflow"===this.options.mode&&(this.options.enhanced||(this.element.addClass(this.options.classes.reflowTable),this._updateReflow()))},rebuild:function(){this._super(),"reflow"===this.options.mode&&this._refresh(!1)},_refresh:function(a){this._super(a),a||"reflow"!==this.options.mode||this._updateReflow()},_updateReflow:function(){var b=this,c=this.options;a(b.allHeaders.get().reverse()).each(function(){var d,e,f=a(this).jqmData("cells"),g=a.mobile.getAttribute(this,"colstart"),h=f.not(this).filter("thead th").length&&" ui-table-cell-label-top",i=a(this).clone().contents();i.length>0&&(h?(d=parseInt(this.getAttribute("colspan"),10),e="",d&&(e="td:nth-child("+d+"n + "+g+")"),b._addLabels(f.filter(e),c.classes.cellLabels+h,i)):b._addLabels(f,c.classes.cellLabels,i))})},_addLabels:function(b,c,d){b.not(":has(b."+c+")").prepend(a("").append(d))}})}(a),function(a,c){var d=function(b,c){return-1===(""+(a.mobile.getAttribute(this,"filtertext")||a(this).text())).toLowerCase().indexOf(c)};a.widget("mobile.filterable",{initSelector:":jqmData(filter='true')",options:{filterReveal:!1,filterCallback:d,enhanced:!1,input:null,children:"> li, > option, > optgroup option, > tbody tr, > .ui-controlgroup-controls > .ui-btn, > .ui-controlgroup-controls > .ui-checkbox, > .ui-controlgroup-controls > .ui-radio"},_create:function(){var b=this.options;a.extend(this,{_search:null,_timer:0}),this._setInput(b.input),b.enhanced||this._filterItems((this._search&&this._search.val()||"").toLowerCase())},_onKeyUp:function(){var c,d,e=this._search;if(e){if(c=e.val().toLowerCase(),d=a.mobile.getAttribute(e[0],"lastval")+"",d&&d===c)return;this._timer&&(b.clearTimeout(this._timer),this._timer=0),this._timer=this._delay(function(){return this._trigger("beforefilter",null,{input:e})===!1?!1:(e[0].setAttribute("data-"+a.mobile.ns+"lastval",c),this._filterItems(c),void(this._timer=0))},250)}},_getFilterableItems:function(){var b=this.element,c=this.options.children,d=c?a.isFunction(c)?c():c.nodeName?a(c):c.jquery?c:this.element.find(c):{length:0};return 0===d.length&&(d=b.children()),d},_filterItems:function(b){var c,e,f,g,h=[],i=[],j=this.options,k=this._getFilterableItems();if(null!=b)for(e=j.filterCallback||d,f=k.length,c=0;f>c;c++)g=e.call(k[c],c,b)?i:h,g.push(k[c]);0===i.length?k[j.filterReveal&&0===b.length?"addClass":"removeClass"]("ui-screen-hidden"):(a(i).addClass("ui-screen-hidden"),a(h).removeClass("ui-screen-hidden")),this._refreshChildWidget(),this._trigger("filter",null,{items:k})},_refreshChildWidget:function(){var b,c,d=["collapsibleset","selectmenu","controlgroup","listview"];for(c=d.length-1;c>-1;c--)b=d[c],a.mobile[b]&&(b=this.element.data("mobile-"+b),b&&a.isFunction(b.refresh)&&b.refresh())},_setInput:function(c){var d=this._search;this._timer&&(b.clearTimeout(this._timer),this._timer=0),d&&(this._off(d,"keyup change input"),d=null),c&&(d=c.jquery?c:c.nodeName?a(c):this.document.find(c),this._on(d,{keydown:"_onKeyDown",keypress:"_onKeyPress",keyup:"_onKeyUp",change:"_onKeyUp",input:"_onKeyUp"})),this._search=d},_onKeyDown:function(b){b.keyCode===a.ui.keyCode.ENTER&&(b.preventDefault(),this._preventKeyPress=!0)},_onKeyPress:function(a){this._preventKeyPress&&(a.preventDefault(),this._preventKeyPress=!1)},_setOptions:function(a){var b=!(a.filterReveal===c&&a.filterCallback===c&&a.children===c);this._super(a),a.input!==c&&(this._setInput(a.input),b=!0),b&&this.refresh()},_destroy:function(){var a=this.options,b=this._getFilterableItems();a.enhanced?b.toggleClass("ui-screen-hidden",a.filterReveal):b.removeClass("ui-screen-hidden")},refresh:function(){this._timer&&(b.clearTimeout(this._timer),this._timer=0),this._filterItems((this._search&&this._search.val()||"").toLowerCase())}})}(a),function(a,b){var c=function(a,b){return function(c){b.call(this,c),a._syncTextInputOptions(c)}},d=/(^|\s)ui-li-divider(\s|$)/,e=a.mobile.filterable.prototype.options.filterCallback;a.mobile.filterable.prototype.options.filterCallback=function(a,b){return!this.className.match(d)&&e.call(this,a,b)},a.widget("mobile.filterable",a.mobile.filterable,{options:{filterPlaceholder:"Filter items...",filterTheme:null},_create:function(){var b,c,d=this.element,e=["collapsibleset","selectmenu","controlgroup","listview"],f={};for(this._super(),a.extend(this,{_widget:null}),b=e.length-1;b>-1;b--)if(c=e[b],a.mobile[c]){if(this._setWidget(d.data("mobile-"+c)))break;f[c+"create"]="_handleCreate"}this._widget||this._on(d,f)},_handleCreate:function(a){this._setWidget(this.element.data("mobile-"+a.type.substring(0,a.type.length-6)))},_trigger:function(a,b,c){return this._widget&&"mobile-listview"===this._widget.widgetFullName&&"beforefilter"===a&&this._widget._trigger("beforefilter",b,c),this._super(a,b,c)},_setWidget:function(a){return!this._widget&&a&&(this._widget=a,this._widget._setOptions=c(this,this._widget._setOptions)),this._widget&&(this._syncTextInputOptions(this._widget.options),"listview"===this._widget.widgetName&&(this._widget.options.hideDividers=!0,this._widget.element.listview("refresh"))),!!this._widget},_isSearchInternal:function(){return this._search&&this._search.jqmData("ui-filterable-"+this.uuid+"-internal")},_setInput:function(b){var c=this.options,d=!0,e={};if(!b){if(this._isSearchInternal())return;d=!1,b=a("").jqmData("ui-filterable-"+this.uuid+"-internal",!0),a("").append(b).submit(function(a){a.preventDefault(),b.blur()}).insertBefore(this.element),a.mobile.textinput&&(null!=this.options.filterTheme&&(e.theme=c.filterTheme),b.textinput(e))}this._super(b),this._isSearchInternal()&&d&&this._search.attr("placeholder",this.options.filterPlaceholder)},_setOptions:function(c){var d=this._super(c);return c.filterPlaceholder!==b&&this._isSearchInternal()&&this._search.attr("placeholder",c.filterPlaceholder),c.filterTheme!==b&&this._search&&a.mobile.textinput&&this._search.textinput("option","theme",c.filterTheme),d},_destroy:function(){this._isSearchInternal()&&this._search.remove(),this._super()},_syncTextInputOptions:function(c){var d,e={};if(this._isSearchInternal()&&a.mobile.textinput){for(d in a.mobile.textinput.prototype.options)c[d]!==b&&(e[d]="theme"===d&&null!=this.options.filterTheme?this.options.filterTheme:c[d]);this._search.textinput("option",e)}}}),a.widget("mobile.listview",a.mobile.listview,{options:{filter:!1},_create:function(){return this.options.filter!==!0||this.element.data("mobile-filterable")||this.element.filterable(),this._super()},_afterListviewRefresh:function(){var a=this.element.data("mobile-filterable");this.options.filter===!0&&a&&(this._preventRefreshLoop=!0,a.refresh())},refresh:function(){var a;return this._preventRefreshLoop||(a=this._superApply(arguments)),this._preventRefreshLoop=!1,a}})}(a),function(a,b){function c(){return++e}function d(a){return a.hash.length>1&&decodeURIComponent(a.href.replace(f,""))===decodeURIComponent(location.href.replace(f,""))}var e=0,f=/#.*$/;a.widget("ui.tabs",{version:"fadf2b312a05040436451c64bbfaf4814bc62c56",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var b=this,c=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",c.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(b){a(this).is(".ui-state-disabled")&&b.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){a(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),c.active=this._initialActive(),a.isArray(c.disabled)&&(c.disabled=a.unique(c.disabled.concat(a.map(this.tabs.filter(".ui-state-disabled"),function(a){return b.tabs.index(a)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(c.active):a(),this._refresh(),this.active.length&&this.load(c.active)},_initialActive:function(){var b=this.options.active,c=this.options.collapsible,d=location.hash.substring(1);return null===b&&(d&&this.tabs.each(function(c,e){return a(e).attr("aria-controls")===d?(b=c,!1):void 0}),null===b&&(b=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===b||-1===b)&&(b=this.tabs.length?0:!1)),b!==!1&&(b=this.tabs.index(this.tabs.eq(b)),-1===b&&(b=c?!1:0)),!c&&b===!1&&this.anchors.length&&(b=0),b},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):a()}},_tabKeydown:function(b){var c=a(this.document[0].activeElement).closest("li"),d=this.tabs.index(c),e=!0;if(!this._handlePageNav(b)){switch(b.keyCode){case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:d++;break;case a.ui.keyCode.UP:case a.ui.keyCode.LEFT:e=!1,d--;break;case a.ui.keyCode.END:d=this.anchors.length-1;break;case a.ui.keyCode.HOME:d=0;break;case a.ui.keyCode.SPACE:return b.preventDefault(),clearTimeout(this.activating),void this._activate(d);case a.ui.keyCode.ENTER:return b.preventDefault(),clearTimeout(this.activating),void this._activate(d===this.options.active?!1:d);default:return}b.preventDefault(),clearTimeout(this.activating),d=this._focusNextTab(d,e),b.ctrlKey||(c.attr("aria-selected","false"),this.tabs.eq(d).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",d)},this.delay))}},_panelKeydown:function(b){this._handlePageNav(b)||b.ctrlKey&&b.keyCode===a.ui.keyCode.UP&&(b.preventDefault(),this.active.focus())},_handlePageNav:function(b){return b.altKey&&b.keyCode===a.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):b.altKey&&b.keyCode===a.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(b,c){function d(){return b>e&&(b=0),0>b&&(b=e),b}for(var e=this.tabs.length-1;-1!==a.inArray(d(),this.options.disabled);)b=c?b+1:b-1;return b},_focusNextTab:function(a,b){return a=this._findNextTab(a,b),this.tabs.eq(a).focus(),a},_setOption:function(a,b){return"active"===a?void this._activate(b):"disabled"===a?void this._setupDisabled(b):(this._super(a,b),"collapsible"===a&&(this.element.toggleClass("ui-tabs-collapsible",b),b||this.options.active!==!1||this._activate(0)),"event"===a&&this._setupEvents(b),void("heightStyle"===a&&this._setupHeightStyle(b)))},_tabId:function(a){return a.attr("aria-controls")||"ui-tabs-"+c()},_sanitizeSelector:function(a){return a?a.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var b=this.options,c=this.tablist.children(":has(a[href])");b.disabled=a.map(c.filter(".ui-state-disabled"),function(a){return c.index(a)}),this._processTabs(),b.active!==!1&&this.anchors.length?this.active.length&&!a.contains(this.tablist[0],this.active[0])?this.tabs.length===b.disabled.length?(b.active=!1,this.active=a()):this._activate(this._findNextTab(Math.max(0,b.active-1),!1)):b.active=this.tabs.index(this.active):(b.active=!1,this.active=a()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var b=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return a("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=a(),this.anchors.each(function(c,e){var f,g,h,i=a(e).uniqueId().attr("id"),j=a(e).closest("li"),k=j.attr("aria-controls");d(e)?(f=e.hash,g=b.element.find(b._sanitizeSelector(f))):(h=b._tabId(j),f="#"+h,g=b.element.find(f),g.length||(g=b._createPanel(h),g.insertAfter(b.panels[c-1]||b.tablist)),g.attr("aria-live","polite")),g.length&&(b.panels=b.panels.add(g)),k&&j.data("ui-tabs-aria-controls",k),j.attr({"aria-controls":f.substring(1),"aria-labelledby":i}),g.attr("aria-labelledby",i)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(b){return a("").attr("id",b).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(b){a.isArray(b)&&(b.length?b.length===this.anchors.length&&(b=!0):b=!1);for(var c,d=0;c=this.tabs[d];d++)b===!0||-1!==a.inArray(d,b)?a(c).addClass("ui-state-disabled").attr("aria-disabled","true"):a(c).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=b},_setupEvents:function(b){var c={click:function(a){a.preventDefault()}};b&&a.each(b.split(" "),function(a,b){c[b]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,c),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(b){var c,d=this.element.parent();"fill"===b?(c=d.height(),c-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var b=a(this),d=b.css("position");"absolute"!==d&&"fixed"!==d&&(c-=b.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){c-=a(this).outerHeight(!0)}),this.panels.each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")):"auto"===b&&(c=0,this.panels.each(function(){c=Math.max(c,a(this).height("").height())}).height(c))},_eventHandler:function(b){var c=this.options,d=this.active,e=a(b.currentTarget),f=e.closest("li"),g=f[0]===d[0],h=g&&c.collapsible,i=h?a():this._getPanelForTab(f),j=d.length?this._getPanelForTab(d):a(),k={oldTab:d,oldPanel:j,newTab:h?a():f,newPanel:i};b.preventDefault(),f.hasClass("ui-state-disabled")||f.hasClass("ui-tabs-loading")||this.running||g&&!c.collapsible||this._trigger("beforeActivate",b,k)===!1||(c.active=h?!1:this.tabs.index(f),this.active=g?a():f,this.xhr&&this.xhr.abort(),j.length||i.length||a.error("jQuery UI Tabs: Mismatching fragment identifier."),i.length&&this.load(this.tabs.index(f),b),this._toggle(b,k))},_toggle:function(b,c){function d(){f.running=!1,f._trigger("activate",b,c)}function e(){c.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),g.length&&f.options.show?f._show(g,f.options.show,d):(g.show(),d())}var f=this,g=c.newPanel,h=c.oldPanel;this.running=!0,h.length&&this.options.hide?this._hide(h,this.options.hide,function(){c.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),e()}):(c.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),h.hide(),e()),h.attr({"aria-expanded":"false","aria-hidden":"true"}),c.oldTab.attr("aria-selected","false"),g.length&&h.length?c.oldTab.attr("tabIndex",-1):g.length&&this.tabs.filter(function(){return 0===a(this).attr("tabIndex")}).attr("tabIndex",-1),g.attr({"aria-expanded":"true","aria-hidden":"false"}),c.newTab.attr({"aria-selected":"true",tabIndex:0})
+},_activate:function(b){var c,d=this._findActive(b);d[0]!==this.active[0]&&(d.length||(d=this.active),c=d.find(".ui-tabs-anchor")[0],this._eventHandler({target:c,currentTarget:c,preventDefault:a.noop}))},_findActive:function(b){return b===!1?a():this.tabs.eq(b)},_getIndex:function(a){return"string"==typeof a&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){a.data(this,"ui-tabs-destroy")?a(this).remove():a(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var b=a(this),c=b.data("ui-tabs-aria-controls");c?b.attr("aria-controls",c).removeData("ui-tabs-aria-controls"):b.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(c){var d=this.options.disabled;d!==!1&&(c===b?d=!1:(c=this._getIndex(c),d=a.isArray(d)?a.map(d,function(a){return a!==c?a:null}):a.map(this.tabs,function(a,b){return b!==c?b:null})),this._setupDisabled(d))},disable:function(c){var d=this.options.disabled;if(d!==!0){if(c===b)d=!0;else{if(c=this._getIndex(c),-1!==a.inArray(c,d))return;d=a.isArray(d)?a.merge([c],d).sort():[c]}this._setupDisabled(d)}},load:function(b,c){b=this._getIndex(b);var e=this,f=this.tabs.eq(b),g=f.find(".ui-tabs-anchor"),h=this._getPanelForTab(f),i={tab:f,panel:h};d(g[0])||(this.xhr=a.ajax(this._ajaxSettings(g,c,i)),this.xhr&&"canceled"!==this.xhr.statusText&&(f.addClass("ui-tabs-loading"),h.attr("aria-busy","true"),this.xhr.success(function(a){setTimeout(function(){h.html(a),e._trigger("load",c,i)},1)}).complete(function(a,b){setTimeout(function(){"abort"===b&&e.panels.stop(!1,!0),f.removeClass("ui-tabs-loading"),h.removeAttr("aria-busy"),a===e.xhr&&delete e.xhr},1)})))},_ajaxSettings:function(b,c,d){var e=this;return{url:b.attr("href"),beforeSend:function(b,f){return e._trigger("beforeLoad",c,a.extend({jqXHR:b,ajaxSettings:f},d))}}},_getPanelForTab:function(b){var c=a(b).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+c))}})}(a),function(){}(a),function(a,b){function c(a){e=a.originalEvent,i=e.accelerationIncludingGravity,f=Math.abs(i.x),g=Math.abs(i.y),h=Math.abs(i.z),!b.orientation&&(f>7||(h>6&&8>g||8>h&&g>6)&&f>5)?d.enabled&&d.disable():d.enabled||d.enable()}a.mobile.iosorientationfixEnabled=!0;var d,e,f,g,h,i,j=navigator.userAgent;return/iPhone|iPad|iPod/.test(navigator.platform)&&/OS [1-5]_[0-9_]* like Mac OS X/i.test(j)&&j.indexOf("AppleWebKit")>-1?(d=a.mobile.zoom,void a.mobile.document.on("mobileinit",function(){a.mobile.iosorientationfixEnabled&&a.mobile.window.bind("orientationchange.iosorientationfix",d.enable).bind("devicemotion.iosorientationfix",c)})):void(a.mobile.iosorientationfixEnabled=!1)}(a,this),function(a,b){function d(){e.removeClass("ui-mobile-rendering")}var e=a("html"),f=a.mobile.window;a(b.document).trigger("mobileinit"),a.mobile.gradeA()&&(a.mobile.ajaxBlacklist&&(a.mobile.ajaxEnabled=!1),e.addClass("ui-mobile ui-mobile-rendering"),setTimeout(d,5e3),a.extend(a.mobile,{initializePage:function(){var b=a.mobile.path,e=a(":jqmData(role='page'), :jqmData(role='dialog')"),g=b.stripHash(b.stripQueryParams(b.parseLocation().hash)),h=a.mobile.path.parseLocation(),i=c.getElementById(g);e.length||(e=a("body").wrapInner("
").children(0)),e.each(function(){var b=a(this);b[0].getAttribute("data-"+a.mobile.ns+"url")||b.attr("data-"+a.mobile.ns+"url",b.attr("id")||h.pathname+h.search)}),a.mobile.firstPage=e.first(),a.mobile.pageContainer=a.mobile.firstPage.parent().addClass("ui-mobile-viewport").pagecontainer(),a.mobile.navreadyDeferred.resolve(),f.trigger("pagecontainercreate"),a.mobile.loading("show"),d(),a.mobile.hashListeningEnabled&&a.mobile.path.isHashValid(location.hash)&&(a(i).is(":jqmData(role='page')")||a.mobile.path.isPath(g)||g===a.mobile.dialogHashKey)?a.event.special.navigate.isPushStateEnabled()?(a.mobile.navigate.history.stack=[],a.mobile.navigate(a.mobile.path.isPath(location.hash)?location.hash:location.href)):f.trigger("hashchange",[!0]):(a.mobile.path.isHashValid(location.hash)&&(a.mobile.navigate.history.initialDst=g.replace("#","")),a.event.special.navigate.isPushStateEnabled()&&a.mobile.navigate.navigator.squash(b.parseLocation().href),a.mobile.changePage(a.mobile.firstPage,{transition:"none",reverse:!0,changeHash:!1,fromHashChange:!0}))}}),a(function(){a.support.inlineSVG(),a.mobile.hideUrlBar&&b.scrollTo(0,1),a.mobile.defaultHomeScroll=a.support.scrollTop&&1!==a.mobile.window.scrollTop()?1:0,a.mobile.autoInitializePage&&a.mobile.initializePage(),a.mobile.hideUrlBar&&f.load(a.mobile.silentScroll),a.support.cssPointerEvents||a.mobile.document.delegate(".ui-state-disabled,.ui-disabled","vclick",function(a){a.preventDefault(),a.stopImmediatePropagation()})}))}(a,this)});
+//# sourceMappingURL=jquery.mobile.min.map
\ No newline at end of file
diff --git a/bigbluebutton-client/resources/prod/lib/jquery.verto.js b/bigbluebutton-client/resources/prod/lib/jquery.verto.js
new file mode 100755
index 0000000000..0fd9fb846a
--- /dev/null
+++ b/bigbluebutton-client/resources/prod/lib/jquery.verto.js
@@ -0,0 +1,2729 @@
+
+/*
+ * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
+ * Copyright (C) 2005-2014, Anthony Minessale II
+ *
+ * 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 Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II
+ *
+ * jquery.verto.js - Main interface
+ *
+ */
+
+(function($) {
+ var sources = [];
+
+ var generateGUID = (typeof(window.crypto) !== 'undefined' && typeof(window.crypto.getRandomValues) !== 'undefined') ?
+ function() {
+ // If we have a cryptographically secure PRNG, use that
+ // http://stackoverflow.com/questions/6906916/collisions-when-generating-uuids-in-javascript
+ var buf = new Uint16Array(8);
+ window.crypto.getRandomValues(buf);
+ var S4 = function(num) {
+ var ret = num.toString(16);
+ while (ret.length < 4) {
+ ret = "0" + ret;
+ }
+ return ret;
+ };
+ return (S4(buf[0]) + S4(buf[1]) + "-" + S4(buf[2]) + "-" + S4(buf[3]) + "-" + S4(buf[4]) + "-" + S4(buf[5]) + S4(buf[6]) + S4(buf[7]));
+ }
+
+ :
+
+ function() {
+ // Otherwise, just use Math.random
+ // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0,
+ v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+ };
+
+ /// MASTER OBJ
+ $.verto = function(options, callbacks) {
+ var verto = this;
+
+ $.verto.saved.push(verto);
+
+ verto.options = $.extend({
+ login: null,
+ passwd: null,
+ socketUrl: null,
+ tag: null,
+ localTag: null,
+ videoParams: {},
+ audioParams: {},
+ loginParams: {},
+ deviceParams: {onResCheck: null},
+ userVariables: {},
+ iceServers: false,
+ ringSleep: 6000,
+ sessid: null
+ }, options);
+
+ if (verto.options.deviceParams.useCamera) {
+ $.FSRTC.getValidRes(verto.options.deviceParams.useCamera, verto.options.deviceParams.onResCheck);
+ }
+
+ if (!verto.options.deviceParams.useMic) {
+ verto.options.deviceParams.useMic = "any";
+ }
+
+ if (!verto.options.deviceParams.useSpeak) {
+ verto.options.deviceParams.useSpeak = "any";
+ }
+
+ if (verto.options.sessid) {
+ verto.sessid = verto.options.sessid;
+ } else {
+ verto.sessid = localStorage.getItem("verto_session_uuid") || generateGUID();
+ localStorage.setItem("verto_session_uuid", verto.sessid);
+ }
+
+ verto.dialogs = {};
+ verto.callbacks = callbacks || {};
+ verto.eventSUBS = {};
+
+ verto.rpcClient = new $.JsonRpcClient({
+ login: verto.options.login,
+ passwd: verto.options.passwd,
+ socketUrl: verto.options.socketUrl,
+ loginParams: verto.options.loginParams,
+ userVariables: verto.options.userVariables,
+ sessid: verto.sessid,
+ onmessage: function(e) {
+ return verto.handleMessage(e.eventData);
+ },
+ onWSConnect: function(o) {
+ o.call('login', {});
+ },
+ onWSLogin: function(success) {
+ if (verto.callbacks.onWSLogin) {
+ verto.callbacks.onWSLogin(verto, success);
+ }
+ },
+ onWSClose: function(success) {
+ if (verto.callbacks.onWSClose) {
+ verto.callbacks.onWSClose(verto, success);
+ }
+ verto.purge();
+ }
+ });
+
+ if (verto.options.ringFile && verto.options.tag) {
+ verto.ringer = $("#" + verto.options.tag);
+ }
+
+ verto.rpcClient.call('login', {});
+
+ };
+
+
+ $.verto.prototype.deviceParams = function(obj) {
+ var verto = this;
+
+ for (var i in obj) {
+ verto.options.deviceParams[i] = obj[i];
+ }
+
+ if (obj.useCamera) {
+ $.FSRTC.getValidRes(verto.options.deviceParams.useCamera, obj ? obj.onResCheck : undefined);
+ }
+ };
+
+ $.verto.prototype.videoParams = function(obj) {
+ var verto = this;
+
+ for (var i in obj) {
+ verto.options.videoParams[i] = obj[i];
+ }
+ };
+
+ $.verto.prototype.iceServers = function(obj) {
+ var verto = this;
+ verto.options.iceServers = obj;
+ };
+
+ $.verto.prototype.loginData = function(params) {
+ var verto = this;
+ verto.options.login = params.login;
+ verto.options.passwd = params.passwd;
+ verto.rpcClient.loginData(params);
+ };
+
+ $.verto.prototype.logout = function(msg) {
+ var verto = this;
+ verto.rpcClient.closeSocket();
+ if (verto.callbacks.onWSClose) {
+ verto.callbacks.onWSClose(verto, false);
+ }
+ verto.purge();
+ };
+
+ $.verto.prototype.login = function(msg) {
+ var verto = this;
+ verto.logout();
+ verto.rpcClient.call('login', {});
+ };
+
+ $.verto.prototype.message = function(msg) {
+ var verto = this;
+ var err = 0;
+
+ if (!msg.to) {
+ console.error("Missing To");
+ err++;
+ }
+
+ if (!msg.body) {
+ console.error("Missing Body");
+ err++;
+ }
+
+ if (err) {
+ return false;
+ }
+
+ verto.sendMethod("verto.info", {
+ msg: msg
+ });
+
+ return true;
+ };
+
+ $.verto.prototype.processReply = function(method, success, e) {
+ var verto = this;
+ var i;
+
+ //console.log("Response: " + method, success, e);
+
+ switch (method) {
+ case "verto.subscribe":
+ for (i in e.unauthorizedChannels) {
+ drop_bad(verto, e.unauthorizedChannels[i]);
+ }
+ for (i in e.subscribedChannels) {
+ mark_ready(verto, e.subscribedChannels[i]);
+ }
+
+ break;
+ case "verto.unsubscribe":
+ //console.error(e);
+ break;
+ }
+ };
+
+ $.verto.prototype.sendMethod = function(method, params) {
+ var verto = this;
+
+ verto.rpcClient.call(method, params,
+
+ function(e) {
+ /* Success */
+ verto.processReply(method, true, e);
+ },
+
+ function(e) {
+ /* Error */
+ verto.processReply(method, false, e);
+ });
+ };
+
+ function do_sub(verto, channel, obj) {
+
+ }
+
+ function drop_bad(verto, channel) {
+ console.error("drop unauthorized channel: " + channel);
+ delete verto.eventSUBS[channel];
+ }
+
+ function mark_ready(verto, channel) {
+ for (var j in verto.eventSUBS[channel]) {
+ verto.eventSUBS[channel][j].ready = true;
+ console.log("subscribed to channel: " + channel);
+ if (verto.eventSUBS[channel][j].readyHandler) {
+ verto.eventSUBS[channel][j].readyHandler(verto, channel);
+ }
+ }
+ }
+
+ var SERNO = 1;
+
+ function do_subscribe(verto, channel, subChannels, sparams) {
+ var params = sparams || {};
+
+ var local = params.local;
+
+ var obj = {
+ eventChannel: channel,
+ userData: params.userData,
+ handler: params.handler,
+ ready: false,
+ readyHandler: params.readyHandler,
+ serno: SERNO++
+ };
+
+ var isnew = false;
+
+ if (!verto.eventSUBS[channel]) {
+ verto.eventSUBS[channel] = [];
+ subChannels.push(channel);
+ isnew = true;
+ }
+
+ verto.eventSUBS[channel].push(obj);
+
+ if (local) {
+ obj.ready = true;
+ obj.local = true;
+ }
+
+ if (!isnew && verto.eventSUBS[channel][0].ready) {
+ obj.ready = true;
+ if (obj.readyHandler) {
+ obj.readyHandler(verto, channel);
+ }
+ }
+
+ return {
+ serno: obj.serno,
+ eventChannel: channel
+ };
+
+ }
+
+ $.verto.prototype.subscribe = function(channel, sparams) {
+ var verto = this;
+ var r = [];
+ var subChannels = [];
+ var params = sparams || {};
+
+ if (typeof(channel) === "string") {
+ r.push(do_subscribe(verto, channel, subChannels, params));
+ } else {
+ for (var i in channel) {
+ r.push(do_subscribe(verto, channel, subChannels, params));
+ }
+ }
+
+ if (subChannels.length) {
+ verto.sendMethod("verto.subscribe", {
+ eventChannel: subChannels.length == 1 ? subChannels[0] : subChannels,
+ subParams: params.subParams
+ });
+ }
+
+ return r;
+ };
+
+ $.verto.prototype.unsubscribe = function(handle) {
+ var verto = this;
+ var i;
+
+ if (!handle) {
+ for (i in verto.eventSUBS) {
+ if (verto.eventSUBS[i]) {
+ verto.unsubscribe(verto.eventSUBS[i]);
+ }
+ }
+ } else {
+ var unsubChannels = {};
+ var sendChannels = [];
+ var channel;
+
+ if (typeof(handle) == "string") {
+ delete verto.eventSUBS[handle];
+ unsubChannels[handle]++;
+ } else {
+ for (i in handle) {
+ if (typeof(handle[i]) == "string") {
+ channel = handle[i];
+ delete verto.eventSUBS[channel];
+ unsubChannels[channel]++;
+ } else {
+ var repl = [];
+ channel = handle[i].eventChannel;
+
+ for (var j in verto.eventSUBS[channel]) {
+ if (verto.eventSUBS[channel][j].serno == handle[i].serno) {} else {
+ repl.push(verto.eventSUBS[channel][j]);
+ }
+ }
+
+ verto.eventSUBS[channel] = repl;
+
+ if (verto.eventSUBS[channel].length === 0) {
+ delete verto.eventSUBS[channel];
+ unsubChannels[channel]++;
+ }
+ }
+ }
+ }
+
+ for (var u in unsubChannels) {
+ console.log("Sending Unsubscribe for: ", u);
+ sendChannels.push(u);
+ }
+
+ if (sendChannels.length) {
+ verto.sendMethod("verto.unsubscribe", {
+ eventChannel: sendChannels.length == 1 ? sendChannels[0] : sendChannels
+ });
+ }
+ }
+ };
+
+ $.verto.prototype.broadcast = function(channel, params) {
+ var verto = this;
+ var msg = {
+ eventChannel: channel,
+ data: {}
+ };
+ for (var i in params) {
+ msg.data[i] = params[i];
+ }
+ verto.sendMethod("verto.broadcast", msg);
+ };
+
+ $.verto.prototype.purge = function(callID) {
+ var verto = this;
+ var x = 0;
+ var i;
+
+ for (i in verto.dialogs) {
+ if (!x) {
+ console.log("purging dialogs");
+ }
+ x++;
+ verto.dialogs[i].setState($.verto.enum.state.purge);
+ }
+
+ for (i in verto.eventSUBS) {
+ if (verto.eventSUBS[i]) {
+ console.log("purging subscription: " + i);
+ delete verto.eventSUBS[i];
+ }
+ }
+ };
+
+ $.verto.prototype.hangup = function(callID) {
+ var verto = this;
+ if (callID) {
+ var dialog = verto.dialogs[callID];
+
+ if (dialog) {
+ dialog.hangup();
+ }
+ } else {
+ for (var i in verto.dialogs) {
+ verto.dialogs[i].hangup();
+ }
+ }
+ };
+
+ $.verto.prototype.newCall = function(args, callbacks) {
+ var verto = this;
+
+ if (!verto.rpcClient.socketReady()) {
+ console.error("Not Connected...");
+ return;
+ }
+
+ var dialog = new $.verto.dialog($.verto.enum.direction.outbound, this, args);
+
+ dialog.invite();
+
+ if (callbacks) {
+ dialog.callbacks = callbacks;
+ }
+
+ return dialog;
+ };
+
+ $.verto.prototype.handleMessage = function(data) {
+ var verto = this;
+
+ if (!(data && data.method)) {
+ console.error("Invalid Data", data);
+ return;
+ }
+
+ if (data.params.callID) {
+ var dialog = verto.dialogs[data.params.callID];
+
+ if (data.method === "verto.attach" && dialog) {
+ delete dialog.verto.dialogs[dialog.callID];
+ dialog.rtc.stop();
+ dialog = null;
+ }
+
+ if (dialog) {
+
+ switch (data.method) {
+ case 'verto.bye':
+ dialog.hangup(data.params);
+ break;
+ case 'verto.answer':
+ dialog.handleAnswer(data.params);
+ break;
+ case 'verto.media':
+ dialog.handleMedia(data.params);
+ break;
+ case 'verto.display':
+ dialog.handleDisplay(data.params);
+ break;
+ case 'verto.info':
+ dialog.handleInfo(data.params);
+ break;
+ default:
+ console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", dialog, data.method);
+ break;
+ }
+ } else {
+
+ switch (data.method) {
+ case 'verto.attach':
+ data.params.attach = true;
+
+ if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) {
+ data.params.useVideo = true;
+ }
+
+ if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) {
+ data.params.useStereo = true;
+ }
+
+ dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params);
+ dialog.setState($.verto.enum.state.recovering);
+
+ break;
+ case 'verto.invite':
+
+ if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) {
+ data.params.wantVideo = true;
+ }
+
+ if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) {
+ data.params.useStereo = true;
+ }
+
+ dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params);
+ break;
+ default:
+ console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED");
+ break;
+ }
+ }
+
+ return {
+ method: data.method
+ };
+ } else {
+ switch (data.method) {
+ case 'verto.punt':
+ verto.purge();
+ verto.logout();
+ break;
+ case 'verto.event':
+ var list = null;
+ var key = null;
+
+ if (data.params) {
+ key = data.params.eventChannel;
+ }
+
+ if (key) {
+ list = verto.eventSUBS[key];
+
+ if (!list) {
+ list = verto.eventSUBS[key.split(".")[0]];
+ }
+ }
+
+ if (!list && key && key === verto.sessid) {
+ if (verto.callbacks.onMessage) {
+ verto.callbacks.onMessage(verto, null, $.verto.enum.message.pvtEvent, data.params);
+ }
+ } else if (!list && key && verto.dialogs[key]) {
+ verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent, data.params);
+ } else if (!list) {
+ if (!key) {
+ key = "UNDEFINED";
+ }
+ console.error("UNSUBBED or invalid EVENT " + key + " IGNORED");
+ } else {
+ for (var i in list) {
+ var sub = list[i];
+
+ if (!sub || !sub.ready) {
+ console.error("invalid EVENT for " + key + " IGNORED");
+ } else if (sub.handler) {
+ sub.handler(verto, data.params, sub.userData);
+ } else if (verto.callbacks.onEvent) {
+ verto.callbacks.onEvent(verto, data.params, sub.userData);
+ } else {
+ console.log("EVENT:", data.params);
+ }
+ }
+ }
+
+ break;
+
+ case "verto.info":
+ if (verto.callbacks.onMessage) {
+ verto.callbacks.onMessage(verto, null, $.verto.enum.message.info, data.params.msg);
+ }
+ //console.error(data);
+ console.debug("MESSAGE from: " + data.params.msg.from, data.params.msg.body);
+
+ break;
+
+ default:
+ console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", data.method);
+ break;
+ }
+ }
+ };
+
+ var del_array = function(array, name) {
+ var r = [];
+ var len = array.length;
+
+ for (var i = 0; i < len; i++) {
+ if (array[i] != name) {
+ r.push(array[i]);
+ }
+ }
+
+ return r;
+ };
+
+ var hashArray = function() {
+ var vha = this;
+
+ var hash = {};
+ var array = [];
+
+ vha.reorder = function(a) {
+ array = a;
+ var h = hash;
+ hash = {};
+
+ var len = array.length;
+
+ for (var i = 0; i < len; i++) {
+ var key = array[i];
+ if (h[key]) {
+ hash[key] = h[key];
+ delete h[key];
+ }
+ }
+ h = undefined;
+ };
+
+ vha.clear = function() {
+ hash = undefined;
+ array = undefined;
+ hash = {};
+ array = [];
+ };
+
+ vha.add = function(name, val, insertAt) {
+ var redraw = false;
+
+ if (!hash[name]) {
+ if (insertAt === undefined || insertAt < 0 || insertAt >= array.length) {
+ array.push(name);
+ } else {
+ var x = 0;
+ var n = [];
+ var len = array.length;
+
+ for (var i = 0; i < len; i++) {
+ if (x++==insertAt) {
+ n.push(name);
+ }
+ n.push(array[i]);
+ }
+
+ array = undefined;
+ array = n;
+ n = undefined;
+ redraw = true;
+ }
+ }
+
+ hash[name] = val;
+
+ return redraw;
+ };
+
+ vha.del = function(name) {
+ var r = false;
+
+ if (hash[name]) {
+ array = del_array(array, name);
+ delete hash[name];
+ r = true;
+ } else {
+ console.error("can't del nonexistant key " + name);
+ }
+
+ return r;
+ };
+
+ vha.get = function(name) {
+ return hash[name];
+ };
+
+ vha.order = function() {
+ return array;
+ };
+
+ vha.hash = function() {
+ return hash;
+ };
+
+ vha.indexOf = function(name) {
+ var len = array.length;
+
+ for (var i = 0; i < len; i++) {
+ if (array[i] == name) {
+ return i;
+ }
+ }
+ };
+
+ vha.arrayLen = function() {
+ return array.length;
+ };
+
+ vha.asArray = function() {
+ var r = [];
+
+ var len = array.length;
+
+ for (var i = 0; i < len; i++) {
+ var key = array[i];
+ r.push(hash[key]);
+ }
+
+ return r;
+ };
+
+ vha.each = function(cb) {
+ var len = array.length;
+
+ for (var i = 0; i < len; i++) {
+ cb(array[i], hash[array[i]]);
+ }
+ };
+
+ vha.dump = function(html) {
+ var str = "";
+
+ vha.each(function(name, val) {
+ str += "name: " + name + " val: " + JSON.stringify(val) + (html ? "
" : "\n");
+ });
+
+ return str;
+ };
+
+ };
+
+ $.verto.liveArray = function(verto, context, name, config) {
+ var la = this;
+ var lastSerno = 0;
+ var binding = null;
+ var user_obj = config.userObj;
+ var local = false;
+
+ // Inherit methods of hashArray
+ hashArray.call(la);
+
+ // Save the hashArray add, del, reorder, clear methods so we can make our own.
+ la._add = la.add;
+ la._del = la.del;
+ la._reorder = la.reorder;
+ la._clear = la.clear;
+
+ la.context = context;
+ la.name = name;
+ la.user_obj = user_obj;
+
+ la.verto = verto;
+ la.broadcast = function(channel, obj) {
+ verto.broadcast(channel, obj);
+ };
+ la.errs = 0;
+
+ la.clear = function() {
+ la._clear();
+ lastSerno = 0;
+
+ if (la.onChange) {
+ la.onChange(la, {
+ action: "clear"
+ });
+ }
+ };
+
+ la.checkSerno = function(serno) {
+ if (serno < 0) {
+ return true;
+ }
+
+ if (lastSerno > 0 && serno != (lastSerno + 1)) {
+ if (la.onErr) {
+ la.onErr(la, {
+ lastSerno: lastSerno,
+ serno: serno
+ });
+ }
+ la.errs++;
+ console.debug(la.errs);
+ if (la.errs < 3) {
+ la.bootstrap(la.user_obj);
+ }
+ return false;
+ } else {
+ lastSerno = serno;
+ return true;
+ }
+ };
+
+ la.reorder = function(serno, a) {
+ if (la.checkSerno(serno)) {
+ la._reorder(a);
+ if (la.onChange) {
+ la.onChange(la, {
+ serno: serno,
+ action: "reorder"
+ });
+ }
+ }
+ };
+
+ la.init = function(serno, val, key, index) {
+ if (key === null || key === undefined) {
+ key = serno;
+ }
+ if (la.checkSerno(serno)) {
+ if (la.onChange) {
+ la.onChange(la, {
+ serno: serno,
+ action: "init",
+ index: index,
+ key: key,
+ data: val
+ });
+ }
+ }
+ };
+
+ la.bootObj = function(serno, val) {
+ if (la.checkSerno(serno)) {
+
+ //la.clear();
+ for (var i in val) {
+ la._add(val[i][0], val[i][1]);
+ }
+
+ if (la.onChange) {
+ la.onChange(la, {
+ serno: serno,
+ action: "bootObj",
+ data: val,
+ redraw: true
+ });
+ }
+ }
+ };
+
+ // @param serno La is the serial number for la particular request.
+ // @param key If looking at it as a hash table, la represents the key in the hashArray object where you want to store the val object.
+ // @param index If looking at it as an array, la represents the position in the array where you want to store the val object.
+ // @param val La is the object you want to store at the key or index location in the hash table / array.
+ la.add = function(serno, val, key, index) {
+ if (key === null || key === undefined) {
+ key = serno;
+ }
+ if (la.checkSerno(serno)) {
+ var redraw = la._add(key, val, index);
+ if (la.onChange) {
+ la.onChange(la, {
+ serno: serno,
+ action: "add",
+ index: index,
+ key: key,
+ data: val,
+ redraw: redraw
+ });
+ }
+ }
+ };
+
+ la.modify = function(serno, val, key, index) {
+ if (key === null || key === undefined) {
+ key = serno;
+ }
+ if (la.checkSerno(serno)) {
+ la._add(key, val, index);
+ if (la.onChange) {
+ la.onChange(la, {
+ serno: serno,
+ action: "modify",
+ key: key,
+ data: val,
+ index: index
+ });
+ }
+ }
+ };
+
+ la.del = function(serno, key, index) {
+ if (key === null || key === undefined) {
+ key = serno;
+ }
+ if (la.checkSerno(serno)) {
+ if (index === null || index < 0 || index === undefined) {
+ index = la.indexOf(key);
+ }
+ var ok = la._del(key);
+
+ if (ok && la.onChange) {
+ la.onChange(la, {
+ serno: serno,
+ action: "del",
+ key: key,
+ index: index
+ });
+ }
+ }
+ };
+
+ var eventHandler = function(v, e, la) {
+ var packet = e.data;
+
+ //console.error("READ:", packet);
+
+ if (packet.name != la.name) {
+ return;
+ }
+
+ switch (packet.action) {
+
+ case "init":
+ la.init(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex);
+ break;
+
+ case "bootObj":
+ la.bootObj(packet.wireSerno, packet.data);
+ break;
+ case "add":
+ la.add(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex);
+ break;
+
+ case "modify":
+ if (! (packet.arrIndex || packet.hashKey)) {
+ console.error("Invalid Packet", packet);
+ } else {
+ la.modify(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex);
+ }
+ break;
+ case "del":
+ if (! (packet.arrIndex || packet.hashKey)) {
+ console.error("Invalid Packet", packet);
+ } else {
+ la.del(packet.wireSerno, packet.hashKey, packet.arrIndex);
+ }
+ break;
+
+ case "clear":
+ la.clear();
+ break;
+
+ case "reorder":
+ la.reorder(packet.wireSerno, packet.order);
+ break;
+
+ default:
+ if (la.checkSerno(packet.wireSerno)) {
+ if (la.onChange) {
+ la.onChange(la, {
+ serno: packet.wireSerno,
+ action: packet.action,
+ data: packet.data
+ });
+ }
+ }
+ break;
+ }
+ };
+
+ if (la.context) {
+ binding = la.verto.subscribe(la.context, {
+ handler: eventHandler,
+ userData: la,
+ subParams: config.subParams
+ });
+ }
+
+ la.destroy = function() {
+ la._clear();
+ la.verto.unsubscribe(binding);
+ };
+
+ la.sendCommand = function(cmd, obj) {
+ var self = la;
+ self.broadcast(self.context, {
+ liveArray: {
+ command: cmd,
+ context: self.context,
+ name: self.name,
+ obj: obj
+ }
+ });
+ };
+
+ la.bootstrap = function(obj) {
+ var self = la;
+ la.sendCommand("bootstrap", obj);
+ //self.heartbeat();
+ };
+
+ la.changepage = function(obj) {
+ var self = la;
+ self.clear();
+ self.broadcast(self.context, {
+ liveArray: {
+ command: "changepage",
+ context: la.context,
+ name: la.name,
+ obj: obj
+ }
+ });
+ };
+
+ la.heartbeat = function(obj) {
+ var self = la;
+
+ var callback = function() {
+ self.heartbeat.call(self, obj);
+ };
+ self.broadcast(self.context, {
+ liveArray: {
+ command: "heartbeat",
+ context: self.context,
+ name: self.name,
+ obj: obj
+ }
+ });
+ self.hb_pid = setTimeout(callback, 30000);
+ };
+
+ la.bootstrap(la.user_obj);
+ };
+
+ $.verto.liveTable = function(verto, context, name, jq, config) {
+ var dt;
+ var la = new $.verto.liveArray(verto, context, name, {
+ subParams: config.subParams
+ });
+ var lt = this;
+
+ lt.liveArray = la;
+ lt.dataTable = dt;
+ lt.verto = verto;
+
+ lt.destroy = function() {
+ if (dt) {
+ dt.fnDestroy();
+ }
+ if (la) {
+ la.destroy();
+ }
+
+ dt = null;
+ la = null;
+ };
+
+ la.onErr = function(obj, args) {
+ console.error("Error: ", obj, args);
+ };
+
+ /* back compat so jsonstatus can always be enabled */
+ function genRow(data) {
+ if (typeof(data[4]) === "string" && data[4].indexOf("{") > -1) {
+ var tmp = $.parseJSON(data[4]);
+ data[4] = tmp.oldStatus;
+ data[5] = null;
+ }
+ return data;
+ }
+
+ function genArray(obj) {
+ var data = obj.asArray();
+
+ for (var i in data) {
+ data[i] = genRow(data[i]);
+ }
+
+ return data;
+ }
+
+
+ la.onChange = function(obj, args) {
+ var index = 0;
+ var iserr = 0;
+
+ if (!dt) {
+ if (!config.aoColumns) {
+ if (args.action != "init") {
+ return;
+ }
+
+ config.aoColumns = [];
+
+ for (var i in args.data) {
+ config.aoColumns.push({
+ "sTitle": args.data[i]
+ });
+ }
+ }
+
+ dt = jq.dataTable(config);
+ }
+
+ if (dt && (args.action == "del" || args.action == "modify")) {
+ index = args.index;
+
+ if (index === undefined && args.key) {
+ index = la.indexOf(args.key);
+ }
+
+ if (index === undefined) {
+ console.error("INVALID PACKET Missing INDEX\n", args);
+ return;
+ }
+ }
+
+ if (config.onChange) {
+ config.onChange(obj, args);
+ }
+
+ try {
+ switch (args.action) {
+ case "bootObj":
+ if (!args.data) {
+ console.error("missing data");
+ return;
+ }
+ dt.fnClearTable();
+ dt.fnAddData(genArray(obj));
+ dt.fnAdjustColumnSizing();
+ break;
+ case "add":
+ if (!args.data) {
+ console.error("missing data");
+ return;
+ }
+ if (args.redraw > -1) {
+ // specific position, more costly
+ dt.fnClearTable();
+ dt.fnAddData(genArray(obj));
+ } else {
+ dt.fnAddData(genRow(args.data));
+ }
+ dt.fnAdjustColumnSizing();
+ break;
+ case "modify":
+ if (!args.data) {
+ return;
+ }
+ //console.debug(args, index);
+ dt.fnUpdate(genRow(args.data), index);
+ dt.fnAdjustColumnSizing();
+ break;
+ case "del":
+ dt.fnDeleteRow(index);
+ dt.fnAdjustColumnSizing();
+ break;
+ case "clear":
+ dt.fnClearTable();
+ break;
+ case "reorder":
+ // specific position, more costly
+ dt.fnClearTable();
+ dt.fnAddData(genArray(obj));
+ break;
+ case "hide":
+ jq.hide();
+ break;
+
+ case "show":
+ jq.show();
+ break;
+
+ }
+ } catch(err) {
+ console.error("ERROR: " + err);
+ iserr++;
+ }
+
+ if (iserr) {
+ obj.errs++;
+ if (obj.errs < 3) {
+ obj.bootstrap(obj.user_obj);
+ }
+ } else {
+ obj.errs = 0;
+ }
+
+ };
+
+ la.onChange(la, {
+ action: "init"
+ });
+
+ };
+
+ var CONFMAN_SERNO = 1;
+
+ /*
+ Conference Manager without jQuery table.
+ */
+
+ $.verto.conf = function(verto, params) {
+ var conf = this;
+
+ conf.params = $.extend({
+ dialog: null,
+ hasVid: false,
+ laData: null,
+ onBroadcast: null,
+ onLaChange: null,
+ onLaRow: null
+ }, params);
+
+ conf.verto = verto;
+ conf.serno = CONFMAN_SERNO++;
+
+ createMainModeratorMethods();
+
+ verto.subscribe(conf.params.laData.modChannel, {
+ handler: function(v, e) {
+ if (conf.params.onBroadcast) {
+ conf.params.onBroadcast(verto, conf, e.data);
+ }
+ }
+ });
+
+ verto.subscribe(conf.params.laData.chatChannel, {
+ handler: function(v, e) {
+ if (typeof(conf.params.chatCallback) === "function") {
+ conf.params.chatCallback(v,e);
+ }
+ }
+ });
+ };
+
+ $.verto.conf.prototype.modCommand = function(cmd, id, value) {
+ var conf = this;
+
+ conf.verto.rpcClient.call("verto.broadcast", {
+ "eventChannel": conf.params.laData.modChannel,
+ "data": {
+ "application": "conf-control",
+ "command": cmd,
+ "id": id,
+ "value": value
+ }
+ });
+ };
+
+ $.verto.conf.prototype.destroy = function() {
+ var conf = this;
+
+ conf.destroyed = true;
+ conf.params.onBroadcast(conf.verto, conf, 'destroy');
+
+ if (conf.params.laData.modChannel) {
+ conf.verto.unsubscribe(conf.params.laData.modChannel);
+ }
+
+ if (conf.params.laData.chatChannel) {
+ conf.verto.unsubscribe(conf.params.laData.chatChannel);
+ }
+ };
+
+ function createMainModeratorMethods() {
+ $.verto.conf.prototype.listVideoLayouts = function() {
+ this.modCommand("list-videoLayouts", null, null);
+ };
+
+ $.verto.conf.prototype.play = function(file) {
+ this.modCommand("play", null, file);
+ };
+
+ $.verto.conf.prototype.stop = function() {
+ this.modCommand("stop", null, "all");
+ };
+
+ $.verto.conf.prototype.record = function(file) {
+ this.modCommand("recording", null, ["start", file]);
+ };
+
+ $.verto.conf.prototype.stopRecord = function() {
+ this.modCommand("recording", null, ["stop", "all"]);
+ };
+
+ $.verto.conf.prototype.snapshot = function(file) {
+ if (!this.params.hasVid) {
+ throw 'Conference has no video';
+ }
+ this.modCommand("vid-write-png", null, file);
+ };
+
+ $.verto.conf.prototype.setVideoLayout = function(layout) {
+ if (!this.params.hasVid) {
+ throw 'Conference has no video';
+ }
+ this.modCommand("vid-layout", null, layout);
+ };
+
+ $.verto.conf.prototype.kick = function(memberID) {
+ this.modCommand("kick", parseInt(memberID));
+ };
+
+ $.verto.conf.prototype.muteMic = function(memberID) {
+ this.modCommand("tmute", parseInt(memberID));
+ };
+
+ $.verto.conf.prototype.muteVideo = function(memberID) {
+ if (!this.params.hasVid) {
+ throw 'Conference has no video';
+ }
+ this.modCommand("tvmute", parseInt(memberID));
+ };
+
+ $.verto.conf.prototype.presenter = function(memberID) {
+ if (!this.params.hasVid) {
+ throw 'Conference has no video';
+ }
+ this.modCommand("vid-res-id", parseInt(memberID), "presenter");
+ };
+
+ $.verto.conf.prototype.videoFloor = function(memberID) {
+ if (!this.params.hasVid) {
+ throw 'Conference has no video';
+ }
+ this.modCommand("vid-floor", parseInt(memberID), "force");
+ };
+
+ $.verto.conf.prototype.banner = function(memberID, text) {
+ if (!this.params.hasVid) {
+ throw 'Conference has no video';
+ }
+ this.modCommand("vid-banner", parseInt(memberID), escape(text));
+ };
+
+ $.verto.conf.prototype.volumeDown = function(memberID) {
+ this.modCommand("volume_out", parseInt(memberID), "down");
+ };
+
+ $.verto.conf.prototype.volumeUp = function(memberID) {
+ this.modCommand("volume_out", parseInt(memberID), "up");
+ };
+
+ $.verto.conf.prototype.gainDown = function(memberID) {
+ this.modCommand("volume_in", parseInt(memberID), "down");
+ };
+
+ $.verto.conf.prototype.gainUp = function(memberID) {
+ this.modCommand("volume_in", parseInt(memberID), "up");
+ };
+
+ $.verto.conf.prototype.transfer = function(memberID, exten) {
+ this.modCommand("transfer", parseInt(memberID), exten);
+ };
+
+ $.verto.conf.prototype.sendChat = function(message, type) {
+ var conf = this;
+ conf.verto.rpcClient.call("verto.broadcast", {
+ "eventChannel": conf.params.laData.chatChannel,
+ "data": {
+ "action": "send",
+ "message": message,
+ "type": type
+ }
+ });
+ };
+
+ }
+
+ $.verto.modfuncs = {};
+
+ $.verto.confMan = function(verto, params) {
+ var confMan = this;
+
+ confMan.params = $.extend({
+ tableID: null,
+ statusID: null,
+ mainModID: null,
+ dialog: null,
+ hasVid: false,
+ laData: null,
+ onBroadcast: null,
+ onLaChange: null,
+ onLaRow: null
+ }, params);
+
+ confMan.verto = verto;
+ confMan.serno = CONFMAN_SERNO++;
+ confMan.canvasCount = confMan.params.laData.canvasCount;
+
+ function genMainMod(jq) {
+ var play_id = "play_" + confMan.serno;
+ var stop_id = "stop_" + confMan.serno;
+ var recording_id = "recording_" + confMan.serno;
+ var snapshot_id = "snapshot_" + confMan.serno;
+ var rec_stop_id = "recording_stop" + confMan.serno;
+ var div_id = "confman_" + confMan.serno;
+
+ var html = "
" +
+ "" +
+ "" +
+ "" +
+ "" +
+ (confMan.params.hasVid ? "" : "") +
+ "
";
+
+ jq.html(html);
+
+ $.verto.modfuncs.change_video_layout = function(id, canvas_id) {
+ var val = $("#" + id + " option:selected").text();
+ if (val !== "none") {
+ confMan.modCommand("vid-layout", null, [val, canvas_id]);
+ }
+ };
+
+ if (confMan.params.hasVid) {
+ for (var j = 0; j < confMan.canvasCount; j++) {
+ var vlayout_id = "confman_vid_layout_" + j + "_" + confMan.serno;
+ var vlselect_id = "confman_vl_select_" + j + "_" + confMan.serno;
+
+
+ var vlhtml = "
" +
+ "Video Layout Canvas " + (j+1) +
+ " " +
+ "
";
+ jq.append(vlhtml);
+ }
+
+ $("#" + snapshot_id).click(function() {
+ var file = prompt("Please enter file name", "");
+ if (file) {
+ confMan.modCommand("vid-write-png", null, file);
+ }
+ });
+ }
+
+ $("#" + play_id).click(function() {
+ var file = prompt("Please enter file name", "");
+ if (file) {
+ confMan.modCommand("play", null, file);
+ }
+ });
+
+ $("#" + stop_id).click(function() {
+ confMan.modCommand("stop", null, "all");
+ });
+
+ $("#" + recording_id).click(function() {
+ var file = prompt("Please enter file name", "");
+ if (file) {
+ confMan.modCommand("recording", null, ["start", file]);
+ }
+ });
+
+ $("#" + rec_stop_id).click(function() {
+ confMan.modCommand("recording", null, ["stop", "all"]);
+ });
+
+ }
+
+ function genControls(jq, rowid) {
+ var x = parseInt(rowid);
+ var kick_id = "kick_" + x;
+ var canvas_in_next_id = "canvas_in_next_" + x;
+ var canvas_in_prev_id = "canvas_in_prev_" + x;
+ var canvas_out_next_id = "canvas_out_next_" + x;
+ var canvas_out_prev_id = "canvas_out_prev_" + x;
+
+ var canvas_in_set_id = "canvas_in_set_" + x;
+ var canvas_out_set_id = "canvas_out_set_" + x;
+
+ var layer_set_id = "layer_set_" + x;
+ var layer_next_id = "layer_next_" + x;
+ var layer_prev_id = "layer_prev_" + x;
+
+ var tmute_id = "tmute_" + x;
+ var tvmute_id = "tvmute_" + x;
+ var vbanner_id = "vbanner_" + x;
+ var tvpresenter_id = "tvpresenter_" + x;
+ var tvfloor_id = "tvfloor_" + x;
+ var box_id = "box_" + x;
+ var gainup_id = "gain_in_up" + x;
+ var gaindn_id = "gain_in_dn" + x;
+ var volup_id = "vol_in_up" + x;
+ var voldn_id = "vol_in_dn" + x;
+ var transfer_id = "transfer" + x;
+
+
+ var html = "";
+
+ html += "General Controls
";
+
+ html += "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+
+ if (confMan.params.hasVid) {
+ html += "
Video Controls
";
+
+
+ html += "" +
+ "" +
+ "" +
+ "";
+
+ if (confMan.canvasCount > 1) {
+ html += "
Canvas Controls
" +
+ "" +
+ "" +
+ "" +
+
+ "
" +
+
+ "" +
+ "" +
+ "";
+ }
+
+ html += "
" +
+
+ "" +
+ "" +
+ "" +
+
+
+
+ "";
+ }
+
+ jq.html(html);
+
+
+ if (!jq.data("mouse")) {
+ $("#" + box_id).hide();
+ }
+
+ jq.mouseover(function(e) {
+ jq.data({"mouse": true});
+ $("#" + box_id).show();
+ });
+
+ jq.mouseout(function(e) {
+ jq.data({"mouse": false});
+ $("#" + box_id).hide();
+ });
+
+ $("#" + transfer_id).click(function() {
+ var xten = prompt("Enter Extension");
+ if (xten) {
+ confMan.modCommand("transfer", x, xten);
+ }
+ });
+
+ $("#" + kick_id).click(function() {
+ confMan.modCommand("kick", x);
+ });
+
+
+ $("#" + layer_set_id).click(function() {
+ var cid = prompt("Please enter layer ID", "");
+ if (cid) {
+ confMan.modCommand("vid-layer", x, cid);
+ }
+ });
+
+ $("#" + layer_next_id).click(function() {
+ confMan.modCommand("vid-layer", x, "next");
+ });
+ $("#" + layer_prev_id).click(function() {
+ confMan.modCommand("vid-layer", x, "prev");
+ });
+
+ $("#" + canvas_in_set_id).click(function() {
+ var cid = prompt("Please enter canvas ID", "");
+ if (cid) {
+ confMan.modCommand("vid-canvas", x, cid);
+ }
+ });
+
+ $("#" + canvas_out_set_id).click(function() {
+ var cid = prompt("Please enter canvas ID", "");
+ if (cid) {
+ confMan.modCommand("vid-watching-canvas", x, cid);
+ }
+ });
+
+ $("#" + canvas_in_next_id).click(function() {
+ confMan.modCommand("vid-canvas", x, "next");
+ });
+ $("#" + canvas_in_prev_id).click(function() {
+ confMan.modCommand("vid-canvas", x, "prev");
+ });
+
+
+ $("#" + canvas_out_next_id).click(function() {
+ confMan.modCommand("vid-watching-canvas", x, "next");
+ });
+ $("#" + canvas_out_prev_id).click(function() {
+ confMan.modCommand("vid-watching-canvas", x, "prev");
+ });
+
+ $("#" + tmute_id).click(function() {
+ confMan.modCommand("tmute", x);
+ });
+
+ if (confMan.params.hasVid) {
+ $("#" + tvmute_id).click(function() {
+ confMan.modCommand("tvmute", x);
+ });
+ $("#" + tvpresenter_id).click(function() {
+ confMan.modCommand("vid-res-id", x, "presenter");
+ });
+ $("#" + tvfloor_id).click(function() {
+ confMan.modCommand("vid-floor", x, "force");
+ });
+ $("#" + vbanner_id).click(function() {
+ var text = prompt("Please enter text", "");
+ if (text) {
+ confMan.modCommand("vid-banner", x, escape(text));
+ }
+ });
+ }
+
+ $("#" + gainup_id).click(function() {
+ confMan.modCommand("volume_in", x, "up");
+ });
+
+ $("#" + gaindn_id).click(function() {
+ confMan.modCommand("volume_in", x, "down");
+ });
+
+ $("#" + volup_id).click(function() {
+ confMan.modCommand("volume_out", x, "up");
+ });
+
+ $("#" + voldn_id).click(function() {
+ confMan.modCommand("volume_out", x, "down");
+ });
+
+ return html;
+ }
+
+ var atitle = "";
+ var awidth = 0;
+
+ //$(".jsDataTable").width(confMan.params.hasVid ? "900px" : "800px");
+
+ verto.subscribe(confMan.params.laData.chatChannel, {
+ handler: function(v, e) {
+ if (typeof(confMan.params.chatCallback) === "function") {
+ confMan.params.chatCallback(v,e);
+ }
+ }
+ });
+
+ if (confMan.params.laData.role === "moderator") {
+ atitle = "Action";
+ awidth = 600;
+
+ if (confMan.params.mainModID) {
+ genMainMod($(confMan.params.mainModID));
+ $(confMan.params.displayID).html("Moderator Controls Ready
");
+ } else {
+ $(confMan.params.mainModID).html("");
+ }
+
+ verto.subscribe(confMan.params.laData.modChannel, {
+ handler: function(v, e) {
+ //console.error("MODDATA:", e.data);
+ if (confMan.params.onBroadcast) {
+ confMan.params.onBroadcast(verto, confMan, e.data);
+ }
+
+ if (e.data["conf-command"] === "list-videoLayouts") {
+ for (var j = 0; j < confMan.canvasCount; j++) {
+ var vlselect_id = "#confman_vl_select_" + j + "_" + confMan.serno;
+ var vlayout_id = "#confman_vid_layout_" + j + "_" + confMan.serno;
+
+ var x = 0;
+ var options;
+
+ $(vlselect_id).selectmenu({});
+ $(vlselect_id).selectmenu("enable");
+ $(vlselect_id).empty();
+
+ $(vlselect_id).append(new Option("Choose a Layout", "none"));
+
+ if (e.data.responseData) {
+ var rdata = [];
+
+ for (var i in e.data.responseData) {
+ rdata.push(e.data.responseData[i].name);
+ }
+
+ options = rdata.sort(function(a, b) {
+ var ga = a.substring(0, 6) == "group:" ? true : false;
+ var gb = b.substring(0, 6) == "group:" ? true : false;
+
+ if ((ga || gb) && ga != gb) {
+ return ga ? -1 : 1;
+ }
+
+ return ( ( a == b ) ? 0 : ( ( a > b ) ? 1 : -1 ) );
+ });
+
+ for (var i in options) {
+ $(vlselect_id).append(new Option(options[i], options[i]));
+ x++;
+ }
+ }
+
+ if (x) {
+ $(vlselect_id).selectmenu('refresh', true);
+ } else {
+ $(vlayout_id).hide();
+ }
+ }
+ } else {
+
+ if (!confMan.destroyed && confMan.params.displayID) {
+ $(confMan.params.displayID).html(e.data.response + "
");
+ if (confMan.lastTimeout) {
+ clearTimeout(confMan.lastTimeout);
+ confMan.lastTimeout = 0;
+ }
+ confMan.lastTimeout = setTimeout(function() { $(confMan.params.displayID).html(confMan.destroyed ? "" : "Moderator Controls Ready
");}, 4000);
+ }
+ }
+ }
+ });
+
+
+ if (confMan.params.hasVid) {
+ confMan.modCommand("list-videoLayouts", null, null);
+ }
+ }
+
+ var row_callback = null;
+
+ if (confMan.params.laData.role === "moderator") {
+ row_callback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
+ if (!aData[5]) {
+ var $row = $('td:eq(5)', nRow);
+ genControls($row, aData);
+
+ if (confMan.params.onLaRow) {
+ confMan.params.onLaRow(verto, confMan, $row, aData);
+ }
+ }
+ };
+ }
+
+ confMan.lt = new $.verto.liveTable(verto, confMan.params.laData.laChannel, confMan.params.laData.laName, $(confMan.params.tableID), {
+ subParams: {
+ callID: confMan.params.dialog ? confMan.params.dialog.callID : null
+ },
+
+ "onChange": function(obj, args) {
+ $(confMan.params.statusID).text("Conference Members: " + " (" + obj.arrayLen() + " Total)");
+ if (confMan.params.onLaChange) {
+ confMan.params.onLaChange(verto, confMan, $.verto.enum.confEvent.laChange, obj, args);
+ }
+ },
+
+ "aaData": [],
+ "aoColumns": [
+ {
+ "sTitle": "ID",
+ "sWidth": "50"
+ },
+ {
+ "sTitle": "Number",
+ "sWidth": "250"
+ },
+ {
+ "sTitle": "Name",
+ "sWidth": "250"
+ },
+ {
+ "sTitle": "Codec",
+ "sWidth": "100"
+ },
+ {
+ "sTitle": "Status",
+ "sWidth": confMan.params.hasVid ? "200px" : "150px"
+ },
+ {
+ "sTitle": atitle,
+ "sWidth": awidth,
+ }
+ ],
+ "bAutoWidth": true,
+ "bDestroy": true,
+ "bSort": false,
+ "bInfo": false,
+ "bFilter": false,
+ "bLengthChange": false,
+ "bPaginate": false,
+ "iDisplayLength": 1400,
+
+ "oLanguage": {
+ "sEmptyTable": "The Conference is Empty....."
+ },
+
+ "fnRowCallback": row_callback
+
+ });
+ };
+
+ $.verto.confMan.prototype.modCommand = function(cmd, id, value) {
+ var confMan = this;
+
+ confMan.verto.rpcClient.call("verto.broadcast", {
+ "eventChannel": confMan.params.laData.modChannel,
+ "data": {
+ "application": "conf-control",
+ "command": cmd,
+ "id": id,
+ "value": value
+ }
+ });
+ };
+
+ $.verto.confMan.prototype.sendChat = function(message, type) {
+ var confMan = this;
+ confMan.verto.rpcClient.call("verto.broadcast", {
+ "eventChannel": confMan.params.laData.chatChannel,
+ "data": {
+ "action": "send",
+ "message": message,
+ "type": type
+ }
+ });
+ };
+
+
+ $.verto.confMan.prototype.destroy = function() {
+ var confMan = this;
+
+ confMan.destroyed = true;
+
+ if (confMan.lt) {
+ confMan.lt.destroy();
+ }
+
+ if (confMan.params.laData.chatChannel) {
+ confMan.verto.unsubscribe(confMan.params.laData.chatChannel);
+ }
+
+ if (confMan.params.laData.modChannel) {
+ confMan.verto.unsubscribe(confMan.params.laData.modChannel);
+ }
+
+ if (confMan.params.mainModID) {
+ $(confMan.params.mainModID).html("");
+ }
+ };
+
+ $.verto.dialog = function(direction, verto, params) {
+ var dialog = this;
+
+ dialog.params = $.extend({
+ useVideo: verto.options.useVideo,
+ useStereo: verto.options.useStereo,
+ screenShare: false,
+ useCamera: verto.options.deviceParams.useCamera,
+ useMic: verto.options.deviceParams.useMic,
+ useSpeak: verto.options.deviceParams.useSpeak,
+ tag: verto.options.tag,
+ localTag: verto.options.localTag,
+ login: verto.options.login,
+ videoParams: verto.options.videoParams
+ }, params);
+
+ dialog.verto = verto;
+ dialog.direction = direction;
+ dialog.lastState = null;
+ dialog.state = dialog.lastState = $.verto.enum.state.new;
+ dialog.callbacks = verto.callbacks;
+ dialog.answered = false;
+ dialog.attach = params.attach || false;
+ dialog.screenShare = params.screenShare || false;
+ dialog.useCamera = dialog.params.useCamera;
+ dialog.useMic = dialog.params.useMic;
+ dialog.useSpeak = dialog.params.useSpeak;
+
+ if (dialog.params.callID) {
+ dialog.callID = dialog.params.callID;
+ } else {
+ dialog.callID = dialog.params.callID = generateGUID();
+ }
+
+ if (dialog.params.tag) {
+ dialog.audioStream = document.getElementById(dialog.params.tag);
+
+ if (dialog.params.useVideo) {
+ dialog.videoStream = dialog.audioStream;
+ }
+ } //else conjure one TBD
+
+ if (dialog.params.localTag) {
+ dialog.localVideo = document.getElementById(dialog.params.localTag);
+ }
+
+ dialog.verto.dialogs[dialog.callID] = dialog;
+
+ var RTCcallbacks = {};
+
+ if (dialog.direction == $.verto.enum.direction.inbound) {
+ if (dialog.params.display_direction === "outbound") {
+ dialog.params.remote_caller_id_name = dialog.params.caller_id_name;
+ dialog.params.remote_caller_id_number = dialog.params.caller_id_number;
+ } else {
+ dialog.params.remote_caller_id_name = dialog.params.callee_id_name;
+ dialog.params.remote_caller_id_number = dialog.params.callee_id_number;
+ }
+
+ if (!dialog.params.remote_caller_id_name) {
+ dialog.params.remote_caller_id_name = "Nobody";
+ }
+
+ if (!dialog.params.remote_caller_id_number) {
+ dialog.params.remote_caller_id_number = "UNKNOWN";
+ }
+
+ RTCcallbacks.onMessage = function(rtc, msg) {
+ console.debug(msg);
+ };
+
+ RTCcallbacks.onAnswerSDP = function(rtc, sdp) {
+ console.error("answer sdp", sdp);
+ };
+ } else {
+ dialog.params.remote_caller_id_name = "Outbound Call";
+ dialog.params.remote_caller_id_number = dialog.params.destination_number;
+ }
+
+ RTCcallbacks.onICESDP = function(rtc) {
+ console.log("RECV " + rtc.type + " SDP", rtc.mediaData.SDP);
+
+ if (dialog.state == $.verto.enum.state.requesting || dialog.state == $.verto.enum.state.answering || dialog.state == $.verto.enum.state.active) {
+ location.reload();
+ return;
+ }
+
+ if (rtc.type == "offer") {
+ if (dialog.state == $.verto.enum.state.active) {
+ dialog.setState($.verto.enum.state.requesting);
+ dialog.sendMethod("verto.attach", {
+ sdp: rtc.mediaData.SDP
+ });
+ } else {
+ dialog.setState($.verto.enum.state.requesting);
+
+ dialog.sendMethod("verto.invite", {
+ sdp: rtc.mediaData.SDP
+ });
+ }
+ } else { //answer
+ dialog.setState($.verto.enum.state.answering);
+
+ dialog.sendMethod(dialog.attach ? "verto.attach" : "verto.answer", {
+ sdp: dialog.rtc.mediaData.SDP
+ });
+ }
+ };
+
+ RTCcallbacks.onICE = function(rtc) {
+ //console.log("cand", rtc.mediaData.candidate);
+ if (rtc.type == "offer") {
+ console.log("offer", rtc.mediaData.candidate);
+ return;
+ }
+ };
+
+ RTCcallbacks.onStream = function(rtc, stream) {
+ console.log("stream started");
+ };
+
+ RTCcallbacks.onError = function(e) {
+ console.error("ERROR:", e);
+ dialog.hangup({cause: "Device or Permission Error"});
+ };
+
+ dialog.rtc = new $.FSRTC({
+ callbacks: RTCcallbacks,
+ localVideo: dialog.screenShare ? null : dialog.localVideo,
+ useVideo: dialog.params.useVideo ? dialog.videoStream : null,
+ useAudio: dialog.audioStream,
+ useStereo: dialog.params.useStereo,
+ videoParams: dialog.params.videoParams,
+ audioParams: verto.options.audioParams,
+ iceServers: verto.options.iceServers,
+ screenShare: dialog.screenShare,
+ useCamera: dialog.useCamera,
+ useMic: dialog.useMic,
+ useSpeak: dialog.useSpeak
+ });
+
+ dialog.rtc.verto = dialog.verto;
+
+ if (dialog.direction == $.verto.enum.direction.inbound) {
+ if (dialog.attach) {
+ dialog.answer();
+ } else {
+ dialog.ring();
+ }
+ }
+ };
+
+ $.verto.dialog.prototype.invite = function() {
+ var dialog = this;
+ dialog.rtc.call();
+ };
+
+ $.verto.dialog.prototype.sendMethod = function(method, obj) {
+ var dialog = this;
+ obj.dialogParams = {};
+
+ for (var i in dialog.params) {
+ if (i == "sdp" && method != "verto.invite" && method != "verto.attach") {
+ continue;
+ }
+
+ obj.dialogParams[i] = dialog.params[i];
+ }
+
+ dialog.verto.rpcClient.call(method, obj,
+
+ function(e) {
+ /* Success */
+ dialog.processReply(method, true, e);
+ },
+
+ function(e) {
+ /* Error */
+ dialog.processReply(method, false, e);
+ });
+ };
+
+ function checkStateChange(oldS, newS) {
+
+ if (newS == $.verto.enum.state.purge || $.verto.enum.states[oldS.name][newS.name]) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ // Attach audio output device to video element using device/sink ID.
+ function find_name(id) {
+ for (var i in $.verto.audioOutDevices) {
+ var source = $.verto.audioOutDevices[i];
+ if (source.id === id) {
+ return(source.label);
+ }
+ }
+
+ return id;
+ }
+
+ $.verto.dialog.prototype.setAudioPlaybackDevice = function(sinkId, callback, arg) {
+ var dialog = this;
+ var element = dialog.audioStream;
+
+ if (typeof element.sinkId !== 'undefined') {
+ var devname = find_name(sinkId);
+ console.info("Dialog: " + dialog.callID + " Setting speaker:", element, devname);
+
+ element.setSinkId(sinkId)
+ .then(function() {
+ console.log("Dialog: " + dialog.callID + ' Success, audio output device attached: ' + sinkId);
+ if (callback) {
+ callback(true, devname, arg);
+ }
+ })
+ .catch(function(error) {
+ var errorMessage = error;
+ if (error.name === 'SecurityError') {
+ errorMessage = "Dialog: " + dialog.callID + ' You need to use HTTPS for selecting audio output ' +
+ 'device: ' + error;
+ }
+ if (callback) {
+ callback(false, null, arg);
+ }
+ console.error(errorMessage);
+ });
+ } else {
+ console.warn("Dialog: " + dialog.callID + ' Browser does not support output device selection.');
+ if (callback) {
+ callback(false, null, arg);
+ }
+ }
+ }
+
+ $.verto.dialog.prototype.setState = function(state) {
+ var dialog = this;
+
+ if (dialog.state == $.verto.enum.state.ringing) {
+ dialog.stopRinging();
+ }
+
+ if (dialog.state == state || !checkStateChange(dialog.state, state)) {
+ console.error("Dialog " + dialog.callID + ": INVALID state change from " + dialog.state.name + " to " + state.name);
+ dialog.hangup();
+ return false;
+ }
+
+ console.log("Dialog " + dialog.callID + ": state change from " + dialog.state.name + " to " + state.name);
+
+ dialog.lastState = dialog.state;
+ dialog.state = state;
+
+ if (!dialog.causeCode) {
+ dialog.causeCode = 16;
+ }
+
+ if (!dialog.cause) {
+ dialog.cause = "NORMAL CLEARING";
+ }
+
+ if (dialog.callbacks.onDialogState) {
+ dialog.callbacks.onDialogState(this);
+ }
+
+ switch (dialog.state) {
+
+ case $.verto.enum.state.early:
+ case $.verto.enum.state.active:
+
+ var speaker = dialog.useSpeak;
+ console.info("Using Speaker: ", speaker);
+
+ if (speaker && speaker !== "any") {
+ setTimeout(function() {
+ dialog.setAudioPlaybackDevice(speaker);
+ }, 500);
+ }
+
+ break;
+
+ case $.verto.enum.state.trying:
+ setTimeout(function() {
+ if (dialog.state == $.verto.enum.state.trying) {
+ dialog.setState($.verto.enum.state.hangup);
+ }
+ }, 30000);
+ break;
+ case $.verto.enum.state.purge:
+ dialog.setState($.verto.enum.state.destroy);
+ break;
+ case $.verto.enum.state.hangup:
+
+ if (dialog.lastState.val > $.verto.enum.state.requesting.val && dialog.lastState.val < $.verto.enum.state.hangup.val) {
+ dialog.sendMethod("verto.bye", {});
+ }
+
+ dialog.setState($.verto.enum.state.destroy);
+ break;
+ case $.verto.enum.state.destroy:
+ delete dialog.verto.dialogs[dialog.callID];
+ if (dialog.params.screenShare) {
+ dialog.rtc.stopPeer();
+ } else {
+ dialog.rtc.stop();
+ }
+ break;
+ }
+
+ return true;
+ };
+
+ $.verto.dialog.prototype.processReply = function(method, success, e) {
+ var dialog = this;
+
+ //console.log("Response: " + method + " State:" + dialog.state.name, success, e);
+
+ switch (method) {
+
+ case "verto.answer":
+ case "verto.attach":
+ if (success) {
+ dialog.setState($.verto.enum.state.active);
+ } else {
+ dialog.hangup();
+ }
+ break;
+ case "verto.invite":
+ if (success) {
+ dialog.setState($.verto.enum.state.trying);
+ } else {
+ dialog.setState($.verto.enum.state.destroy);
+ }
+ break;
+
+ case "verto.bye":
+ dialog.hangup();
+ break;
+
+ case "verto.modify":
+ if (e.holdState) {
+ if (e.holdState == "held") {
+ if (dialog.state != $.verto.enum.state.held) {
+ dialog.setState($.verto.enum.state.held);
+ }
+ } else if (e.holdState == "active") {
+ if (dialog.state != $.verto.enum.state.active) {
+ dialog.setState($.verto.enum.state.active);
+ }
+ }
+ }
+
+ if (success) {}
+
+ break;
+
+ default:
+ break;
+ }
+
+ };
+
+ $.verto.dialog.prototype.hangup = function(params) {
+ var dialog = this;
+
+ if (params) {
+ if (params.causeCode) {
+ dialog.causeCode = params.causeCode;
+ }
+
+ if (params.cause) {
+ dialog.cause = params.cause;
+ }
+ }
+
+ if (dialog.state.val >= $.verto.enum.state.new.val && dialog.state.val < $.verto.enum.state.hangup.val) {
+ dialog.setState($.verto.enum.state.hangup);
+ } else if (dialog.state.val < $.verto.enum.state.destroy) {
+ dialog.setState($.verto.enum.state.destroy);
+ }
+ };
+
+ $.verto.dialog.prototype.stopRinging = function() {
+ var dialog = this;
+ if (dialog.verto.ringer) {
+ dialog.verto.ringer.stop();
+ }
+ };
+
+ $.verto.dialog.prototype.indicateRing = function() {
+ var dialog = this;
+
+ if (dialog.verto.ringer) {
+ dialog.verto.ringer.attr("src", dialog.verto.options.ringFile)[0].play();
+
+ setTimeout(function() {
+ dialog.stopRinging();
+ if (dialog.state == $.verto.enum.state.ringing) {
+ dialog.indicateRing();
+ }
+ },
+ dialog.verto.options.ringSleep);
+ }
+ };
+
+ $.verto.dialog.prototype.ring = function() {
+ var dialog = this;
+
+ dialog.setState($.verto.enum.state.ringing);
+ dialog.indicateRing();
+ };
+
+ $.verto.dialog.prototype.useVideo = function(on) {
+ var dialog = this;
+
+ dialog.params.useVideo = on;
+
+ if (on) {
+ dialog.videoStream = dialog.audioStream;
+ } else {
+ dialog.videoStream = null;
+ }
+
+ dialog.rtc.useVideo(dialog.videoStream, dialog.localVideo);
+
+ };
+
+ $.verto.dialog.prototype.setMute = function(what) {
+ var dialog = this;
+ return dialog.rtc.setMute(what);
+ };
+
+ $.verto.dialog.prototype.getMute = function() {
+ var dialog = this;
+ return dialog.rtc.getMute();
+ };
+
+ $.verto.dialog.prototype.setVideoMute = function(what) {
+ var dialog = this;
+ return dialog.rtc.setVideoMute(what);
+ };
+
+ $.verto.dialog.prototype.getVideoMute = function() {
+ var dialog = this;
+ return dialog.rtc.getVideoMute();
+ };
+
+ $.verto.dialog.prototype.useStereo = function(on) {
+ var dialog = this;
+
+ dialog.params.useStereo = on;
+ dialog.rtc.useStereo(on);
+ };
+
+ $.verto.dialog.prototype.dtmf = function(digits) {
+ var dialog = this;
+ if (digits) {
+ dialog.sendMethod("verto.info", {
+ dtmf: digits
+ });
+ }
+ };
+
+ $.verto.dialog.prototype.transfer = function(dest, params) {
+ var dialog = this;
+ if (dest) {
+ dialog.sendMethod("verto.modify", {
+ action: "transfer",
+ destination: dest,
+ params: params
+ });
+ }
+ };
+
+ $.verto.dialog.prototype.hold = function(params) {
+ var dialog = this;
+
+ dialog.sendMethod("verto.modify", {
+ action: "hold",
+ params: params
+ });
+ };
+
+ $.verto.dialog.prototype.unhold = function(params) {
+ var dialog = this;
+
+ dialog.sendMethod("verto.modify", {
+ action: "unhold",
+ params: params
+ });
+ };
+
+ $.verto.dialog.prototype.toggleHold = function(params) {
+ var dialog = this;
+
+ dialog.sendMethod("verto.modify", {
+ action: "toggleHold",
+ params: params
+ });
+ };
+
+ $.verto.dialog.prototype.message = function(msg) {
+ var dialog = this;
+ var err = 0;
+
+ msg.from = dialog.params.login;
+
+ if (!msg.to) {
+ console.error("Missing To");
+ err++;
+ }
+
+ if (!msg.body) {
+ console.error("Missing Body");
+ err++;
+ }
+
+ if (err) {
+ return false;
+ }
+
+ dialog.sendMethod("verto.info", {
+ msg: msg
+ });
+
+ return true;
+ };
+
+ $.verto.dialog.prototype.answer = function(params) {
+ var dialog = this;
+
+ if (!dialog.answered) {
+ if (!params) {
+ params = {};
+ }
+
+ params.sdp = dialog.params.sdp;
+
+ if (params) {
+ if (params.useVideo) {
+ dialog.useVideo(true);
+ }
+ dialog.params.callee_id_name = params.callee_id_name;
+ dialog.params.callee_id_number = params.callee_id_number;
+
+ if (params.useCamera) {
+ dialog.useCamera = params.useCamera;
+ }
+
+ if (params.useMic) {
+ dialog.useMic = params.useMic;
+ }
+
+ if (params.useSpeak) {
+ dialog.useSpeak = params.useSpeak;
+ }
+ }
+
+ dialog.rtc.createAnswer(params);
+ dialog.answered = true;
+ }
+ };
+
+ $.verto.dialog.prototype.handleAnswer = function(params) {
+ var dialog = this;
+
+ dialog.gotAnswer = true;
+
+ if (dialog.state.val >= $.verto.enum.state.active.val) {
+ return;
+ }
+
+ if (dialog.state.val >= $.verto.enum.state.early.val) {
+ dialog.setState($.verto.enum.state.active);
+ } else {
+ if (dialog.gotEarly) {
+ console.log("Dialog " + dialog.callID + " Got answer while still establishing early media, delaying...");
+ } else {
+ console.log("Dialog " + dialog.callID + " Answering Channel");
+ dialog.rtc.answer(params.sdp, function() {
+ dialog.setState($.verto.enum.state.active);
+ }, function(e) {
+ console.error(e);
+ dialog.hangup();
+ });
+ console.log("Dialog " + dialog.callID + "ANSWER SDP", params.sdp);
+ }
+ }
+
+
+ };
+
+ $.verto.dialog.prototype.cidString = function(enc) {
+ var dialog = this;
+ var party = dialog.params.remote_caller_id_name + (enc ? " <" : " <") + dialog.params.remote_caller_id_number + (enc ? ">" : ">");
+ return party;
+ };
+
+ $.verto.dialog.prototype.sendMessage = function(msg, params) {
+ var dialog = this;
+
+ if (dialog.callbacks.onMessage) {
+ dialog.callbacks.onMessage(dialog.verto, dialog, msg, params);
+ }
+ };
+
+ $.verto.dialog.prototype.handleInfo = function(params) {
+ var dialog = this;
+
+ dialog.sendMessage($.verto.enum.message.info, params.msg);
+ };
+
+ $.verto.dialog.prototype.handleDisplay = function(params) {
+ var dialog = this;
+
+ if (params.display_name) {
+ dialog.params.remote_caller_id_name = params.display_name;
+ }
+ if (params.display_number) {
+ dialog.params.remote_caller_id_number = params.display_number;
+ }
+
+ dialog.sendMessage($.verto.enum.message.display, {});
+ };
+
+ $.verto.dialog.prototype.handleMedia = function(params) {
+ var dialog = this;
+
+ if (dialog.state.val >= $.verto.enum.state.early.val) {
+ return;
+ }
+
+ dialog.gotEarly = true;
+
+ dialog.rtc.answer(params.sdp, function() {
+ console.log("Dialog " + dialog.callID + "Establishing early media");
+ dialog.setState($.verto.enum.state.early);
+
+ if (dialog.gotAnswer) {
+ console.log("Dialog " + dialog.callID + "Answering Channel");
+ dialog.setState($.verto.enum.state.active);
+ }
+ }, function(e) {
+ console.error(e);
+ dialog.hangup();
+ });
+ console.log("Dialog " + dialog.callID + "EARLY SDP", params.sdp);
+ };
+
+ $.verto.ENUM = function(s) {
+ var i = 0,
+ o = {};
+ s.split(" ").map(function(x) {
+ o[x] = {
+ name: x,
+ val: i++
+ };
+ });
+ return Object.freeze(o);
+ };
+
+ $.verto.enum = {};
+
+ $.verto.enum.states = Object.freeze({
+ new: {
+ requesting: 1,
+ recovering: 1,
+ ringing: 1,
+ destroy: 1,
+ answering: 1,
+ hangup: 1
+ },
+ requesting: {
+ trying: 1,
+ hangup: 1,
+ active: 1
+ },
+ recovering: {
+ answering: 1,
+ hangup: 1
+ },
+ trying: {
+ active: 1,
+ early: 1,
+ hangup: 1
+ },
+ ringing: {
+ answering: 1,
+ hangup: 1
+ },
+ answering: {
+ active: 1,
+ hangup: 1
+ },
+ active: {
+ answering: 1,
+ requesting: 1,
+ hangup: 1,
+ held: 1
+ },
+ held: {
+ hangup: 1,
+ active: 1
+ },
+ early: {
+ hangup: 1,
+ active: 1
+ },
+ hangup: {
+ destroy: 1
+ },
+ destroy: {},
+ purge: {
+ destroy: 1
+ }
+ });
+
+ $.verto.enum.state = $.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge");
+ $.verto.enum.direction = $.verto.ENUM("inbound outbound");
+ $.verto.enum.message = $.verto.ENUM("display info pvtEvent");
+
+ $.verto.enum = Object.freeze($.verto.enum);
+
+ $.verto.saved = [];
+
+ $.verto.unloadJobs = [];
+
+ $(window).bind('beforeunload', function() {
+ for (var f in $.verto.unloadJobs) {
+ $.verto.unloadJobs[f]();
+ }
+
+ for (var i in $.verto.saved) {
+ var verto = $.verto.saved[i];
+ if (verto) {
+ verto.purge();
+ verto.logout();
+ }
+ }
+
+ return $.verto.warnOnUnload;
+ });
+
+ $.verto.videoDevices = [];
+ $.verto.audioInDevices = [];
+ $.verto.audioOutDevices = [];
+
+ var checkDevices = function(runtime) {
+ console.info("enumerating devices");
+ var aud_in = [], aud_out = [], vid = [];
+
+ if ((!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) && MediaStreamTrack.getSources) {
+ MediaStreamTrack.getSources(function (media_sources) {
+ for (var i = 0; i < media_sources.length; i++) {
+
+ if (media_sources[i].kind == 'video') {
+ vid.push(media_sources[i]);
+ } else {
+ aud_in.push(media_sources[i]);
+ }
+ }
+
+ $.verto.videoDevices = vid;
+ $.verto.audioInDevices = aud_in;
+
+ console.info("Audio Devices", $.verto.audioInDevices);
+ console.info("Video Devices", $.verto.videoDevices);
+ runtime(true);
+ });
+ } else {
+ /* of course it's a totally different API CALL with different element names for the same exact thing */
+
+ if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
+ console.log("enumerateDevices() not supported.");
+ return;
+ }
+
+ // List cameras and microphones.
+
+ navigator.mediaDevices.enumerateDevices()
+ .then(function(devices) {
+ devices.forEach(function(device) {
+ console.log(device);
+
+ console.log(device.kind + ": " + device.label +
+ " id = " + device.deviceId);
+
+ if (device.kind === "videoinput") {
+ vid.push({id: device.deviceId, kind: "video", label: device.label});
+ } else if (device.kind === "audioinput") {
+ aud_in.push({id: device.deviceId, kind: "audio_in", label: device.label});
+ } else if (device.kind === "audiooutput") {
+ aud_out.push({id: device.deviceId, kind: "audio_out", label: device.label});
+ }
+ });
+
+
+ $.verto.videoDevices = vid;
+ $.verto.audioInDevices = aud_in;
+ $.verto.audioOutDevices = aud_out;
+
+ console.info("Audio IN Devices", $.verto.audioInDevices);
+ console.info("Audio Out Devices", $.verto.audioOutDevices);
+ console.info("Video Devices", $.verto.videoDevices);
+ runtime(true);
+
+ })
+ .catch(function(err) {
+ console.log(" Device Enumeration ERROR: " + err.name + ": " + err.message);
+ runtime(false);
+ });
+ }
+
+ };
+
+ $.verto.refreshDevices = function(runtime) {
+ checkDevices(runtime);
+ }
+
+ $.verto.init = function(obj, runtime) {
+ if (!obj) {
+ obj = {};
+ }
+
+ if (!obj.skipPermCheck && !obj.skipDeviceCheck) {
+ $.FSRTC.checkPerms(function(status) {
+ checkDevices(runtime);
+ }, true, true);
+ } else if (obj.skipPermCheck && !obj.skipDeviceCheck) {
+ checkDevices(runtime);
+ } else if (!obj.skipPermCheck && obj.skipDeviceCheck) {
+ $.FSRTC.checkPerms(function(status) {
+ runtime(status);
+ }, true, true);
+ } else {
+ runtime(null);
+ }
+
+ }
+
+ $.verto.genUUID = function () {
+ return generateGUID();
+ }
+
+
+})(jQuery);
diff --git a/bigbluebutton-client/resources/prod/lib/verto_extension.js b/bigbluebutton-client/resources/prod/lib/verto_extension.js
new file mode 100755
index 0000000000..685aabd0fd
--- /dev/null
+++ b/bigbluebutton-client/resources/prod/lib/verto_extension.js
@@ -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);
+ }
+}
diff --git a/bigbluebutton-client/resources/prod/lib/verto_extension_share.js b/bigbluebutton-client/resources/prod/lib/verto_extension_share.js
new file mode 100755
index 0000000000..8c8c74d7ce
--- /dev/null
+++ b/bigbluebutton-client/resources/prod/lib/verto_extension_share.js
@@ -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);
+ });
+}
diff --git a/bigbluebutton-client/resources/prod/locales.xml b/bigbluebutton-client/resources/prod/locales.xml
index 3fad42325b..f80e27d3e5 100755
--- a/bigbluebutton-client/resources/prod/locales.xml
+++ b/bigbluebutton-client/resources/prod/locales.xml
@@ -32,6 +32,7 @@
+
diff --git a/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml b/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
index fd6378595e..99881b885f 100755
--- a/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
+++ b/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
@@ -186,10 +186,6 @@ with BigBlueButton; if not, see .
if (ShortcutOptions.deskshareActive){
keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.share.desktop') as String)] = ShortcutEvent.SHARE_DESKTOP;
}
- if (ShortcutOptions.audioActive){
- keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.share.microphone') as String)] = ShortcutEvent.SHARE_MICROPHONE;
- keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.share.pauseRemoteStream') as String)] = ShortcutEvent.PAUSE_REMOTE_STREAM;
- }
}
public function hotkeyCapture():void{
diff --git a/bigbluebutton-client/src/DeskShareModule.mxml b/bigbluebutton-client/src/DeskShareModule.mxml
index 610d91b6cb..9576e2ecd7 100644
--- a/bigbluebutton-client/src/DeskShareModule.mxml
+++ b/bigbluebutton-client/src/DeskShareModule.mxml
@@ -20,45 +20,46 @@ with BigBlueButton; if not, see .
-->
-
-
-
+ creationComplete="onCreationComplete()">
+
+
+
.
+
+
+
+
@@ -102,11 +106,13 @@ with BigBlueButton; if not, see .
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.ConfigLoadedEvent;
import org.bigbluebutton.main.events.LoadConfigCommand;
+ import org.bigbluebutton.main.events.ConfigEvent;
import org.bigbluebutton.main.events.LogoutEvent;
import org.bigbluebutton.main.events.ModuleLoadEvent;
import org.bigbluebutton.main.events.PortTestEvent;
import org.bigbluebutton.main.events.SuccessfulLoginEvent;
import org.bigbluebutton.main.model.modules.ModulesProxy;
+ import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
]]>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/ConferenceParameters.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/ConferenceParameters.as
index 17d9f002f0..d94bb513fa 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/ConferenceParameters.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/ConferenceParameters.as
@@ -43,6 +43,7 @@ package org.bigbluebutton.main.model {
*/
public var username:String;
+ public var avatarURL:String;
/**
* The role of the local user. Could be MODERATOR or VIEWER
*/
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/ShortcutOptions.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/ShortcutOptions.as
index b489877c94..44f6375235 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/ShortcutOptions.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/ShortcutOptions.as
@@ -82,10 +82,6 @@ package org.bigbluebutton.main.model
if (presentation){generalResource.push('bbb.shortcutkey.focus.presentation');}
if (chat){generalResource.push('bbb.shortcutkey.focus.chat');}
- if (audio){
- generalResource.push('bbb.shortcutkey.share.microphone');
- generalResource.push('bbb.shortcutkey.share.pauseRemoteStream');
- }
if (deskshare){generalResource.push('bbb.shortcutkey.share.desktop');}
if (webcam){generalResource.push('bbb.shortcutkey.share.webcam');}
generalResource.push('bbb.shortcutkey.shortcutWindow');
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as
index 626b698e43..0d0f2d047e 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as
@@ -55,6 +55,7 @@ package org.bigbluebutton.main.model.users
[Bindable] public var disableMyPrivateChat:Boolean = false;
[Bindable] public var disableMyPublicChat:Boolean = false;
[Bindable] public var lockedLayout:Boolean = false;
+ [Bindable] public var avatarURL:String="";
[Bindable]
public function get hasStream():Boolean {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
index 87152ec3b3..a4886bc0c3 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
@@ -597,5 +597,20 @@ package org.bigbluebutton.main.model.users {
}
}
}
+
+ public function getUserAvatarURL(userID:String):String { // David, to get specific user avatar url
+ if(userID != null ){
+ var p:Object = getUserIndex(userID);
+ if (p != null) {
+ var u:BBBUser = p.participant as BBBUser;
+ LOGGER.info("getUserAvatarURL user =" + JSON.stringify(u));
+ if(u.avatarURL == null || u.avatarURL == ""){
+ return this.avatarURL;
+ }
+ return u.avatarURL;
+ }
+ }
+ return this.avatarURL;
+ }
}
}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
index 541eb28cf0..b16e81c832 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
@@ -71,6 +71,8 @@ with BigBlueButton; if not, see .
}
chatNoiseCheckBox.selected = Accessibility.active;
changeChatNoise();
+
+ lockSettingsChanged();
}
public function accessibleClick(event:KeyboardEvent):void{
@@ -94,6 +96,8 @@ with BigBlueButton; if not, see .
protected function openPrivateChat(event:Event):void{
if (usersList.selectedIndex == -1) return;
+ if (!usersList.visible || !usersList.enabled) return;
+
var chatWithUserID:String = usersList.selectedItem.userID;
// Don't want to be chatting with ourself.
@@ -121,7 +125,7 @@ with BigBlueButton; if not, see .
}
}
- private function lockSettingsChanged(e:Event):void {
+ private function lockSettingsChanged(e:Event = null):void {
if (UsersUtil.amIModerator() || UsersUtil.amIPresenter()) return; // Settings only affect viewers.
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/RecordingStatusEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/RecordingStatusEvent.as
index 35abf1e6d6..5979cb5bd1 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/RecordingStatusEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/RecordingStatusEvent.as
@@ -1,13 +1,13 @@
/**
* 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.
@@ -22,19 +22,19 @@ package org.bigbluebutton.modules.deskshare.events
public class RecordingStatusEvent extends Event
{
- public static const DESKSHARE_RECORD_EVENT = "DESKSHARE_RECORD_EVENT";
-
- public static const RECORD_STOPPED_EVENT = "DESKSHARE_RECORD_STOPPED_EVENT";
- public static const RECORD_STARTED_EVENT = "DESKSHARE_RECORD_STARTED_EVENT";
- public static const RECORD_UPDATED_EVENT = "DESKSHARE_RECORD_UPDATED_EVENT";
- public static const RECORD_ERROR_EVENT = "DESKSHARE_RECORD_ERROR_EVENT";
-
+ public static const DESKSHARE_RECORD_EVENT:String = "DESKSHARE_RECORD_EVENT";
+
+ public static const RECORD_STOPPED_EVENT:String = "DESKSHARE_RECORD_STOPPED_EVENT";
+ public static const RECORD_STARTED_EVENT:String = "DESKSHARE_RECORD_STARTED_EVENT";
+ public static const RECORD_UPDATED_EVENT:String = "DESKSHARE_RECORD_UPDATED_EVENT";
+ public static const RECORD_ERROR_EVENT:String = "DESKSHARE_RECORD_ERROR_EVENT";
+
public var status:String;
-
+
public function RecordingStatusEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
-
+
}
-}
\ No newline at end of file
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/UseJavaModeCommand.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/UseJavaModeCommand.as
new file mode 100755
index 0000000000..ab5aad3532
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/UseJavaModeCommand.as
@@ -0,0 +1,14 @@
+package org.bigbluebutton.modules.deskshare.events
+{
+ import flash.events.Event;
+
+ public class UseJavaModeCommand extends Event
+ {
+ public static const USE_JAVA_MODE:String = "use Java to join deskshare event";
+
+ public function UseJavaModeCommand()
+ {
+ super(USE_JAVA_MODE, true, false);
+ }
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCShareWindowEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCShareWindowEvent.as
new file mode 100755
index 0000000000..3fefb5cf88
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCShareWindowEvent.as
@@ -0,0 +1,33 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+package org.bigbluebutton.modules.deskshare.events
+{
+ import flash.events.Event;
+
+ public class WebRTCShareWindowEvent extends Event
+ {
+ public static const CLOSE:String = "WebRTC Deskshare Share Window Close Event";
+
+ public function WebRTCShareWindowEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+ {
+ super(type, bubbles, cancelable);
+ }
+
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCStreamEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCStreamEvent.as
new file mode 100755
index 0000000000..d34393029e
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCStreamEvent.as
@@ -0,0 +1,37 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+package org.bigbluebutton.modules.deskshare.events
+{
+ import flash.events.Event;
+
+ public class WebRTCStreamEvent extends Event
+ {
+ public static const START:String = "WebRTC Deskshare Stream Started Event";
+ public static const STOP:String = "WebRTC Deskshare Stream Stopped Event";
+
+ public var videoWidth:Number = 0;
+ public var videoHeight:Number = 0;
+
+ public function WebRTCStreamEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+ {
+ super(type, bubbles, cancelable);
+ }
+
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCViewStreamEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCViewStreamEvent.as
new file mode 100755
index 0000000000..17a6266fa0
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCViewStreamEvent.as
@@ -0,0 +1,41 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+package org.bigbluebutton.modules.deskshare.events
+{
+ import flash.events.Event;
+ import org.bigbluebutton.main.api.JSLog;
+
+ public class WebRTCViewStreamEvent extends Event
+ {
+ public static const START:String = "WebRTC Start Viewing Stream Event";
+ public static const STOP:String = "WebRTC Stop Viewing Stream Event";
+
+ public var videoWidth:Number = 0;
+ public var videoHeight:Number = 0;
+ public var rtmp:String = null;
+
+ public function WebRTCViewStreamEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+ {
+ super(type, bubbles, cancelable);
+ JSLog.warn("creating a WebRTCViewStreamEvent event " + type, null);
+ }
+
+ }
+}
+
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCViewWindowEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCViewWindowEvent.as
new file mode 100755
index 0000000000..133090432b
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/events/WebRTCViewWindowEvent.as
@@ -0,0 +1,33 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+package org.bigbluebutton.modules.deskshare.events
+{
+ import flash.events.Event;
+
+ public class WebRTCViewWindowEvent extends Event
+ {
+ public static const CLOSE:String = "WebRTC Deskshare View Window Close Event";
+
+ public function WebRTCViewWindowEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+ {
+ super(type, bubbles, cancelable);
+ }
+
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/DeskshareManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/DeskshareManager.as
old mode 100644
new mode 100755
index f1781cf235..ea5d2d7e26
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/DeskshareManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/DeskshareManager.as
@@ -1,13 +1,13 @@
/**
* 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.
@@ -20,15 +20,19 @@
package org.bigbluebutton.modules.deskshare.managers
{
import com.asfusion.mate.events.Dispatcher;
-
+
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.main.events.MadePresenterEvent;
+ import org.bigbluebutton.modules.deskshare.events.UseJavaModeCommand;
import org.bigbluebutton.modules.deskshare.model.DeskshareOptions;
import org.bigbluebutton.modules.deskshare.services.DeskshareService;
-
- public class DeskshareManager {
+ import org.bigbluebutton.modules.deskshare.utils.JavaCheck;
+ import org.bigbluebutton.modules.deskshare.utils.BrowserCheck;
+ import flash.external.ExternalInterface;
+
+ public class DeskshareManager {
private static const LOGGER:ILogger = getClassLogger(DeskshareManager);
private var publishWindowManager:PublishWindowManager;
@@ -38,65 +42,66 @@ package org.bigbluebutton.modules.deskshare.managers
private var service:DeskshareService;
private var globalDispatcher:Dispatcher;
private var sharing:Boolean = false;
-
+ private var usingJava:Boolean = true;
+
public function DeskshareManager() {
service = new DeskshareService();
globalDispatcher = new Dispatcher();
publishWindowManager = new PublishWindowManager(service);
- viewWindowManager = new ViewerWindowManager(service);
- toolbarButtonManager = new ToolbarButtonManager();
+ viewWindowManager = new ViewerWindowManager(service);
+ toolbarButtonManager = new ToolbarButtonManager();
}
-
+
public function handleStartModuleEvent(module:DeskShareModule):void {
LOGGER.debug("Deskshare Module starting");
- this.module = module;
+ this.module = module;
service.handleStartModuleEvent(module);
-
+
if (UsersUtil.amIPresenter()) {
initDeskshare();
}
-
+
}
-
+
public function handleStopModuleEvent():void {
LOGGER.debug("Deskshare Module stopping");
publishWindowManager.stopSharing();
- viewWindowManager.stopViewing();
+ viewWindowManager.stopViewing();
service.disconnect();
}
-
+
public function handleStreamStoppedEvent():void {
LOGGER.debug("Sending deskshare stopped command");
service.stopSharingDesktop(module.getRoom(), module.getRoom());
}
-
+
public function handleStreamStartedEvent(videoWidth:Number, videoHeight:Number):void {
LOGGER.debug("Sending startViewing command");
service.sendStartViewingNotification(videoWidth, videoHeight);
}
-
+
public function handleStartedViewingEvent(stream:String):void {
LOGGER.debug("handleStartedViewingEvent [{0}]", [stream]);
service.sendStartedViewingNotification(stream);
}
-
+
private function initDeskshare():void {
sharing = false;
- var option:DeskshareOptions = new DeskshareOptions();
- option.parseOptions();
- if (option.autoStart) {
+ var options:DeskshareOptions = new DeskshareOptions();
+ options.parseOptions();
+ if (options.autoStart) {
handleStartSharingEvent(true);
}
- if(option.showButton){
+ if(options.showButton){
toolbarButtonManager.addToolbarButton();
- }
+ }
}
-
+
public function handleMadePresenterEvent(e:MadePresenterEvent):void {
LOGGER.debug("Got MadePresenterEvent ");
initDeskshare();
}
-
+
public function handleMadeViewerEvent(e:MadePresenterEvent):void{
LOGGER.debug("Got MadeViewerEvent ");
toolbarButtonManager.removeToolbarButton();
@@ -105,35 +110,65 @@ package org.bigbluebutton.modules.deskshare.managers
}
sharing = false;
}
-
+
public function handleStartSharingEvent(autoStart:Boolean):void {
- LOGGER.debug("DeskshareManager::handleStartSharingEvent");
- //toolbarButtonManager.disableToolbarButton();
- toolbarButtonManager.startedSharing();
- var option:DeskshareOptions = new DeskshareOptions();
- option.parseOptions();
- publishWindowManager.startSharing(option.publishURI , option.useTLS , module.getRoom(), autoStart, option.autoFullScreen);
- sharing = true;
+ LOGGER.debug("DeskshareManager::handleStartSharingEvent (Java)");
+ var options:DeskshareOptions = new DeskshareOptions();
+ options.parseOptions();
+
+ // falling back to java, or we can't use WebRTC
+ if (autoStart || (options.useWebRTCIfAvailable && !BrowserCheck.isWebRTCSupported())) {
+ if (BrowserCheck.isUsingLessThanChrome38OnMac()) {
+ usingJava = false;
+ publishWindowManager.startSharing(options.publishURI , options.useTLS , module.getRoom(), autoStart, options.autoFullScreen);
+ } else {
+ var javaIssue:String = JavaCheck.checkJava();
+
+ if (javaIssue != null) {
+ if (BrowserCheck.isChrome42OrHigher()) {
+ usingJava = false;
+ publishWindowManager.startSharing(options.publishURI , options.useTLS , module.getRoom(), autoStart, options.autoFullScreen);
+ } else {
+ usingJava = false;
+ publishWindowManager.startSharing(options.publishURI , options.useTLS , module.getRoom(), autoStart, options.autoFullScreen);
+ }
+ } else {
+ usingJava = true;
+ toolbarButtonManager.startedSharing();
+
+ publishWindowManager.startSharing(options.publishURI , options.useTLS , module.getRoom(), autoStart, options.autoFullScreen);
+ sharing = true;
+ }
+ }
+ } else {
+ // using WebRTC or not a fallback case
+ usingJava = false;
+ }
}
-
+
public function handleShareWindowCloseEvent():void {
//toolbarButtonManager.enableToolbarButton();
publishWindowManager.handleShareWindowCloseEvent();
sharing = false;
toolbarButtonManager.stopedSharing();
}
-
+
public function handleViewWindowCloseEvent():void {
- LOGGER.debug("Received stop viewing command");
- viewWindowManager.handleViewWindowCloseEvent();
+ LOGGER.debug("Received stop viewing command");
+ viewWindowManager.handleViewWindowCloseEvent();
}
-
+
public function handleStreamStartEvent(videoWidth:Number, videoHeight:Number):void{
- if (sharing) return;
- LOGGER.debug("Received start vieweing command");
+ if (!usingJava) { return; }
+ if (sharing) { return; }
+ LOGGER.debug("Received start viewing command");
viewWindowManager.startViewing(module.getRoom(), videoWidth, videoHeight);
}
-
-
+
+ public function handleUseJavaModeCommand():void {
+ usingJava = true;
+ handleStartSharingEvent(true);
+ }
+
}
}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/PublishWindowManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/PublishWindowManager.as
index b1214ee290..c019407a57 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/PublishWindowManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/PublishWindowManager.as
@@ -39,7 +39,8 @@ package org.bigbluebutton.modules.deskshare.managers
private var globalDispatcher:Dispatcher;
private var service:DeskshareService;
private var buttonShownOnToolbar:Boolean = false;
-
+ private var isOpen:Boolean = false;
+
// Timer to auto-publish webcam. We need this timer to delay
// the auto-publishing until after the Viewers's window has loaded
// to receive the publishing events. Otherwise, the user joining next
@@ -53,12 +54,18 @@ package org.bigbluebutton.modules.deskshare.managers
}
public function stopSharing():void {
- if (shareWindow != null) shareWindow.stopSharing();
+ if (shareWindow != null) {
+ shareWindow.stopSharing();
+ isOpen = false;
+ }
}
-
+
public function startSharing(uri:String , useTLS:Boolean , room:String, autoStart:Boolean, autoFullScreen:Boolean):void {
LOGGER.debug("DS:PublishWindowManager::opening desk share window, autostart={0} autoFullScreen={1}", [autoStart, autoFullScreen]);
-
+ if (isOpen) {
+ return;
+ }
+ isOpen = true;
shareWindow = new DesktopPublishWindow();
shareWindow.initWindow(service.getConnection(), uri , useTLS , room, autoStart, autoFullScreen);
shareWindow.visible = true;
@@ -72,7 +79,7 @@ package org.bigbluebutton.modules.deskshare.managers
autoPublishTimer = new Timer(2000, 1);
autoPublishTimer.addEventListener(TimerEvent.TIMER, autopublishTimerHandler);
autoPublishTimer.start();
- }
+ }
}
private function autopublishTimerHandler(event:TimerEvent):void {
@@ -82,14 +89,16 @@ package org.bigbluebutton.modules.deskshare.managers
public function handleShareWindowCloseEvent():void {
closeWindow(shareWindow);
}
-
- private function openWindow(window:IBbbModuleWindow):void {
+
+ private function openWindow(window:IBbbModuleWindow):void {
+ isOpen = true;
var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
event.window = window;
globalDispatcher.dispatchEvent(event);
}
private function closeWindow(window:IBbbModuleWindow):void {
+ isOpen = false;
var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
event.window = window;
globalDispatcher.dispatchEvent(event);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCDeskshareManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCDeskshareManager.as
new file mode 100755
index 0000000000..3a90cbb1f3
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCDeskshareManager.as
@@ -0,0 +1,261 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+
+package org.bigbluebutton.modules.deskshare.managers
+{
+ import com.asfusion.mate.events.Dispatcher;
+
+ import flash.external.ExternalInterface;
+
+ import org.as3commons.logging.api.ILogger;
+ import org.as3commons.logging.api.getClassLogger;
+ import org.bigbluebutton.core.UsersUtil;
+ import org.bigbluebutton.core.managers.UserManager;
+ import org.bigbluebutton.main.events.MadePresenterEvent;
+ import org.bigbluebutton.modules.deskshare.events.UseJavaModeCommand;
+ import org.bigbluebutton.modules.deskshare.events.WebRTCViewStreamEvent;
+ import org.bigbluebutton.modules.deskshare.model.DeskshareOptions;
+ import org.bigbluebutton.modules.deskshare.events.ShareWindowEvent;
+ import org.bigbluebutton.modules.deskshare.services.WebRTCDeskshareService;
+ import org.bigbluebutton.modules.deskshare.utils.BrowserCheck;
+ import org.bigbluebutton.main.api.JSLog;
+
+ public class WebRTCDeskshareManager {
+ private static const LOGGER:ILogger = getClassLogger(WebRTCDeskshareManager);
+
+ private var publishWindowManager:WebRTCPublishWindowManager;
+ private var viewWindowManager:WebRTCViewerWindowManager;
+ private var toolbarButtonManager:ToolbarButtonManager;
+ private var module:DeskShareModule;
+ private var service:WebRTCDeskshareService;
+ private var globalDispatcher:Dispatcher;
+ private var sharing:Boolean = false;
+ private var usingWebRTC:Boolean = false;
+ private var chromeExtensionKey:String = null;
+ private var vertoServerCredentials:Object = new Object();
+
+ public function WebRTCDeskshareManager() {
+ service = new WebRTCDeskshareService();
+ globalDispatcher = new Dispatcher();
+ publishWindowManager = new WebRTCPublishWindowManager(service);
+ viewWindowManager = new WebRTCViewerWindowManager(service);
+ }
+
+ public function handleStartModuleEvent(module:DeskShareModule):void {
+ LOGGER.debug("WebRTC Deskshare Module starting");
+ this.module = module;
+ service.handleStartModuleEvent(module);
+
+ if (UsersUtil.amIPresenter()) {
+ initDeskshare();
+ }
+ }
+
+ public function handleStopModuleEvent():void {
+ LOGGER.debug("WebRTC Deskshare Module stopping");
+
+ publishWindowManager.stopSharing();
+ viewWindowManager.stopViewing();
+ service.disconnect();
+ }
+
+ /*presenter stopped their program stream*/
+ public function handleStreamStoppedEvent():void {
+ LOGGER.debug("DeskshareManager::handleStreamStoppedEvent Sending deskshare stopped command");
+ JSLog.warn("WebRTCDeskshareManager::handleStreamStoppedEvent", {});
+ stopWebRTCDeskshare();
+ }
+
+ /*viewer being told there is no more stream*/
+ public function handleStreamStopEvent(args:Object):void {
+ LOGGER.debug("WebRTCDeskshareManager::handleStreamStopEvent");
+ JSLog.warn("WebRTCDeskshareManager::handleStreamStopEvent", {});
+ viewWindowManager.handleViewWindowCloseEvent();
+ }
+
+ private function stopWebRTCDeskshare():void {
+ LOGGER.debug("DeskshareManager::stopWebRTCDeskshare");
+ viewWindowManager.stopViewing();
+ /* stopping WebRTC deskshare. Alert DeskshareManager to reset toolbar */
+ globalDispatcher.dispatchEvent(new ShareWindowEvent(ShareWindowEvent.CLOSE));
+
+ if (ExternalInterface.available) {
+ var loggingCallback:Function = function(args:Object):void {LOGGER.debug(args); JSLog.warn("loggingCallback", args)};
+ var onSuccess:Function = function():void { LOGGER.debug("onSuccess"); JSLog.warn("onSuccess - as", {})};
+ ExternalInterface.addCallback("loggingCallback", loggingCallback);
+ ExternalInterface.addCallback("onSuccess", onSuccess);
+ ExternalInterface.call("endScreenshare", "loggingCallback", "onSuccess");
+ } else {
+ LOGGER.error("Error! ExternalInterface not available (webrtcDeskshare)");
+ }
+ }
+
+ private function startWebRTCDeskshare():void {
+ LOGGER.debug("DeskshareManager::startWebRTCDeskshare");
+
+ var result:String;
+ if (ExternalInterface.available) {
+ var loggingCallback:Function = function(args:Object):void {LOGGER.debug(args); JSLog.warn("loggingCallback", args)};
+ ExternalInterface.addCallback("loggingCallback", loggingCallback);
+ var videoTag:String = "localVertoVideo";
+ var modifyResolution:Boolean = false;
+ // register these callbacks
+ var onSuccess:Function = function():void { LOGGER.debug("onSuccess"); JSLog.warn("onSuccess - as", {})};
+ ExternalInterface.addCallback("onSuccess", onSuccess);
+ var onFail:Function = function(args:Object):void {
+ JSLog.warn("onFail - as", args);
+ JSLog.warn("WebRTCDeskshareManager::startWebRTCDeskshare - falling back to java", {});
+ globalDispatcher.dispatchEvent(new UseJavaModeCommand())
+ };
+ ExternalInterface.addCallback("onFail", onFail);
+ JSLog.warn("calling startScreenshare", {});
+ result = ExternalInterface.call("startScreenshare", "loggingCallback", videoTag, vertoServerCredentials, chromeExtensionKey, modifyResolution, "onSuccess", "onFail");
+ }
+ }
+
+ private function initDeskshare():void {
+ sharing = false;
+ var options:DeskshareOptions = new DeskshareOptions();
+ options.parseOptions();
+ if (options.chromeExtensionKey) {
+ chromeExtensionKey = options.chromeExtensionKey;
+ }
+ if (options.vertoPort) {
+ vertoServerCredentials.vertoPort = options.vertoPort;
+ }
+ if (options.hostName) {
+ vertoServerCredentials.hostName = options.hostName;
+ }
+ if (options.login) {
+ vertoServerCredentials.login = options.login;
+ }
+ if (options.password) {
+ vertoServerCredentials.password = options.password;
+ }
+ if (options.autoStart) {
+ handleStartSharingEvent(true);
+ }
+ }
+
+ public function handleMadePresenterEvent(e:MadePresenterEvent):void {
+ LOGGER.debug("Got MadePresenterEvent ");
+ initDeskshare();
+ }
+
+ public function handleMadeViewerEvent(e:MadePresenterEvent):void{
+ LOGGER.debug("Got MadeViewerEvent ");
+ if (sharing) {
+ publishWindowManager.stopSharing();
+ stopWebRTCDeskshare();
+ }
+ sharing = false;
+ }
+
+ private function canIUseVertoOnThisBrowser(onFailure:Function, onSuccess:Function):void {
+ LOGGER.debug("DeskshareManager::canIUseVertoOnThisBrowser");
+ var options:DeskshareOptions = new DeskshareOptions();
+ options.parseOptions();
+
+ if (options.useWebRTCIfAvailable && BrowserCheck.isWebRTCSupported()) {
+ JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent WebRTC Supported", {});
+ if (BrowserCheck.isFirefox()) {
+ onSuccess("Firefox, lets try");
+ } else {
+ if (chromeExtensionKey != null) {
+ /*toolbarButtonManager.startedSharing();*/
+ JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent chrome extension key exists - ", chromeExtensionKey);
+ if (ExternalInterface.available) {
+ var success:Function = function(status:String):void {
+ ExternalInterface.addCallback("callback", null);
+ JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent inside onSuccess", {});
+ if (status == "installed-enabled") {
+ JSLog.warn("Chrome Extension exists", {});
+ onSuccess("worked");
+ } else {
+ onFailure("No Chrome Extension");
+ }
+ };
+ ExternalInterface.addCallback("callback", success);
+ ExternalInterface.call("getChromeExtensionStatus", chromeExtensionKey, "callback");
+ }
+ } else {
+ onFailure("No chromeExtensionKey in config.xml");
+ return;
+ }
+ }
+ } else {
+ onFailure("Web browser doesn't support WebRTC");
+ return;
+ }
+ }
+
+ /*handle start sharing event*/
+ public function handleStartSharingEvent(autoStart:Boolean):void {
+ LOGGER.debug("WebRTCDeskshareManager::handleStartSharingEvent");
+ JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent", {});
+ var onFailure:Function = function(message:String):void {
+ JSLog.warn(message, {});
+ usingWebRTC = false;
+ // send out event to fallback to Java
+ JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent - falling back to java", {});
+ globalDispatcher.dispatchEvent(new UseJavaModeCommand());
+ return;
+ };
+
+ var onSuccess:Function = function(message:String):void {
+ JSLog.warn(message, {});
+ usingWebRTC = true;
+ startWebRTCDeskshare();
+ };
+
+ canIUseVertoOnThisBrowser(onFailure, onSuccess);
+ }
+
+ public function handleShareWindowCloseEvent():void {
+ publishWindowManager.handleShareWindowCloseEvent();
+ sharing = false;
+ stopWebRTCDeskshare();
+ }
+
+ public function handleViewWindowCloseEvent():void {
+ LOGGER.debug("Received stop viewing command");
+ JSLog.warn("WebRTCDeskshareManager::handleViewWindowCloseEvent", {});
+ viewWindowManager.handleViewWindowCloseEvent();
+ }
+
+ public function handleStreamStartEvent(e:WebRTCViewStreamEvent):void{
+ // if (!usingWebRTC) { return; } //TODO this was causing issues
+ if (sharing) return; //TODO must uncomment this for the non-webrtc desktop share
+ var isPresenter:Boolean = UserManager.getInstance().getConference().amIPresenter;
+ LOGGER.debug("Received start viewing command when isPresenter==[{0}]",[isPresenter]);
+
+ if(isPresenter) {
+ publishWindowManager.startViewing(e.rtmp, e.videoWidth, e.videoHeight);
+ } else {
+ viewWindowManager.startViewing(e.rtmp, e.videoWidth, e.videoHeight);
+ }
+
+ sharing = true; //TODO must uncomment this for the non-webrtc desktop share
+ }
+
+ public function handleUseJavaModeCommand():void {
+ usingWebRTC = false;
+ }
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCPublishWindowManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCPublishWindowManager.as
new file mode 100755
index 0000000000..6385bcb941
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCPublishWindowManager.as
@@ -0,0 +1,86 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+
+package org.bigbluebutton.modules.deskshare.managers
+{
+ import com.asfusion.mate.events.Dispatcher;
+
+ import flash.events.TimerEvent;
+ import flash.utils.Timer;
+
+ import org.as3commons.logging.api.ILogger;
+ import org.as3commons.logging.api.getClassLogger;
+ import org.bigbluebutton.common.IBbbModuleWindow;
+ import org.bigbluebutton.common.events.CloseWindowEvent;
+ import org.bigbluebutton.common.events.OpenWindowEvent;
+ import org.bigbluebutton.modules.deskshare.services.WebRTCDeskshareService;
+ import org.bigbluebutton.modules.deskshare.view.components.WebRTCDesktopPublishWindow;
+
+ public class WebRTCPublishWindowManager {
+ private static const LOGGER:ILogger = getClassLogger(PublishWindowManager);
+
+ private var shareWindow:WebRTCDesktopPublishWindow;
+ private var globalDispatcher:Dispatcher;
+ private var service:WebRTCDeskshareService;
+ private var buttonShownOnToolbar:Boolean = false;
+
+ // Timer to auto-publish webcam. We need this timer to delay
+ // the auto-publishing until after the Viewers's window has loaded
+ // to receive the publishing events. Otherwise, the user joining next
+ // won't be able to view the webcam.
+ private var autoPublishTimer:Timer;
+
+ public function WebRTCPublishWindowManager(service:WebRTCDeskshareService) {
+ LOGGER.debug("PublishWindowManager init");
+ globalDispatcher = new Dispatcher();
+ this.service = service;
+ }
+
+ public function stopSharing():void {
+ if (shareWindow != null) shareWindow.stopSharing();
+ }
+
+ private function autopublishTimerHandler(event:TimerEvent):void {
+ shareWindow.shareScreen(true);
+ }
+
+ public function handleShareWindowCloseEvent():void {
+ closeWindow(shareWindow);
+ }
+
+ private function openWindow(window:IBbbModuleWindow):void {
+ var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
+ event.window = window;
+ globalDispatcher.dispatchEvent(event);
+ }
+
+ private function closeWindow(window:IBbbModuleWindow):void {
+ var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
+ event.window = window;
+ globalDispatcher.dispatchEvent(event);
+ }
+
+ public function startViewing(rtmp:String, videoWidth:Number, videoHeight:Number):void{
+ shareWindow = new WebRTCDesktopPublishWindow();
+ shareWindow.visible = true;
+ openWindow(shareWindow);
+ shareWindow.startVideo(rtmp, videoWidth, videoHeight);
+ }
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCViewerWindowManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCViewerWindowManager.as
new file mode 100755
index 0000000000..90233a0c82
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/managers/WebRTCViewerWindowManager.as
@@ -0,0 +1,78 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+
+package org.bigbluebutton.modules.deskshare.managers
+{
+ import com.asfusion.mate.events.Dispatcher;
+
+ import org.as3commons.logging.api.ILogger;
+ import org.as3commons.logging.api.getClassLogger;
+ import org.bigbluebutton.common.IBbbModuleWindow;
+ import org.bigbluebutton.common.events.CloseWindowEvent;
+ import org.bigbluebutton.common.events.OpenWindowEvent;
+ import org.bigbluebutton.modules.deskshare.services.WebRTCDeskshareService;
+ import org.bigbluebutton.modules.deskshare.view.components.WebRTCDesktopPublishWindow;
+ import org.bigbluebutton.modules.deskshare.view.components.WebRTCDesktopViewWindow;
+
+ public class WebRTCViewerWindowManager {
+ private static const LOGGER:ILogger = getClassLogger(ViewerWindowManager);
+
+ private var viewWindow:WebRTCDesktopViewWindow;
+ private var shareWindow:WebRTCDesktopPublishWindow;
+ private var service:WebRTCDeskshareService;
+ private var isViewing:Boolean = false;
+ private var globalDispatcher:Dispatcher;
+
+ public function WebRTCViewerWindowManager(service:WebRTCDeskshareService) {
+ this.service = service;
+ globalDispatcher = new Dispatcher();
+ }
+
+ public function stopViewing():void {
+ if (isViewing) viewWindow.stopViewing();
+ }
+
+ private function openWindow(window:IBbbModuleWindow):void{
+ var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
+ event.window = window;
+ globalDispatcher.dispatchEvent(event);
+ }
+
+ public function handleViewWindowCloseEvent():void {
+ LOGGER.debug("ViewerWindowManager Received stop viewing command");
+ closeWindow(viewWindow);
+ isViewing = false;
+ }
+
+ private function closeWindow(window:IBbbModuleWindow):void {
+ var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
+ event.window = window;
+ globalDispatcher.dispatchEvent(event);
+ }
+
+ public function startViewing(rtmp:String, videoWidth:Number, videoHeight:Number):void{
+ LOGGER.debug("ViewerWindowManager::startViewing");
+
+ viewWindow = new WebRTCDesktopViewWindow();
+ viewWindow.startVideo(rtmp, videoWidth, videoHeight);
+ openWindow(viewWindow);
+ isViewing = true;
+ }
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/maps/DeskshareEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/maps/DeskshareEventMap.mxml
index f037c5f40c..b2cc1db5b9 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/maps/DeskshareEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/maps/DeskshareEventMap.mxml
@@ -34,6 +34,7 @@ with BigBlueButton; if not, see .
import org.bigbluebutton.modules.deskshare.events.ShareWindowEvent;
import org.bigbluebutton.modules.deskshare.events.StartedViewingEvent;
import org.bigbluebutton.modules.deskshare.events.StreamEvent;
+ import org.bigbluebutton.modules.deskshare.events.UseJavaModeCommand;
import org.bigbluebutton.modules.deskshare.events.ViewStreamEvent;
import org.bigbluebutton.modules.deskshare.events.ViewWindowEvent;
import org.bigbluebutton.modules.deskshare.managers.DeskshareManager;
@@ -85,8 +86,12 @@ with BigBlueButton; if not, see .
-
-
+
+
+
+
+
+
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/maps/WebRTCDeskshareEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/maps/WebRTCDeskshareEventMap.mxml
new file mode 100755
index 0000000000..2890ca6763
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/maps/WebRTCDeskshareEventMap.mxml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/model/DeskshareOptions.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/model/DeskshareOptions.as
index aa8aa92cf4..be20f67bc5 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/model/DeskshareOptions.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/model/DeskshareOptions.as
@@ -1,13 +1,13 @@
/**
* 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.
@@ -19,9 +19,9 @@
package org.bigbluebutton.modules.deskshare.model
{
import flash.external.ExternalInterface;
-
+
import org.bigbluebutton.core.BBB;
-
+
public class DeskshareOptions
{
[Bindable] public var showButton:Boolean = true;
@@ -30,6 +30,12 @@ package org.bigbluebutton.modules.deskshare.model
public var useTLS:Boolean = false;
[Bindable] public var baseTabIndex:int;
public var publishURI:String;
+ [Bindable] public var useWebRTCIfAvailable:Boolean = true;
+ [Bindable] public var chromeExtensionKey:String = null;
+ [Bindable] public var vertoPort:String = null;
+ [Bindable] public var hostName:String = null;
+ [Bindable] public var login:String = null;
+ [Bindable] public var password:String = null;
public function parseOptions():void {
var vxml:XML = BBB.getConfigForModule("DeskShareModule");
@@ -60,7 +66,25 @@ package org.bigbluebutton.modules.deskshare.model
showButton = false;
}
}
+ if (vxml.@useWebRTCIfAvailable != undefined) {
+ useWebRTCIfAvailable = (vxml.@useWebRTCIfAvailable.toString().toUpperCase() == "TRUE");
+ }
+ if (vxml.@chromeExtensionKey != undefined) {
+ chromeExtensionKey = vxml.@chromeExtensionKey.toString();
+ }
+ if (vxml.@vertoPort != undefined) {
+ vertoPort = vxml.@vertoPort.toString();
+ }
+ if (vxml.@hostName != undefined) {
+ hostName = vxml.@hostName.toString();
+ }
+ if (vxml.@login != undefined) {
+ login = vxml.@login.toString();
+ }
+ if (vxml.@password != undefined) {
+ password = vxml.@password.toString();
+ }
}
}
}
-}
\ No newline at end of file
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/WebRTCDeskshareService.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/WebRTCDeskshareService.as
new file mode 100755
index 0000000000..72f0f51280
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/WebRTCDeskshareService.as
@@ -0,0 +1,74 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+package org.bigbluebutton.modules.deskshare.services
+{
+ import com.asfusion.mate.events.Dispatcher;
+
+ import flash.net.NetConnection;
+
+ import org.as3commons.logging.api.ILogger;
+ import org.as3commons.logging.api.getClassLogger;
+ import org.bigbluebutton.modules.deskshare.services.red5.WebRTCConnection;
+
+ /**
+ * The DeskShareProxy communicates with the Red5 deskShare server application
+ * @author Snap
+ *
+ */
+ public class WebRTCDeskshareService
+ {
+ private static const LOGGER:ILogger = getClassLogger(DeskshareService);
+
+ private var conn:WebRTCConnection;
+
+ private var module:DeskShareModule;
+ private var dispatcher:Dispatcher;
+
+ private var uri:String;
+ private var room:String;
+
+ public function WebRTCDeskshareService() {
+ this.dispatcher = new Dispatcher();
+ }
+
+ public function handleStartModuleEvent(module:DeskShareModule):void {
+ LOGGER.debug("Deskshare Module starting");
+ this.module = module;
+ connect(module.uri, module.getRoom());
+ }
+
+ public function connect(uri:String, room:String):void {
+ this.uri = uri;
+ this.room = room;
+ LOGGER.debug("Deskshare Service connecting to {0}", [uri]);
+ conn = new WebRTCConnection(room); //to red5 deskshare
+
+ conn.setURI(uri);
+ conn.connect();
+ }
+
+ public function getConnection():NetConnection{
+ return conn.getConnection();
+ }
+
+ public function disconnect():void{
+ conn.disconnect();
+ }
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/red5/WebRTCConnection.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/red5/WebRTCConnection.as
new file mode 100755
index 0000000000..33ea3f8664
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/red5/WebRTCConnection.as
@@ -0,0 +1,322 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+
+package org.bigbluebutton.modules.deskshare.services.red5
+{
+ import com.asfusion.mate.events.Dispatcher;
+
+ import flash.events.AsyncErrorEvent;
+ import flash.events.NetStatusEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.events.TimerEvent;
+ import flash.net.NetConnection;
+ import flash.net.ObjectEncoding;
+ import flash.net.Responder;
+ import flash.utils.Timer;
+
+ import mx.utils.ObjectUtil;
+
+ import org.as3commons.logging.api.ILogger;
+ import org.as3commons.logging.api.getClassLogger;
+ import org.bigbluebutton.core.BBB;
+ import org.bigbluebutton.core.UsersUtil;
+ import org.bigbluebutton.core.managers.ReconnectionManager;
+ import org.bigbluebutton.main.events.BBBEvent;
+ import org.bigbluebutton.modules.deskshare.events.WebRTCViewStreamEvent;
+
+ public class WebRTCConnection {
+ private static const LOGGER:ILogger = getClassLogger(Connection);
+
+ private var nc:NetConnection;
+ private var uri:String;
+ private var retryTimer:Timer = null;
+ private var retryCount:int = 0;
+ private const MAX_RETRIES:int = 5;
+ private var responder:Responder;
+ private var width:Number;
+ private var height:Number;
+ private var room:String;
+ private var logoutOnUserCommand:Boolean = false;
+ private var reconnecting:Boolean = false;
+ private var wasPresenterBeforeDisconnect:Boolean = false;
+
+ private var dispatcher:Dispatcher = new Dispatcher();
+
+ public function WebRTCConnection(room:String) {
+ this.room = room;
+
+ responder = new Responder(
+ function(result:Object):void {
+ if (result != null && (result.publishing as Boolean)){
+ width = result.width as Number;
+ height = result.height as Number;
+ LOGGER.debug("Desk Share stream is streaming [{0},{1}]", [width, height]);
+ var event:WebRTCViewStreamEvent = new WebRTCViewStreamEvent(WebRTCViewStreamEvent.START);
+ event.videoWidth = width;
+ event.videoHeight = height;
+ dispatcher.dispatchEvent(event); //TODO why?
+ } else {
+ LOGGER.debug("No deskshare stream being published");
+ var connEvent:ConnectionEvent = new ConnectionEvent();
+ connEvent.status = ConnectionEvent.NO_DESKSHARE_STREAM;
+ dispatcher.dispatchEvent(connEvent); //TODO why?
+ }
+ },
+ function(status:Object):void{
+ var checkFailedEvent:ConnectionEvent = new ConnectionEvent();
+ checkFailedEvent.status = ConnectionEvent.FAIL_CHECK_FOR_DESKSHARE_STREAM;
+ dispatcher.dispatchEvent(checkFailedEvent);
+ LOGGER.debug("Error while trying to call remote mathod on server");
+ }
+ );
+ }
+
+ public function connect(retry:Boolean = false):void {
+ nc = new NetConnection();
+ nc.proxyType = "best";
+ nc.objectEncoding = ObjectEncoding.AMF0;
+ nc.client = this;
+
+ nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, debugAsyncErrorHandler);
+ nc.addEventListener(NetStatusEvent.NET_STATUS, debugNetStatusHandler);
+ nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
+ nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
+
+ if (getURI().length == 0){
+ LOGGER.error("please provide a valid URI connection string. URI Connection String missing");
+ return;
+ } else if (nc.connected){
+ LOGGER.error("You are already connected to {0}", [getURI()]);
+ return;
+ }
+
+ LOGGER.debug("Trying to connect to [{0}] retry=[{1}]", [getURI(), retry]);
+ if (! (retryCount > 0)) {
+ var ce:ConnectionEvent = new ConnectionEvent();
+ ce.status = ConnectionEvent.CONNECTING;
+
+ dispatcher.dispatchEvent(ce);
+ }
+
+ nc.connect(getURI(), UsersUtil.getInternalMeetingID());
+ }
+
+ private function connectTimeoutHandler(e:TimerEvent):void {
+ LOGGER.debug("Connection attempt to [{0}] timedout. Retrying.", [getURI()]);
+ retryTimer.stop();
+ retryTimer = null;
+
+ nc.close();
+ nc = null;
+
+ var ce:ConnectionEvent = new ConnectionEvent();;
+
+ retryCount++;
+ if (retryCount < MAX_RETRIES) {
+ ce.status = ConnectionEvent.CONNECTING_RETRY;
+ ce.retryAttempts = retryCount;
+ dispatcher.dispatchEvent(ce);
+
+ connect(false);
+ } else {
+ ce.status = ConnectionEvent.CONNECTING_MAX_RETRY;
+ dispatcher.dispatchEvent(ce);
+ }
+ }
+
+ public function close():void{
+ nc.close();
+ }
+
+ public function setURI(p_URI:String):void{
+ uri = p_URI;
+ }
+
+ public function getURI():String{
+ return uri;
+ }
+
+ public function onBWCheck(... rest):Number {
+ return 0;
+ }
+
+ public function onBWDone(... rest):void {
+ var p_bw:Number;
+ if (rest.length > 0) p_bw = rest[0];
+ // your application should do something here
+ // when the bandwidth check is complete
+ LOGGER.debug("bandwidth = {0} Kbps.", [p_bw]);
+ }
+
+ private function netStatusHandler(event:NetStatusEvent):void {
+ LOGGER.debug("Connected to [" + getURI() + "]. [" + event.info.code + "]");
+
+ if (retryTimer) {
+ retryCount = 0;
+ LOGGER.debug("Cancelling retry timer.");
+ retryTimer.stop();
+ retryTimer = null;
+ }
+
+ var ce:ConnectionEvent = new ConnectionEvent();
+
+ switch(event.info.code){
+ case "NetConnection.Connect.Failed":
+ if (reconnecting) {
+ var attemptFailedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_FAILED_EVENT);
+ attemptFailedEvent.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
+ dispatcher.dispatchEvent(attemptFailedEvent);
+ }
+ ce.status = ConnectionEvent.FAILED;
+
+ dispatcher.dispatchEvent(ce);
+ break;
+
+ case "NetConnection.Connect.Success":
+ ce.status = ConnectionEvent.SUCCESS;
+ if (reconnecting) {
+ reconnecting = false;
+ if (wasPresenterBeforeDisconnect) {
+ wasPresenterBeforeDisconnect = false;
+ // stopSharingDesktop(room, room) //TODO
+ }
+
+ var attemptSucceeded:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_SUCCEEDED_EVENT);
+ attemptSucceeded.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
+ dispatcher.dispatchEvent(attemptSucceeded);
+ }
+
+ // request desktop sharing info (as a late joiner)
+ LOGGER.debug("Sending [desktopSharing.requestDeskShareInfo] to server.");
+ var _nc:ConnectionManager = BBB.initConnectionManager();
+ _nc.sendMessage("desktopSharing.requestDeskShareInfo",
+ function(result:String):void { // On successful result
+ LOGGER.debug(result);
+ },
+ function(status:String):void { // status - On error occurred
+ LOGGER.error(status);
+ }
+ );
+
+ dispatcher.dispatchEvent(ce);
+ break;
+
+ case "NetConnection.Connect.Rejected":
+ ce.status = ConnectionEvent.REJECTED;
+ dispatcher.dispatchEvent(ce);
+ break;
+
+ case "NetConnection.Connect.Closed":
+ LOGGER.debug("Deskshare connection closed.");
+ ce.status = ConnectionEvent.CLOSED;
+ if (UsersUtil.amIPresenter()) {
+ // Let's keep our presenter status before disconnected. We can't
+ // tell the other user's to stop desktop sharing as our connection is broken. (ralam july 24, 2015)
+ wasPresenterBeforeDisconnect = true;
+
+ } else {
+ // stopViewing(); //TODO
+ }
+
+ if (!logoutOnUserCommand) {
+ reconnecting = true;
+
+ var disconnectedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_DISCONNECTED_EVENT);
+ disconnectedEvent.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
+ disconnectedEvent.payload.callback = connect;
+ disconnectedEvent.payload.callbackParameters = [];
+ dispatcher.dispatchEvent(disconnectedEvent);
+ }
+ break;
+
+ case "NetConnection.Connect.InvalidApp":
+ ce.status = ConnectionEvent.INVALIDAPP;
+ dispatcher.dispatchEvent(ce);
+ break;
+
+ case "NetConnection.Connect.AppShutdown":
+ ce.status = ConnectionEvent.APPSHUTDOWN;
+ dispatcher.dispatchEvent(ce);
+ break;
+
+ case "NetConnection.Connect.NetworkChange":
+ LOGGER.info("Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note.");
+ break;
+
+ default :
+ // I dispatch DISCONNECTED incase someone just simply wants to know if we're not connected'
+ // rather than having to subscribe to the events individually
+ ce.status = ConnectionEvent.DISCONNECTED;
+ dispatcher.dispatchEvent(ce);
+ break;
+ }
+ }
+
+ private function securityErrorHandler(event:SecurityErrorEvent):void{
+ var ce:ConnectionEvent = new ConnectionEvent();
+ ce.status = ConnectionEvent.SECURITYERROR;
+ dispatcher.dispatchEvent(ce);
+ }
+
+ /**
+ * Check if anybody is publishing the stream for this room
+ * This method is useful for clients which have joined a room where somebody is already publishing
+ *
+ */
+ private function checkIfStreamIsPublishing(room: String):void{
+ LOGGER.debug("checking if desk share stream is publishing");
+ var event:ConnectionEvent = new ConnectionEvent();
+ event.status = ConnectionEvent.CHECK_FOR_DESKSHARE_STREAM;
+ dispatcher.dispatchEvent(event); // TODO anton send to akka-bbb-apps
+
+ nc.call("deskshare.checkIfStreamIsPublishing", responder, room);
+ }
+
+ public function disconnect():void{
+ logoutOnUserCommand = true;
+ if (nc != null) nc.close();
+ }
+
+ public function connectionSuccessHandler():void{
+ LOGGER.debug("Successully connection to {0}", [uri]);
+
+ checkIfStreamIsPublishing(room);
+ }
+
+ private function debugNetStatusHandler(e:NetStatusEvent):void {
+ LOGGER.debug("netStatusHandler target={0} info={1}", [e.target, ObjectUtil.toString(e.info)]);
+ }
+
+ private function debugAsyncErrorHandler(e:AsyncErrorEvent):void {
+ LOGGER.debug("asyncErrorHandler target={0} info={1}", [e.target, e.text]);
+ }
+
+ public function getConnection():NetConnection{
+ return nc;
+ }
+
+ public function connectionFailedHandler(e:ConnectionEvent):void{
+ LOGGER.error("connection failed to {0} with message {1}", [uri, e.toString()]);
+ }
+
+ public function connectionRejectedHandler(e:ConnectionEvent):void{
+ LOGGER.error("connection rejected to {0} with message {1}", [uri, e.toString()]);
+ }
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/red5/WebRTCConnectionEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/red5/WebRTCConnectionEvent.as
new file mode 100755
index 0000000000..8c735d708c
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/services/red5/WebRTCConnectionEvent.as
@@ -0,0 +1,49 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 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 .
+*
+*/
+package org.bigbluebutton.modules.deskshare.services.red5
+{
+ import flash.events.Event;
+
+ public class WebRTCConnectionEvent extends Event {
+ public static const DESKSHARE_CONNECTION_EVENT:String = "webrtcDeskshare connection event";
+
+ public static const SUCCESS:String = "connection success";
+ public static const FAILED:String = "connection failed";
+ public static const CLOSED:String = "connection closed";
+ public static const REJECTED:String = "connection rejected";
+ public static const INVALIDAPP:String = "connection invalidApp";
+ public static const APPSHUTDOWN:String = "connection appShutdown";
+ public static const SECURITYERROR:String = "connection securityError";
+ public static const DISCONNECTED:String = "connection disconnected";
+ public static const CONNECTING:String = "connection connecting";
+ public static const CONNECTING_RETRY:String = "connection retry";
+ public static const CONNECTING_MAX_RETRY:String = "connection max retry";
+ public static const CHECK_FOR_DESKSHARE_STREAM:String = "connection check webrtcDeskshare publishing";
+ public static const NO_DESKSHARE_STREAM:String = "connection webrtcDeskshare publishing";
+ public static const FAIL_CHECK_FOR_DESKSHARE_STREAM:String = "connection failed check webrtcDeskshare publishing";
+
+ public var status:String = "";
+
+ public var retryAttempts:int = 0;
+
+ public function WebRTCConnectionEvent():void {
+ super(DESKSHARE_CONNECTION_EVENT, true, false);
+ }
+ }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/utils/BrowserCheck.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/utils/BrowserCheck.as
index 624b4c4546..506497f0f5 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/utils/BrowserCheck.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/utils/BrowserCheck.as
@@ -1,7 +1,7 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
-* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+* Copyright (c) 2016 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
@@ -48,6 +48,15 @@ package org.bigbluebutton.modules.deskshare.utils
/* Currently no browser version of Edge supports plugins */
return browser[0] == "Edge";
}
+
+ public static function isChrome():Boolean {
+ var browser:Array = ExternalInterface.call("determineBrowser");
+ return browser[0] == "Chrome";
+ }
+
+ public static function isFirefox():Boolean {
+ var browser:Array = ExternalInterface.call("determineBrowser");
+ return browser[0] == "Firefox";
+ }
}
}
-
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/utils/JavaCheck.as b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/utils/JavaCheck.as
index 4c01c2610e..2e8108434c 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/utils/JavaCheck.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/utils/JavaCheck.as
@@ -1,13 +1,13 @@
/**
* WebMeeting open source conferencing system - http://www.speakserve.org/
- *
- * Copyright (c) 2013 SpeakServe Ltd. and by respective authors (see below).
+ *
+ * Copyright (c) 2016 SpeakServe Ltd. 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.
- *
+ *
* WebMeeting 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.
@@ -19,47 +19,45 @@
package org.bigbluebutton.modules.deskshare.utils
{
import com.asfusion.mate.events.Dispatcher;
-
import flash.external.ExternalInterface;
import flash.utils.setTimeout;
-
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.main.events.ClientStatusEvent;
import org.bigbluebutton.util.i18n.ResourceUtil;
import org.bigbluebutton.modules.deskshare.utils.BrowserCheck;
-
- public class JavaCheck {
+
+ public class JavaCheck {
public static function checkJava():String {
var dispatcher : Dispatcher = new Dispatcher();
var java_version:String = "1.7.0_51";
var xml:XML = BBB.getConfigManager().config.browserVersions;
+
if (xml.@java != undefined) {
java_version = xml.@java.toString();
}
-
+
var isJavaOk: Object = checkJavaVersion(java_version);
-
+
if (isJavaOk.result == "JAVA_OK") {
// Java success
- return null;
-
+ return null;
} else if (isJavaOk.result == "JAVA_NOT_INSTALLED") {
if (!BrowserCheck.isChrome42OrHigher()) {
dispatcher.dispatchEvent(new ClientStatusEvent(ClientStatusEvent.FAIL_MESSAGE_EVENT, ResourceUtil.getInstance().getString("bbb.clientstatus.java.title"), ResourceUtil.getInstance().getString("bbb.clientstatus.java.notinstalled")));
}
- return ResourceUtil.getInstance().getString("bbb.clientstatus.java.notinstalled");
+ return ResourceUtil.getInstance().getString("bbb.clientstatus.java.notinstalled");
} else if (isJavaOk.result == "JAVA_OLDER") {
dispatcher.dispatchEvent(new ClientStatusEvent(ClientStatusEvent.FAIL_MESSAGE_EVENT, ResourceUtil.getInstance().getString("bbb.clientstatus.java.title"), ResourceUtil.getInstance().getString("bbb.clientstatus.java.oldversion")));
- return ResourceUtil.getInstance().getString("bbb.clientstatus.java.oldversion");
+ return ResourceUtil.getInstance().getString("bbb.clientstatus.java.oldversion");
} else {
dispatcher.dispatchEvent(new ClientStatusEvent(ClientStatusEvent.FAIL_MESSAGE_EVENT, ResourceUtil.getInstance().getString("bbb.clientstatus.java.title"), ResourceUtil.getInstance().getString("bbb.clientstatus.java.notdetected")));
- return ResourceUtil.getInstance().getString("bbb.clientstatus.java.notdetected");
- }
+ return ResourceUtil.getInstance().getString("bbb.clientstatus.java.notdetected");
+ }
}
-
+
private static function checkJavaVersion(minVersion: String):Object {
return ExternalInterface.call("checkJavaVersion", minVersion);
}
}
-}
\ No newline at end of file
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/DesktopPublishWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/DesktopPublishWindow.mxml
index 53b90d1e25..644e949432 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/DesktopPublishWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/DesktopPublishWindow.mxml
@@ -69,26 +69,25 @@ with BigBlueButton; if not, see .
import org.bigbluebutton.modules.deskshare.model.DeskshareOptions;
import org.bigbluebutton.modules.deskshare.utils.JavaCheck;
import org.bigbluebutton.modules.deskshare.utils.BrowserCheck;
-
import org.bigbluebutton.util.i18n.ResourceUtil;
-
- private static const LOGGER:ILogger = getClassLogger(DesktopPublishWindow);
+
+ private static const LOGGER:ILogger = getClassLogger(DesktopPublishWindow);
public static const SCALE:Number = 5;
private static const VID_HEIGHT_PAD:Number = 73;
private static const VID_WIDTH_PAD:Number = 6;
-
+
private var images:Images = new Images();
[Bindable] public var bbbLogo:Class = images.bbb_logo;
[Bindable] private var cursorIcon:Class = images.cursorIcon;
-
+
private var connection:NetConnection;
private var uri:String;
private var useTLS:Boolean;
private var room:String;
private var sharingFullScreen:Boolean = false;
private var streaming:Boolean = false;
-
+
private var video:Video;
private var ns:NetStream;
[Bindable] private var videoHolder:UIComponent;
@@ -100,30 +99,30 @@ with BigBlueButton; if not, see .
private var autoStart:Boolean = false;
private var globalDispatcher:Dispatcher = new Dispatcher();
private var javaTimer:Timer;
-
+
[Bindable] private var cursor:Sprite;
[Bindable] private var dsOptions:DeskshareOptions;
-
+
private var calledStopApplet:Boolean = false;
-
+
private function init():void {
dsOptions = new DeskshareOptions();
}
-
+
private function onCreationComplete():void {
windowControls.maximizeRestoreBtn.enabled = false;
-
+
cursor = new Sprite();
cursor.graphics.lineStyle(6, 0xFF0000, 0.6);
- cursor.graphics.drawCircle(0,0,3);
-
- if (BrowserCheck.isUsingLessThanChrome38OnMac()) {
+ cursor.graphics.drawCircle(0,0,3);
+
+ if (BrowserCheck.isUsingLessThanChrome38OnMac()) {
setCurrentState("chromeOnMacWarningState");
} else if (BrowserCheck.isUsingEdgePluginUnsupported()) {
setCurrentState("edgePluginWarningState");
} else {
var javaIssue:String = JavaCheck.checkJava();
-
+
if (javaIssue != null) {
if (BrowserCheck.isChrome42OrHigher()) {
setCurrentState("chrome42WarningState");
@@ -399,11 +398,11 @@ with BigBlueButton; if not, see .
closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopPublish.closeBtn.accessibilityName");
}
}
-
+
private function localeChanged(e:Event):void{
resourcesChanged();
}
-
+
private function closePublishWindow(event:ViewStreamEvent):void{
stopStream();
closeWindow();
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/WebRTCDesktopPublishWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/WebRTCDesktopPublishWindow.mxml
new file mode 100755
index 0000000000..d0f7b0499a
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/WebRTCDesktopPublishWindow.mxml
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ this.width - VID_WIDTH_PAD) && (captureHeight < this.height - VID_HEIGHT_PAD)){
+ vidW = this.width - VID_WIDTH_PAD;
+ vidH = (captureHeight / captureWidth) * vidW;
+ }
+ else if( ((captureWidth < this.width - VID_WIDTH_PAD) && (captureHeight > this.height - VID_HEIGHT_PAD))
+ || ((captureWidth > this.width - VID_WIDTH_PAD) && (captureHeight > this.height - VID_HEIGHT_PAD)) ){
+ vidH = this.height - VID_HEIGHT_PAD;
+ vidW = (captureWidth / captureHeight) * vidH;
+ }
+ else{
+ vidW = captureWidth;
+ vidH = captureHeight;
+ }
+
+ LOGGER.debug("webrtcDeskshare preview[{0},{1}][{2},{3}]", [captureWidth, captureHeight, vidW, vidH]);
+ video = new Video(vidW, vidH);
+ video.width = vidW;
+ video.height = vidH;
+ videoHolder.width = vidW;
+ videoHolder.height = vidH;
+ video.x = videoHolder.x = (this.width - VID_WIDTH_PAD - vidW) / 2;
+ video.y = videoHolder.y = (this.height - VID_HEIGHT_PAD - vidH) / 2;
+
+ videoHolder.addChild(video);
+ this.addChild(videoHolder);
+
+ ns = new NetStream(connection);
+ ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
+ ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
+ ns.client = this;
+ ns.bufferTime = 0;
+ ns.receiveVideo(true);
+ ns.receiveAudio(false);
+ video.attachNetStream(ns);
+
+ ns.play(stream);
+
+ btnClosePublish.enabled = true;
+ }
+
+ private function stopStream():void{
+ streaming = false;
+ captureHeight = Capabilities.screenResolutionY;
+ captureWidth = Capabilities.screenResolutionX;
+ ns.close();
+ }
+
+ private function onAsyncError(e:AsyncErrorEvent):void{
+ LOGGER.debug("VIdeoWindow::asyncerror {0}", [e.toString()]);
+ }
+
+ private function onNetStatus(e:NetStatusEvent):void{
+ switch(e.info.code){
+ case "NetStream.Publish.Start":
+ LOGGER.debug("NetStream.Publish.Start for broadcast stream {0}", [stream]);
+ break;
+ case "NetStream.Play.UnpublishNotify":
+ LOGGER.debug("NetStream.Play.UnpublishNotify for broadcast stream {0}", [stream]);
+ stopSharing();
+ break;
+ case "NetStream.Play.Start":
+ LOGGER.debug("Netstatus: {0}", [e.info.code]);
+ globalDispatcher.dispatchEvent(new BBBEvent(BBBEvent.DESKSHARE_STARTED));
+ }
+ }
+
+ private function onChangedPresenter(e:Event):void{
+ stopSharing();
+ closeWindow();
+ }
+
+ private function closeWindow():void {
+ // LOGGER.debug("Calling stopApplet in closeWindow()");
+ dispatchEvent(new WebRTCShareWindowEvent(WebRTCShareWindowEvent.CLOSE));
+ }
+
+ /*
+ * Override the close handler. We want the Event Map to send a message to
+ * the MDIManager to close this window;
+ */
+ override public function close(event:MouseEvent = null):void {
+ stopSharing();
+ closeWindow();
+ }
+
+ override protected function resourcesChanged():void{
+ super.resourcesChanged();
+ this.title = ResourceUtil.getInstance().getString('bbb.desktopPublish.title');
+
+ if (titleBarOverlay != null) {
+ titleBarOverlay.accessibilityName = ResourceUtil.getInstance().getString('bbb.desktopPublish.title');
+ }
+
+ if (windowControls != null) {
+ minimizeBtn.toolTip = ResourceUtil.getInstance().getString('bbb.desktopPublish.minimizeBtn.toolTip');
+ minimizeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopPublish.minimizeBtn.accessibilityName");
+
+ maximizeRestoreBtn.toolTip = ResourceUtil.getInstance().getString('bbb.desktopPublish.maximizeRestoreBtn.toolTip');
+ maximizeRestoreBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopPublish.maximizeRestoreBtn.accessibilityName");
+
+ closeBtn.toolTip = ResourceUtil.getInstance().getString('bbb.desktopPublish.closeBtn.toolTip');
+ closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopPublish.closeBtn.accessibilityName");
+ }
+ }
+
+ private function localeChanged(e:Event):void{
+ resourcesChanged();
+ }
+
+ private function closePublishWindow(event:WebRTCViewStreamEvent):void{
+ stopStream();
+ closeWindow();
+ }
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/WebRTCDesktopViewWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/WebRTCDesktopViewWindow.mxml
new file mode 100755
index 0000000000..d2ba876ca5
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/WebRTCDesktopViewWindow.mxml
@@ -0,0 +1,388 @@
+
+
+
+
+
+
+
+
+
+
+ 0) p_bw = rest[0];
+ // your application should do something here
+ // when the bandwidth check is complete
+ trace("bandwidth = " + p_bw + " Kbps.");
+ }
+
+ public function getPrefferedPosition():String{
+ return MainCanvas.DESKTOP_SHARING_VIEW;
+ }
+
+ /**
+ * resizes the desktop sharing video to fit to this window
+ */
+ private function fitToWindow():void{
+ if (videoIsSmallerThanWindow()) {
+ fitWindowToVideo();
+ }
+
+ // Ignore if we are displaying the actual size of the video
+ if (! btnActualSize.selected) {
+ fitVideoToWindow();
+ }
+ }
+
+ private function fitVideoToWindow():void {
+ if (this.width < this.height) {
+ fitToWidthAndAdjustHeightToMaintainAspectRatio();
+ } else {
+ fitToHeightAndAdjustWidthToMaintainAspectRatio();
+ }
+ }
+
+ private function fitWindowToVideo():void {
+ video.width = videoWidth;
+ videoHolder.width = videoWidth;
+ video.height = videoHeight;
+ videoHolder.height = videoHeight;
+ this.height = videoHeight + VIDEO_HEIGHT_PADDING;
+ this.width = videoWidth + VIDEO_WIDTH_PADDING;
+ }
+
+ private function videoIsSmallerThanWindow():Boolean {
+ return (videoHeight < this.height) && (videoWidth < this.width);
+ }
+
+
+ private function fitToWidthAndAdjustHeightToMaintainAspectRatio():void {
+ video.width = this.width - VIDEO_WIDTH_PADDING;
+ videoHolder.width = video.width;
+ // Maintain aspect-ratio
+ video.height = (videoHeight * video.width) / videoWidth;
+ videoHolder.height = video.height;
+ this.height = video.height + VIDEO_HEIGHT_PADDING;
+ }
+
+ private function fitToHeightAndAdjustWidthToMaintainAspectRatio():void {
+ video.height = this.height - VIDEO_HEIGHT_PADDING;
+ videoHolder.height = video.height;
+ // Maintain aspect-ratio
+ video.width = (videoWidth * video.height) / videoHeight;
+ videoHolder.width = video.width;
+ this.width = video.width + VIDEO_WIDTH_PADDING;
+ }
+
+ /**
+ * resizes the desktop sharing video to actual video resolution
+ */
+ private function fitToActualSize():void{
+ if (videoIsSmallerThanWindow()) {
+ fitWindowToVideo();
+ } else {
+ video.width = videoWidth;
+ videoHolder.width = videoWidth;
+ video.height = videoHeight;
+ videoHolder.height = videoHeight;
+ }
+ }
+
+ private function determineHowToDisplayVideo():void {
+ if (btnActualSize.selected) {
+ fitToActualSize();
+ btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.desktopView.fitToWindow');
+ btnActualSize.label = ResourceUtil.getInstance().getString('bbb.desktopView.fitToWindow');
+ } else {
+ fitToWindow();
+ btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.desktopView.actualSize');
+ btnActualSize.label = ResourceUtil.getInstance().getString('bbb.desktopView.actualSize');
+ }
+ }
+
+ private function closeWindow():void {
+ dispatchEvent(new ViewWindowEvent(ViewWindowEvent.CLOSE));
+ }
+
+ override protected function resourcesChanged():void{
+ super.resourcesChanged();
+ this.title = ResourceUtil.getInstance().getString('bbb.desktopView.title');
+
+ if (windowControls != null) {
+ minimizeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.minimizeBtn.toolTip");
+ minimizeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopView.minimizeBtn.accessibilityName");
+
+ maximizeRestoreBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.maximizeRestoreBtn.toolTip");
+ maximizeRestoreBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopView.maximizeRestoreBtn.accessibilityName");
+
+ closeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.closeBtn.toolTip");
+ closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopView.closeBtn.accessibilityName");
+ }
+ }
+
+ private function localeChanged(e:Event):void{
+ resourcesChanged();
+ }
+
+ ]]>
+
+
+
+
+
+
+
+
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
index 8b72d806e1..f2a9191b52 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
@@ -47,27 +47,37 @@ package org.bigbluebutton.modules.users.services
import org.bigbluebutton.main.model.users.events.UsersConnectionEvent;
import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
+ import org.bigbluebutton.modules.present.events.CursorEvent;
+ import org.bigbluebutton.modules.present.events.NavigationEvent;
+ import org.bigbluebutton.modules.present.events.RemovePresentationEvent;
+ import org.bigbluebutton.modules.present.events.UploadEvent;
+ import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
+ import org.bigbluebutton.modules.deskshare.events.ViewStreamEvent;
+ import org.bigbluebutton.modules.deskshare.events.WebRTCViewStreamEvent;
+ import org.bigbluebutton.main.api.JSLog;
+ import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
+
public class MessageReceiver implements IMessageListener
{
- private static const LOGGER:ILogger = getClassLogger(MessageReceiver);
-
+ private static const LOGGER:ILogger = getClassLogger(MessageReceiver);
+
private var dispatcher:Dispatcher;
private var _conference:Conference;
private static var globalDispatcher:Dispatcher = new Dispatcher();
-
+
public function MessageReceiver() {
_conference = UserManager.getInstance().getConference();
BBB.initConnectionManager().addMessageListener(this);
this.dispatcher = new Dispatcher();
}
-
+
public function onMessage(messageName:String, message:Object):void {
-// LOGGER.debug(" received message " + messageName);
-
+ // LOGGER.debug(" received message " + messageName);
+
switch (messageName) {
case "getUsersReply":
handleGetUsersReply(message);
- break;
+ break;
case "assignPresenterCallback":
handleAssignPresenterCallback(message);
break;
@@ -128,12 +138,9 @@ package org.bigbluebutton.modules.users.services
case "permissionsSettingsChanged":
handlePermissionsSettingsChanged(message);
break;
- case "userLocked":
+ case "userLocked":
handleUserLocked(message);
break;
- case "userEjectedFromMeeting":
- handleUserEjectedFromMeeting(message);
- break;
// Breakout room feature
case "breakoutRoomsList":
handleBreakoutRoomsList(message)
@@ -153,17 +160,40 @@ package org.bigbluebutton.modules.users.services
case "breakoutRoomClosed":
handleBreakoutRoomClosed(message);
break;
+ case "userEjectedFromMeeting":
+ handleUserEjectedFromMeeting(message);
+ break;
+ case "DeskShareRTMPBroadcastNotification":
+ handleDeskShareRTMPBroadcastNotification(message);
+ break;
}
- }
-
- private function handleUserEjectedFromMeeting(msg: Object):void {
- UsersUtil.setUserEjected();
- }
-
+ }
+
+ private function handleDeskShareRTMPBroadcastNotification(msg:Object):void {
+ LOGGER.debug("*** handleDeskShareRTMPBroadcastNotification **** \n", [msg]);
+
+ var event:WebRTCViewStreamEvent;
+ if (msg.broadcasting) {
+ event = new WebRTCViewStreamEvent(WebRTCViewStreamEvent.START);
+ } else {
+ event = new WebRTCViewStreamEvent(WebRTCViewStreamEvent.STOP);
+ }
+
+ event.videoWidth = msg.width;
+ event.videoHeight = msg.height;
+ event.rtmp = msg.rtmpUrl;
+
+ dispatcher.dispatchEvent(event);
+ }
+
+ private function handleUserEjectedFromMeeting(msg: Object):void {
+ UsersUtil.setUserEjected();
+ }
+
private function handleUserLocked(msg:Object):void {
var map:Object = JSON.parse(msg.msg);
var user:BBBUser = UsersUtil.getUser(map.user);
-
+
if(user.userLocked != map.lock)
user.lockStatusChanged(map.lock);
return;
@@ -192,6 +222,7 @@ package org.bigbluebutton.modules.users.services
var e:BBBEvent = new BBBEvent(BBBEvent.CHANGE_RECORDING_STATUS);
e.payload.remote = true;
e.payload.recording = recording;
+
dispatcher.dispatchEvent(e);
}
@@ -558,6 +589,7 @@ package org.bigbluebutton.modules.users.services
user.isLeavingFlag = false;
user.listenOnly = joinedUser.listenOnly;
user.userLocked = joinedUser.locked;
+ user.avatarURL = joinedUser.avatarURL;
LOGGER.info("User joined = " + JSON.stringify(user));
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/EmojiGrid.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/EmojiGrid.as
index 412e213f25..79aacc9b0e 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/EmojiGrid.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/EmojiGrid.as
@@ -17,7 +17,7 @@
*
*/
package org.bigbluebutton.modules.users.views {
-
+
import com.asfusion.mate.events.Dispatcher;
import flash.events.MouseEvent;
@@ -35,14 +35,14 @@ package org.bigbluebutton.modules.users.views {
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.model.users.events.EmojiStatusEvent;
import org.bigbluebutton.util.i18n.ResourceUtil;
-
+
public class EmojiGrid extends VBox {
- private const EMOJIS:Array = ["raiseHand", "happy", "neutral", "sad", "confused", "away"];
-
+ private const EMOJIS:Array = ["raiseHand", "happy", "neutral", "sad", "confused", "away", "thumbsUp", "thumbsDown", "applause"];
+
private var dispatcher:Dispatcher;
-
+
private var images:Images;
-
+
public function EmojiGrid() {
dispatcher = new Dispatcher();
images = new Images();
@@ -53,7 +53,7 @@ package org.bigbluebutton.modules.users.views {
addRemoveEmoji();
this.setStyle("paddingBottom", 10);
}
-
+
private function drawEmoji():void {
var box:VBox = new VBox();
box.styleName = "emojiGridTile";
@@ -83,7 +83,7 @@ package org.bigbluebutton.modules.users.views {
}
this.addChild(box);
}
-
+
private function addRemoveEmoji():void {
var button:Button = new Button();
button.id = "btnnone";
@@ -100,7 +100,7 @@ package org.bigbluebutton.modules.users.views {
button.addEventListener(MouseEvent.CLICK, buttonMouseEventHandler);
this.addChild(button);
}
-
+
protected function buttonMouseEventHandler(event:MouseEvent):void {
var clickedButton:Button = event.target as Button;
if (!clickedButton.toggle) {
@@ -112,11 +112,11 @@ package org.bigbluebutton.modules.users.views {
}
hide();
}
-
+
protected function mouseDownOutsideHandler(event:FlexMouseEvent):void {
hide();
}
-
+
/**
* Hides the menu
*/
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
index d99b207828..350be55a89 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
@@ -475,7 +475,10 @@
}
public function remoteRaiseHand(e:ShortcutEvent):void{
- dispatchEvent(new EmojiStatusEvent(EmojiStatusEvent.EMOJI_STATUS, "raiseHand"));
+ if (UserManager.getInstance().getConference().myEmojiStatus == "raiseHand")
+ dispatchEvent(new EmojiStatusEvent(EmojiStatusEvent.EMOJI_STATUS, "none"));
+ else
+ dispatchEvent(new EmojiStatusEvent(EmojiStatusEvent.EMOJI_STATUS, "raiseHand"));
}
private function remoteMinimize():void{
@@ -533,7 +536,11 @@
}
private function remoteMuteAllButPres(e:ShortcutEvent):void{
- muteAlmostAll();
+ if (!roomMuted) {
+ muteAlmostAll();
+ } else {
+ muteAll();
+ }
}
]]>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserGraphicHolder.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserGraphicHolder.mxml
index dc6f268c79..7c89cf12c3 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserGraphicHolder.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserGraphicHolder.mxml
@@ -98,7 +98,7 @@ with BigBlueButton; if not, see .
public function loadAvatar(options:VideoConfOptions):void {
avatar.user = _user;
avatar.options = options;
- avatar.load(UsersUtil.getAvatarURL());
+ avatar.load(UsersUtil.getUserAvatarURL(_user.userID));
avatarVisibility = true;
setUserProperties();
diff --git a/bigbluebutton-config/bigbluebutton-release b/bigbluebutton-config/bigbluebutton-release
index edaccb8818..eb747a6170 100644
--- a/bigbluebutton-config/bigbluebutton-release
+++ b/bigbluebutton-config/bigbluebutton-release
@@ -1 +1 @@
-BIGBLUEBUTTON_RELEASE=1.0.0-RC
+BIGBLUEBUTTON_RELEASE=1.0.0
diff --git a/bigbluebutton-config/bin/bbb-record b/bigbluebutton-config/bin/bbb-record
index 233d829f3b..47743a52fe 100755
--- a/bigbluebutton-config/bin/bbb-record
+++ b/bigbluebutton-config/bin/bbb-record
@@ -372,6 +372,7 @@ if [ $DELETE ]; then
rm -rf /var/bigbluebutton/recording/raw/$MEETING_ID*
rm -rf /usr/share/red5/webapps/video/streams/$MEETING_ID
+ rm -rf /usr/share/red5/webapps/video-broadcast/streams/$MEETING_ID
rm -f /var/bigbluebutton/deskshare/$MEETING_ID*.flv
rm -f /var/freeswitch/meetings/$MEETING_ID*.wav
rm -rf /var/bigbluebutton/$MEETING_ID
@@ -400,6 +401,7 @@ if [ $DELETEALL ]; then
rm -rf /var/bigbluebutton/recording/raw/*
find /usr/share/red5/webapps/video/streams -name "*.flv" -exec rm '{}' \;
+ find /usr/share/red5/webapps/video-broadcast/streams -name "*.flv" -exec rm '{}' \;
rm -f /var/bigbluebutton/deskshare/*.flv
rm -f /var/freeswitch/meetings/*.wav
diff --git a/bigbluebutton-config/cron.daily/bigbluebutton b/bigbluebutton-config/cron.daily/bigbluebutton
index 01a0821d5e..0949414171 100755
--- a/bigbluebutton-config/cron.daily/bigbluebutton
+++ b/bigbluebutton-config/cron.daily/bigbluebutton
@@ -41,6 +41,11 @@ find /usr/share/red5/webapps/video/streams/ -name "*.flv.info" -mtime +$history
find /usr/share/red5/webapps/video/streams/ -name "*.flv.meta" -mtime +$history -exec rm '{}' +
find /usr/share/red5/webapps/video/streams/ -type d -empty -mtime +$history -exec rmdir '{}' +
+#
+# Delete webrtc deskshare streams in red5 older than N days
+#
+find /usr/share/red5/webapps/video-broadcast/streams/ -name "*.flv" -mtime +$history -exec rm '{}' \;
+
#
# Delete desktop sharing streams in red5 older than N days
#
diff --git a/bigbluebutton-config/web/css/bbb-bootstrap.css b/bigbluebutton-config/web/css/bbb-bootstrap.css
new file mode 100644
index 0000000000..28e01bd002
--- /dev/null
+++ b/bigbluebutton-config/web/css/bbb-bootstrap.css
@@ -0,0 +1,116 @@
+/*!
+ * This stylesheet is a subset of Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+
+.alert {
+ padding: 15px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.alert h4 {
+ margin-top: 0;
+ color: inherit;
+}
+.alert .alert-link {
+ font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+ margin-bottom: 0;
+}
+.alert > p + p {
+ margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+ padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ color: inherit;
+}
+.alert-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+.alert-success hr {
+ border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+ color: #2b542c;
+}
+.alert-info {
+ color: #31708f;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+.alert-info hr {
+ border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+ color: #245269;
+}
+.alert-warning {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+}
+.alert-warning hr {
+ border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+ color: #66512c;
+}
+.alert-danger {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #ebccd1;
+}
+.alert-danger hr {
+ border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+ color: #843534;
+}
+.close {
+ float: right;
+ font-size: 21px;
+ font-weight: bold;
+ line-height: 1;
+ color: #000;
+ text-shadow: 0 1px 0 #fff;
+ filter: alpha(opacity=20);
+ opacity: .2;
+}
+.close:hover,
+.close:focus {
+ color: #000;
+ text-decoration: none;
+ cursor: pointer;
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+button.close {
+ -webkit-appearance: none;
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+}
+.fade {
+ opacity: 0;
+ -webkit-transition: opacity .15s linear;
+ -o-transition: opacity .15s linear;
+ transition: opacity .15s linear;
+}
+.fade.in {
+ opacity: 1;
+}
diff --git a/bigbluebutton-config/web/default.pdf b/bigbluebutton-config/web/default.pdf
old mode 100755
new mode 100644
index b3e08c05a7..8bd18ac603
Binary files a/bigbluebutton-config/web/default.pdf and b/bigbluebutton-config/web/default.pdf differ
diff --git a/bigbluebutton-config/web/default.ppt b/bigbluebutton-config/web/default.ppt
deleted file mode 100755
index 8390900703..0000000000
Binary files a/bigbluebutton-config/web/default.ppt and /dev/null differ
diff --git a/bigbluebutton-config/web/index.html b/bigbluebutton-config/web/index.html
index ccbee654a9..b5ff34fcc1 100644
--- a/bigbluebutton-config/web/index.html
+++ b/bigbluebutton-config/web/index.html
@@ -9,11 +9,15 @@
-
-
+
+
+
+
+
+
@@ -22,6 +26,10 @@
+
+
+
+
@@ -69,62 +77,62 @@
-
+
Features
-
+
-
+
Record and Playback
BigBlueButton can record your sessions for later playback by students.
-
+
-
+
Whiteboard
The whiteboard controls let you annotate key parts of your presentation.
-
+
-
+
Desktop Sharing
You can broadcast your desktop for all users to see (requires lastest version of Java for presenter only).
-
-
+
+
-
+
WebRTC Audio
Users of Chrome and FireFox browsers will benefit from high-quality, low-latency WebRTC audio. (Users of other browsers will seamlessly use Flash-based audio.)
-
+
-
+
Presentation
You can upload any PDF presentation or MS office document. BigBlueButton keeps everyone in sync with your current slide, zoom, pan, annotations, and mouse pointer.
-
+
-
+
Web Cam
Multiple users can share their webcam at the same time. There is no built-in limit on the number of simultaneously active webcams.
@@ -170,7 +178,7 @@
Getting Started Quickly
-
+
-
+
-
+
@@ -203,11 +211,11 @@
diff --git a/bigbluebutton-config/web/js/bbb-errors.js b/bigbluebutton-config/web/js/bbb-errors.js
new file mode 100644
index 0000000000..ad6513fece
--- /dev/null
+++ b/bigbluebutton-config/web/js/bbb-errors.js
@@ -0,0 +1,23 @@
+function GetURLParameter(sParam) {
+ var sPageURL = decodeURIComponent(window.location.search.substring(1));
+ var sURLVariables = sPageURL.split('&');
+ for (var i = 0; i < sURLVariables.length; i++) {
+ var sParameterName = sURLVariables[i].split('=');
+ if (sParameterName[0] == sParam) {
+ return sParameterName[1];
+ }
+ }
+}
+
+$(document).ready(function() {
+ var sErrors = GetURLParameter('errors');
+ if (typeof sErrors != 'undefined') {
+ var errors = $.parseJSON(sErrors);
+
+ $.each(errors, function( index, error ) {
+ console.info(error.key);
+ $("#messages").append("
×Error: "+error.message+" ");
+ });
+ $('#messages').removeClass('hidden');
+ }
+});
diff --git a/bigbluebutton-config/web/js/bootstrap.min.js b/bigbluebutton-config/web/js/bootstrap.min.js
new file mode 100644
index 0000000000..e79c065134
--- /dev/null
+++ b/bigbluebutton-config/web/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j
document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m
o.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
\ No newline at end of file
diff --git a/bigbluebutton-config/web/js/jquery.min.js b/bigbluebutton-config/web/js/jquery.min.js
new file mode 100644
index 0000000000..6c60672fc5
--- /dev/null
+++ b/bigbluebutton-config/web/js/jquery.min.js
@@ -0,0 +1,5 @@
+/*! jQuery v1.12.0 | (c) jQuery Foundation | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;
+return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML=" a",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,""],legend:[1,""],area:[1,""],param:[1,""],thead:[1,""],tr:[2,""],col:[2,""],td:[3,""],_default:l.htmlSerialize?[0,"",""]:[1,"X","
"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|?\w+;/,ha=/r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?""!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.rnamespace||a.rnamespace.test(g.namespace))&&(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/
-
-
-
-
+
+
+
+
+
+
+
+
+
+
Initializing recording
+
+
+
+
+
+
+
BigBlueButton Playback
+
+
+
+
+
+
+
+
+
Presentation Slides
+
+
+
+
Chat Messages
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
Initializing recording
-
-
-
BigBlueButton Playback
-
-
Slide Thumbnails
-
-
Presentation Slides
-
-
-
-
-
-
-
-
-