diff --git a/Dockerfile b/Dockerfile index c8808ce..5b5579d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,7 +38,7 @@ RUN chmod +x /bin/tini RUN mkdir -p /usr/local/ffmpeg \ && curl -sSL https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz | tar xJvf - -C /usr/local/ffmpeg/ --strip 1 -ADD image/usr/local/lib/web/requirements.txt /tmp/ +ADD image/usr/local/lib/web/backend/requirements.txt /tmp/ RUN pip install setuptools wheel && pip install -r /tmp/requirements.txt ADD image / diff --git a/image/etc/supervisor/conf.d/supervisord.conf b/image/etc/supervisor/conf.d/supervisord.conf index 9d8ab54..48f30e6 100644 --- a/image/etc/supervisor/conf.d/supervisord.conf +++ b/image/etc/supervisor/conf.d/supervisord.conf @@ -7,13 +7,13 @@ directory=/root [program:nginx] priority=10 command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;' -stdout_logfile=/var/log/nginx.log [program:web] priority=10 -directory=/usr/local/lib/web -command=/usr/local/lib/web/run.py -stdout_logfile=/var/log/web.log +directory=/usr/local/lib/web/backend +command=/usr/local/lib/web/backend/run.py +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 [group:x] programs=xvfb,wm,lxpanel,pcmanfm,x11vnc,novnc @@ -22,13 +22,11 @@ programs=xvfb,wm,lxpanel,pcmanfm,x11vnc,novnc priority=10 command=/usr/local/bin/xvfb.sh stopsignal=KILL -stdout_logfile=/var/log/xvfb.log [program:wm] priority=15 command=/usr/bin/openbox environment=DISPLAY=":1",HOME="/root",USER="root" -stdout_logfile=/var/log/openbox.log [program:lxpanel] priority=15 @@ -36,7 +34,6 @@ directory=%HOME% command=/usr/bin/lxpanel --profile LXDE user=%USER% environment=DISPLAY=":1",HOME="%HOME%",USER="%USER%" -stdout_logfile=/var/log/lxpanel.log [program:pcmanfm] priority=15 @@ -44,16 +41,13 @@ directory=%HOME% command=/usr/bin/pcmanfm --desktop --profile LXDE user=%USER% environment=DISPLAY=":1",HOME="%HOME%",USER="%USER%" -stdout_logfile=/var/log/pcmanfm.log [program:x11vnc] priority=20 command=x11vnc -display :1 -xkb -forever -shared -repeat -stdout_logfile=/var/log/x11vnc.log [program:novnc] priority=25 directory=/usr/local/lib/novnc/ command=/usr/local/lib/novnc/utils/launch.sh --listen 6081 -stdout_logfile=/var/log/novnc.log stopasgroup=true diff --git a/image/startup.sh b/image/startup.sh index fcd176f..b10bcf6 100755 --- a/image/startup.sh +++ b/image/startup.sh @@ -32,6 +32,9 @@ mkdir -p $HOME/.config/pcmanfm/LXDE/ ln -sf /usr/local/share/doro-lxde-wallpapers/desktop-items-0.conf $HOME/.config/pcmanfm/LXDE/ chown -R $USER:$USER $HOME +# nginx +sed -i 's#worker_processes .*#worker_processes 1;#' /etc/nginx/nginx.conf + # clearup PASSWORD= diff --git a/image/usr/local/lib/web/config/__init__.py b/image/usr/local/lib/web/backend/config/__init__.py similarity index 100% rename from image/usr/local/lib/web/config/__init__.py rename to image/usr/local/lib/web/backend/config/__init__.py diff --git a/image/usr/local/lib/web/log/__init__.py b/image/usr/local/lib/web/backend/log/__init__.py similarity index 100% rename from image/usr/local/lib/web/log/__init__.py rename to image/usr/local/lib/web/backend/log/__init__.py diff --git a/image/usr/local/lib/web/log/config.py b/image/usr/local/lib/web/backend/log/config.py similarity index 92% rename from image/usr/local/lib/web/log/config.py rename to image/usr/local/lib/web/backend/log/config.py index dff7ea5..0d4fb18 100644 --- a/image/usr/local/lib/web/log/config.py +++ b/image/usr/local/lib/web/backend/log/config.py @@ -35,13 +35,13 @@ class ColoredFormatter(logging.Formatter): class LoggingConfiguration(object): - COLOR_FORMAT = "[%(asctime)s" + \ - "][%(threadName)-22s][%(levelname)s] %(message)s " + \ + COLOR_FORMAT = "%(asctime)s" + \ + " %(levelname)s %(message)s " + \ "(" + BOLD_SEQ + "%(filename)s" + RESET_SEQ + ":%(lineno)d)" - NO_COLOR_FORMAT = "[%(asctime)s][%(threadName)-22s][%(levelname)s] " + \ + NO_COLOR_FORMAT = "%(asctime)s %(levelname)s " + \ "%(message)s " + \ "(%(filename)s:%(lineno)d)" - FILE_FORMAT = "[%(asctime)s][%(threadName)-22s][%(levelname)s] " + \ + FILE_FORMAT = "%(asctime)s %(levelname)s " + \ "%(message)s " @classmethod diff --git a/image/usr/local/lib/web/requirements.txt b/image/usr/local/lib/web/backend/requirements.txt similarity index 100% rename from image/usr/local/lib/web/requirements.txt rename to image/usr/local/lib/web/backend/requirements.txt diff --git a/image/usr/local/lib/web/run.py b/image/usr/local/lib/web/backend/run.py similarity index 91% rename from image/usr/local/lib/web/run.py rename to image/usr/local/lib/web/backend/run.py index bb60282..a5f9ba3 100755 --- a/image/usr/local/lib/web/run.py +++ b/image/usr/local/lib/web/backend/run.py @@ -73,7 +73,7 @@ def main(): import socket os.environ['CONFIG'] = CONFIG - from lightop import app + from vnc import app # websocket conflict: WebSocketHandler if DEBUG or STAGING: @@ -81,16 +81,11 @@ def main(): app.debug = True # app = DebuggedApplication(app, evalex=True) - print('Fork monitor programs') pgid = os.getpgid(0) - procs = [] - procs.extend([subprocess.Popen(program, close_fds=True, shell=True) - for program in PROGRAMS]) signal.signal(signal.SIGTERM, lambda *args: killpg(pgid)) signal.signal(signal.SIGHUP, lambda *args: killpg(pgid)) signal.signal(signal.SIGINT, lambda *args: killpg(pgid)) - print('Running on port ' + str(PORT)) try: app.run(host='', port=PORT) except socket.error as e: @@ -101,7 +96,6 @@ def main(): CONFIG = 'config.Development' if DEBUG else 'config.Production' CONFIG = 'config.Staging' if STAGING else CONFIG PORT = 6079 - PROGRAMS = tuple() signal.signal(signal.SIGCHLD, signal.SIG_IGN) if DEBUG or STAGING: diff --git a/image/usr/local/lib/web/lightop/__init__.py b/image/usr/local/lib/web/backend/vnc/__init__.py similarity index 97% rename from image/usr/local/lib/web/lightop/__init__.py rename to image/usr/local/lib/web/backend/vnc/__init__.py index 4196f25..a046566 100644 --- a/image/usr/local/lib/web/lightop/__init__.py +++ b/image/usr/local/lib/web/backend/vnc/__init__.py @@ -10,11 +10,7 @@ import time # Flask app -app = Flask( - __name__, - static_folder='static', static_url_path='', - instance_relative_config=True -) +app = Flask('novnc2') CONFIG = os.environ.get('CONFIG') or 'config.Development' app.config.from_object('config.Default') app.config.from_object(CONFIG) diff --git a/image/usr/local/lib/web/static/6df2b309.favicon.ico b/image/usr/local/lib/web/static/6df2b309.favicon.ico deleted file mode 100644 index 6527905..0000000 Binary files a/image/usr/local/lib/web/static/6df2b309.favicon.ico and /dev/null differ diff --git a/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.eot b/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index 4a4ca86..0000000 Binary files a/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.svg b/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.svg deleted file mode 100644 index 25691af..0000000 --- a/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.ttf b/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 67fa00b..0000000 Binary files a/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.woff b/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.woff deleted file mode 100644 index 8c54182..0000000 Binary files a/image/usr/local/lib/web/static/fonts/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/image/usr/local/lib/web/static/index.html b/image/usr/local/lib/web/static/index.html deleted file mode 100644 index 226b71d..0000000 --- a/image/usr/local/lib/web/static/index.html +++ /dev/null @@ -1,17 +0,0 @@ - Docker Lightop
# User Volume Action
Container Session Owner Action
\ No newline at end of file diff --git a/image/usr/local/lib/web/static/robots.txt b/image/usr/local/lib/web/static/robots.txt deleted file mode 100644 index ee2cc21..0000000 --- a/image/usr/local/lib/web/static/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# robotstxt.org/ - -User-agent: * diff --git a/image/usr/local/lib/web/static/scripts/046bbd30.main.js b/image/usr/local/lib/web/static/scripts/046bbd30.main.js deleted file mode 100644 index 6f8c70a..0000000 --- a/image/usr/local/lib/web/static/scripts/046bbd30.main.js +++ /dev/null @@ -1 +0,0 @@ -var api={};api.login=function(a,b,c,d){$.ajax({url:"/login",type:"POST",data:{username:a,password:b}}).done(function(a){json=JSON.parse(a),d({session:c,user:json,error:json.error})}).fail(function(a){console.info(a.status+": "+a.statusText)})},api.session_list=function(a){$.ajax({url:"/session",type:"GET"}).done(function(b){var c=[];json=JSON.parse(b),$.each(json,function(a,b){c.push({name:b,value:b})}),a(c)}).fail(function(a){console.info(a.status+": "+a.statusText)})},api.user_list=function(a){$.ajax({url:"/user/",type:"GET"}).done(function(b){var c=[];json=JSON.parse(b),$.each(json,function(a,b){c.push({id:b.id,name:b.name,volume:b.volume})}),a(c)}).fail(function(a){console.info(a.status+": "+a.statusText)})},api.user_add=function(a,b,c){$.ajax({url:"/user/",type:"POST",data:{username:a,password:b}}).done(function(a){json=JSON.parse(a),c("add")}).fail(function(a){console.info(a.status+": "+a.statusText)})},api.user_delete=function(a,b){$.ajax({url:"/user/"+a,type:"DELETE"}).done(function(a){json=JSON.parse(a),b("del")}).fail(function(a){console.info(a.status+": "+a.statusText)})},api.container_list=function(a){$.ajax({url:"/container/",type:"GET"}).done(function(b){var c=[];json=JSON.parse(b),$.each(json,function(a,b){c.push({id:b.id,session:b.session,owner:b.owner})}),a(c)}).fail(function(a){console.info(a.status+": "+a.statusText)})},api.container_delete=function(a,b){$.ajax({url:"/container/"+a,type:"DELETE"}).done(function(a){json=JSON.parse(a),b()}).fail(function(a){console.info(a.status+": "+a.statusText)})};var ui={};ui.bind_login_session=function(a){var b="";a.push({name:"Admin Panel",value:"admin-panel"}),(""==$("#login-session").val()||""==$("#login-session-name").text().trim())&&($("#login-session-name").text(a[0].name),$("#login-session").val(a[0].value)),$.each(a,function(a,c){b+="
  • ",b+='',b+=c.name,b+="",b+="
  • "}),$(".dropdown-menu").html(b)},ui.bind_user_data=function(a){var b="";$.each(a,function(a,c){b+="",b+=""+c.id+"",b+=""+c.name+"",b+=""+c.volume.join("
    ")+"",b+="admin"==c.name?'':'',b+=""}),""==b&&(b='No data'),$("#tbody-account").html(b),$("button.btn-remove-user").on("click",null,ui.model_delete_user)},ui.bind_container_data=function(a){var b="";$.each(a,function(a,c){b+="",b+=""+c.id+"",b+=""+c.session+"",b+=""+c.owner+"",b+='',b+=""}),""==b&&(b='No data'),$("#tbody-container").html(b),$("button.btn-remove-container").on("click",null,ui.model_delete_container)},ui.model_delete_user=function(){var a=$(this).closest("td").prev("td").prev("td"),b=a.prev("td").text(),c=a.text();$("#del-user-modal .modal-body > p").text(c),$("#del-user-id").val(b),$("#del-user-modal").modal("show")},ui.model_delete_container=function(){var a=$(this).closest("td").prev("td"),b=a.prev("td").prev("td").text(),c=a.prev("td").text(),d=a.text();a=$("#del-container-modal .modal-body > p"),a.text(b),a.next("p").text(c),a.next("p").next("p").text(d),$("#del-container-id").val(b),$("#del-container-modal").modal("show")},ui.do_switch_navbar=function(){var a,b=!1;$("#navbar > ul > li").each(function(){a=$(this).children("a").prop("hash"),window.location.hash==a?(b=!0,$(this).addClass("active"),$("#layout-"+a.substring(1)).show()):($(this).removeClass("active"),$("#layout-"+a.substring(1)).hide())}),b||(a=$("#navbar > ul > li:first-child a").prop("hash"),$("#navbar > ul > li:first-child").addClass("active"),$("#layout-"+a.substring(1)).show())},ui.do_session_login=function(a){return void 0!=a.error?void $("#login-msg").text(a.error.code+": "+a.error.message):("admin-panel"==a.session&&a.user.isAdmin?api.user_list(ui.bind_user_data):window.location="ubuntu-trusty-lxde"==a.session?"/u/"+a.session+"/vnc_auto.html?width="+(window.innerWidth-16)+"&height="+(window.innerHeight-16):"/u/"+a.session+"/",void $("#login-modal").modal("hide"))},ui.do_user_login=function(){var a=$("#login-username").val(),b=$("#login-password").val(),c=$("#login-session").val();api.login(a,b,c,ui.do_session_login)},ui.do_add_user=function(){var a=$("#add-username").val(),b=$("#add-password").val();api.user_add(a,b,ui.do_refresh_user_list)},ui.do_delete_user=function(){var a=$("#del-user-id").val();api.user_delete(a,ui.do_refresh_user_list)},ui.do_refresh_user_list=function(a){api.user_list(ui.bind_user_data),$("#"+a+"-user-modal").modal("hide")},ui.do_delete_container=function(){var a=$("#del-container-id").val();api.container_delete(a,ui.do_refresh_container_list)},ui.do_refresh_container_list=function(){api.container_list(ui.bind_container_data),$("#del-container-modal").modal("hide")},$(window).hashchange(function(){ui.do_switch_navbar()}),$(".dropdown-menu").on("click","li a",function(){$("#login-session-name").text($(this).text()),$("#login-session").val($(this).attr("data-value"))}),$("#btn-sign-in").on("click",null,ui.do_user_login),$("#btn-add-user").on("click",null,ui.do_add_user),$("#btn-del-user").on("click",null,ui.do_delete_user),$("#btn-del-container").on("click",null,ui.do_delete_container); \ No newline at end of file diff --git a/image/usr/local/lib/web/static/scripts/2c80432f.plugins.js b/image/usr/local/lib/web/static/scripts/2c80432f.plugins.js deleted file mode 100644 index 2c89978..0000000 --- a/image/usr/local/lib/web/static/scripts/2c80432f.plugins.js +++ /dev/null @@ -1,2 +0,0 @@ -+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=this.unpin=this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.0",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>=i?"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=a("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),+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.0",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){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(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 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.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport);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.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),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.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)),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);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-mp.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.width&&(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(){return this.$tip=this.$tip||a(this.options.template)},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))),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)})};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,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$backdrop=this.isShown=null,this.scrollbarWidth=0,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.0",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.$body.addClass("modal-open"),this.setScrollbar(),this.escape(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),e&&d.$element[0].offsetWidth,d.$element.addClass("in").attr("aria-hidden",!1),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$element.find(".modal-dialog").one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('