diff --git a/.gitignore b/.gitignore index 68673be0f13dd517e857dc2b2762917693701e78..36c259b3c9f854636b6a702eea267cb92bfe7a0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,36 @@ -*.pyc +# SB User Related # +###################### cache/* cache.db* config.ini Logs/* sickbeard.db* autoProcessTV/autoProcessTV.cfg +server.crt +server.key + +# Compiled source # +###################### +*.py[co] + +# IDE specific # +###################### *.bak +*.tmp +*.wpr +*.project +*.cproject +*.tmproj +*.tmproject +*.sw? + +# OS generated files # +###################### +.Spotlight-V100 +.Trashes .DS_Store +desktop.ini +ehthumbs.db +Thumbs.db +.directory +*~ \ No newline at end of file diff --git a/SickBeard.py b/SickBeard.py index fcd5c1b6e2bac1e5d999afe3c46c8ca4b73e0818..1b805f4fff18bae068c6cbc945e19ae9426941bc 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -18,6 +18,9 @@ # along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. import sys +if sys.version_info < (2, 5): + print "Sorry, requires Python 2.5 or higher." + sys.exit(1) # we only need this for compiling an EXE and I will just always do that on 2.6+ if sys.hexversion >= 0x020600F0: @@ -45,6 +48,7 @@ from lib.configobj import ConfigObj signal.signal(signal.SIGINT, sickbeard.sig_handler) signal.signal(signal.SIGTERM, sickbeard.sig_handler) + def loadShowsFromDB(): """ Populates the showList with shows from the database @@ -58,11 +62,12 @@ def loadShowsFromDB(): curShow = TVShow(int(sqlShow["tvdb_id"])) sickbeard.showList.append(curShow) except Exception, e: - logger.log(u"There was an error creating the show in "+sqlShow["location"]+": "+str(e).decode('utf-8'), logger.ERROR) + logger.log(u"There was an error creating the show in " + sqlShow["location"] + ": " + str(e).decode('utf-8'), logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) #TODO: make it update the existing shows if the showlist has something in it + def daemonize(): """ Fork off as a daemon @@ -89,7 +94,7 @@ def daemonize(): if pid != 0: sys.exit(0) except OSError, e: - raise RuntimeError("2st fork failed: %s [%d]" % + raise RuntimeError("2nd fork failed: %s [%d]" % (e.strerror, e.errno)) dev_null = file('/dev/null', 'r') @@ -100,6 +105,7 @@ def daemonize(): logger.log(u"Writing PID " + pid + " to " + str(sickbeard.PIDFILE)) file(sickbeard.PIDFILE, 'w').write("%s\n" % pid) + def main(): """ TV for me @@ -112,6 +118,7 @@ def main(): sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] sickbeard.CREATEPID = False + sickbeard.DAEMON = False sickbeard.SYS_ENCODING = None @@ -192,7 +199,7 @@ def main(): raise SystemExit("Unable to write PID file: %s [%d]" % (e.strerror, e.errno)) else: logger.log(u"Not running in daemon mode. PID file creation disabled.") - + # if they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = os.path.join(sickbeard.DATA_DIR, "config.ini") @@ -213,12 +220,12 @@ def main(): if os.path.isfile(sickbeard.CONFIG_FILE): raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable") elif not os.access(os.path.dirname(sickbeard.CONFIG_FILE), os.W_OK): - raise SystemExit("Config file root dir '" + os.path.dirname(sickbeard.CONFIG_FILE) + "' must be writeable") - + raise SystemExit("Config file root dir '" + os.path.dirname(sickbeard.CONFIG_FILE) + "' must be writeable") + os.chdir(sickbeard.DATA_DIR) - + if consoleLogging: - print "Starting up Sick Beard "+SICKBEARD_VERSION+" from " + sickbeard.CONFIG_FILE + print "Starting up Sick Beard " + SICKBEARD_VERSION + " from " + sickbeard.CONFIG_FILE # load the config and publish it to the sickbeard package if not os.path.isfile(sickbeard.CONFIG_FILE): @@ -233,18 +240,16 @@ def main(): if sickbeard.DAEMON: daemonize() - + # use this pid for everything sickbeard.PID = os.getpid() if forcedPort: - logger.log(u"Forcing web server to port "+str(forcedPort)) + logger.log(u"Forcing web server to port " + str(forcedPort)) startPort = forcedPort else: startPort = sickbeard.WEB_PORT - logger.log(u"Starting Sick Beard on http://localhost:"+str(startPort)) - if sickbeard.WEB_LOG: log_dir = sickbeard.LOG_DIR else: @@ -263,17 +268,20 @@ def main(): try: initWebServer({ - 'port': startPort, - 'host': webhost, + 'port': startPort, + 'host': webhost, 'data_root': os.path.join(sickbeard.PROG_DIR, 'data'), - 'web_root': sickbeard.WEB_ROOT, - 'log_dir': log_dir, - 'username': sickbeard.WEB_USERNAME, - 'password': sickbeard.WEB_PASSWORD, + 'web_root': sickbeard.WEB_ROOT, + 'log_dir': log_dir, + 'username': sickbeard.WEB_USERNAME, + 'password': sickbeard.WEB_PASSWORD, + 'enable_https': sickbeard.ENABLE_HTTPS, + 'https_cert': sickbeard.HTTPS_CERT, + 'https_key': sickbeard.HTTPS_KEY, }) except IOError: logger.log(u"Unable to start web server, is something else running on port %d?" % startPort, logger.ERROR) - if sickbeard.LAUNCH_BROWSER: + if sickbeard.LAUNCH_BROWSER and not sickbeard.DAEMON: logger.log(u"Launching browser and exiting", logger.ERROR) sickbeard.launchBrowser(startPort) sys.exit() @@ -286,7 +294,7 @@ def main(): sickbeard.start() # launch browser if we're supposed to - if sickbeard.LAUNCH_BROWSER and not noLaunch: + if sickbeard.LAUNCH_BROWSER and not noLaunch and not sickbeard.DAEMON: sickbeard.launchBrowser(startPort) # start an update if we're supposed to @@ -297,7 +305,6 @@ def main(): while (True): if sickbeard.invoked_command: - logger.log(u"Executing invoked command: "+repr(sickbeard.invoked_command)) sickbeard.invoked_command() sickbeard.invoked_command = None diff --git a/autoProcessTV/autoProcessTV.cfg.sample b/autoProcessTV/autoProcessTV.cfg.sample index e194862c911a54332824f69787d1c161d3550f40..15dc900c2d24944e736388a6b36d64fb3691bfbc 100644 --- a/autoProcessTV/autoProcessTV.cfg.sample +++ b/autoProcessTV/autoProcessTV.cfg.sample @@ -3,4 +3,5 @@ host=localhost port=8081 username= password= -web_root= \ No newline at end of file +web_root= +ssl=0 \ No newline at end of file diff --git a/autoProcessTV/autoProcessTV.py b/autoProcessTV/autoProcessTV.py index 974830e7419182254e69cdacd24aacffc214bfcd..413c93ff1b4bf4b29686d4275299eb727be2990d 100644 --- a/autoProcessTV/autoProcessTV.py +++ b/autoProcessTV/autoProcessTV.py @@ -57,6 +57,10 @@ def processEpisode(dirName, nzbName=None): port = config.get("SickBeard", "port") username = config.get("SickBeard", "username") password = config.get("SickBeard", "password") + try: + ssl = int(config.get("SickBeard", "ssl")) + except (ConfigParser.NoOptionError, ValueError): + ssl = 0 try: web_root = config.get("SickBeard", "web_root") @@ -73,7 +77,12 @@ def processEpisode(dirName, nzbName=None): myOpener = AuthURLOpener(username, password) - url = "http://" + host + ":" + port + web_root + "/home/postprocess/processEpisode?" + urllib.urlencode(params) + if ssl: + protocol = "https://" + else: + protocol = "http://" + + url = protocol + host + ":" + port + web_root + "/home/postprocess/processEpisode?" + urllib.urlencode(params) print "Opening URL:", url diff --git a/data/css/config.css b/data/css/config.css index 8c259d704caf0a218a51a8e6fdb11dfae5ebec83..0898cc29627299b1c89c926c443249ae7c280f75 100644 --- a/data/css/config.css +++ b/data/css/config.css @@ -1,5 +1,6 @@ #config{text-align:center;padding:0 30px 20px;} #config *{font-family:"Trebuchet MS", Verdana, sans-serif;margin:0;padding:0;} +#config input[type=submit], #config input[type=button] { padding: 1px 5px; } #config h3 a {text-decoration: none;} #config h3 img {vertical-align: baseline; padding-right: 5px;} #config ul{list-style-type:none;padding-left: 20px;} @@ -13,7 +14,7 @@ #config-components{float:left;width:auto;} #config-components-border{float:left;width:auto;border-top:1px solid #999;padding:5px 0;} #config .title-group{border-bottom:1px dotted #666;position:relative;padding:25px 15px 25px;} -#config .component-group{border-bottom:1px dotted #666;position:relative;padding:15px 15px 25px;} +#config .component-group{border-top:1px dotted #666;position:relative;padding:15px 15px 25px;} #config .component-group-desc{float:left;width:235px;} #config .component-group-desc h3{font-size:1.5em;} #config .component-group-desc p{width:85%;font-size:1.2em;color:#666;margin:.8em 0;} diff --git a/data/css/default.css b/data/css/default.css index bef45a0731e672929824c19eaef48b73d53b968d..e87bf2429d7cf453a401c63c6f83ad1560b47ab8 100644 --- a/data/css/default.css +++ b/data/css/default.css @@ -3,6 +3,7 @@ img { border: 0; vertical-align: middle;} body { +text-rendering: optimizeLegibility; background-color:#F5F1E4; color:#000; font-family:'Verdana', 'Helvetica', 'Sans-serif', 'sans'; @@ -56,14 +57,15 @@ margin:0; h1 { text-align:left; -font-size:19px; -line-height:20px; +font-size:21px; +line-height:23px; font-weight:400; +} +h1.title { padding-bottom:4px; margin-bottom:12px; border-bottom:1px solid #4e4e4e; } - h1 a { text-decoration:none; } @@ -123,23 +125,34 @@ font-size: 1em; } .sickbeardTable { -width:100%; -margin-left:auto; -margin-right:auto; + width: 100%; + margin-left:auto; + margin-right:auto; + text-align:left; + color: #000; + background-color: #fff; + border-spacing: 0; +} +.sickbeardTable th, +.sickbeardTable td { + padding: 4px; + border-left: #fff 1px solid; + border-top: #fff 1px solid; +} +.sickbeardTable th:first-child, +.sickbeardTable td:first-child { + border-left: none; } .sickbeardTable th{ -padding:3px; -font-weight:700; -background-color:#333; -color:#FFF; -text-shadow: -1px -1px 0 rgba(0,0,0,0.3); -} -.sickbeardTable td{ -padding:4px; + border-collapse: collapse; + background-color: #333; + color: #fff; + text-shadow: -1px -1px 0 rgba(0,0,0,0.3); + text-align: center; } .sickbeardTable tfoot a { -color:#FFF; -text-decoration: none; + color:#fff; + text-decoration: none; } .row { @@ -148,9 +161,10 @@ clear:left; .plotInfo { cursor:help; -margin-left: 8px; -position: relative; +font-weight: 700; float: right; +position: relative; +margin-left: 8px; } #tooltip { @@ -270,6 +284,10 @@ padding:2px; background-color:#000; color:#fff; } +.sf-menu li:hover, .sf-menu li.sfHover, +.sf-menu a:focus, .sf-menu a:hover, .sf-menu a:active { +color: #f5f5f5 !important; +} #donate { line-height:1em; background: #57442B; @@ -331,7 +349,10 @@ div#addShowPortal button div.button img{ position: absolute; display: block; to div#addShowPortal button .buttontext { position: relative; display: block; padding: 0.1em 0.4em 0.1em 4.4em; text-align: left; } #rootDirs, #rootDirsControls { width: 50%; min-width: 400px; } + +td.tvShow { font-weight: bold; } +td.tvShow a {text-decoration: none; font-size: 1.2em; } td.tvShow:hover { background-color: #cfcfcf !important; cursor: pointer; } .navShow { display: inline; cursor: pointer; vertical-align: top; } @@ -353,6 +374,17 @@ a.whitelink { color: white; } } div.ui-pnotify { min-width: 340px; max-width: 550px; width: auto !important;} +/* override for qtip2 */ +.ui-tooltip-sb .ui-tooltip-titlebar a { color: #222222; text-decoration: none; } +.ui-tooltip, .qtip { max-width: 500px !important; } + +option.flag { + padding-left: 35px; + background-color: #fff; + background-repeat: no-repeat; + background-position: 10px 50%; +} + span.quality { font: bold 1em/1.2em verdana, sans-serif; background: none repeat scroll 0 0 #999999; @@ -367,7 +399,7 @@ span.quality { span.Custom { background: none repeat scroll 0 0 #444499; /* blue */ } -span.HD { +span.HD,span.WEB-DL,span.BluRay { background: none repeat scroll 0 0 #449944; /* green */ } span.SD { diff --git a/data/css/jquery.pnotify.default.css b/data/css/jquery.pnotify.default.css index de8b7df93fdd47d1984c607fcab199775e7be2b8..95699366fcc0d976c577157473048bd0ff678a86 100644 --- a/data/css/jquery.pnotify.default.css +++ b/data/css/jquery.pnotify.default.css @@ -76,14 +76,3 @@ html > body .ui-pnotify { display: block; margin: 0 auto; } -.ui-pnotify .picon { - background-color: transparent; - background-repeat: no-repeat; - background-position: center center; - width: 17px; - height: 17px; -} -.ui-pnotify .ui-widget { - font-family: verdana, sans-serif; - font-size: 95% !important; -} \ No newline at end of file diff --git a/data/css/jquery.qtip2.css b/data/css/jquery.qtip2.css new file mode 100644 index 0000000000000000000000000000000000000000..173ce4ba2a0589c2bc7681f48efe75efa2375fde --- /dev/null +++ b/data/css/jquery.qtip2.css @@ -0,0 +1,536 @@ +/* +* qTip2 - Pretty powerful tooltips +* http://craigsworks.com/projects/qtip2/ +* +* Version: nightly +* Copyright 2009-2010 Craig Michael Thompson - http://craigsworks.com +* +* Dual licensed under MIT or GPLv2 licenses +* http://en.wikipedia.org/wiki/MIT_License +* http://en.wikipedia.org/wiki/GNU_General_Public_License +* +* Date: Thu Nov 17 12:01:03.0000000000 2011 +*/ + +/* Core qTip styles */ +.ui-tooltip, .qtip{ + position: absolute; + left: -28000px; + top: -28000px; + display: none; + + max-width: 280px; + min-width: 50px; + + font-size: 10.5px; + line-height: 12px; + + z-index: 15000; +} + + /* Fluid class for determining actual width in IE */ + .ui-tooltip-fluid{ + display: block; + visibility: hidden; + position: static !important; + float: left !important; + } + + .ui-tooltip-content{ + position: relative; + padding: 5px 9px; + overflow: hidden; + + border-width: 1px; + border-style: solid; + + text-align: left; + word-wrap: break-word; + overflow: hidden; + } + + .ui-tooltip-titlebar{ + position: relative; + min-height: 14px; + padding: 5px 35px 5px 10px; + overflow: hidden; + + border-width: 1px 1px 0; + border-style: solid; + + font-weight: bold; + } + + .ui-tooltip-titlebar + .ui-tooltip-content{ border-top-width: 0px !important; } + + /*! Default close button class */ + .ui-tooltip-titlebar .ui-state-default{ + position: absolute; + right: 4px; + top: 50%; + margin-top: -9px; + + cursor: pointer; + outline: medium none; + + border-width: 1px; + border-style: solid; + } + + * html .ui-tooltip-titlebar .ui-state-default{ top: 16px; } /* IE fix */ + + .ui-tooltip-titlebar .ui-icon, + .ui-tooltip-icon .ui-icon{ + display: block; + text-indent: -1000em; + } + + .ui-tooltip-icon, .ui-tooltip-icon .ui-icon{ + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + } + + .ui-tooltip-icon .ui-icon{ + width: 18px; + height: 14px; + + text-align: center; + text-indent: 0; + font: normal bold 10px/13px Tahoma,sans-serif; + + color: inherit; + background: transparent none no-repeat -100em -100em; + } + + +/* Applied to 'focused' tooltips e.g. most recently displayed/interacted with */ +.ui-tooltip-focus{ + +} + +/* Applied on hover of tooltips i.e. added/removed on mouseenter/mouseleave respectively */ +.ui-tooltip-hover{ + +} + + +/*! Default tooltip style */ +.ui-tooltip-default .ui-tooltip-titlebar, +.ui-tooltip-default .ui-tooltip-content{ + border-color: #F1D031; + background-color: #FFFFA3; + color: #555; +} + + .ui-tooltip-default .ui-tooltip-titlebar{ + background-color: #FFEF93; + } + + .ui-tooltip-default .ui-tooltip-icon{ + border-color: #CCC; + background: #F1F1F1; + color: #777; + } + + .ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover{ + border-color: #AAA; + color: #111; + } + +/* Tips plugin */ +.ui-tooltip .ui-tooltip-tip{ + margin: 0 auto; + overflow: hidden; + z-index: 10; +} + + .ui-tooltip .ui-tooltip-tip, + .ui-tooltip .ui-tooltip-tip *{ + position: absolute; + + line-height: 0.1px !important; + font-size: 0.1px !important; + color: #123456; + + background: transparent; + border: 0px dashed transparent; + } + + .ui-tooltip .ui-tooltip-tip canvas{ top: 0; left: 0; } + + +/*! Light tooltip style */ +.ui-tooltip-light .ui-tooltip-titlebar, +.ui-tooltip-light .ui-tooltip-content{ + border-color: #E2E2E2; + color: #454545; +} + + .ui-tooltip-light .ui-tooltip-content{ + background-color: white; + } + + .ui-tooltip-light .ui-tooltip-titlebar{ + background-color: #f1f1f1; + } + + +/*! Dark tooltip style */ +.ui-tooltip-dark .ui-tooltip-titlebar, +.ui-tooltip-dark .ui-tooltip-content{ + border-color: #303030; + color: #f3f3f3; +} + + .ui-tooltip-dark .ui-tooltip-content{ + background-color: #505050; + } + + .ui-tooltip-dark .ui-tooltip-titlebar{ + background-color: #404040; + } + + .ui-tooltip-dark .ui-tooltip-icon{ + border-color: #444; + } + + .ui-tooltip-dark .ui-tooltip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/*! Cream tooltip style */ +.ui-tooltip-cream .ui-tooltip-titlebar, +.ui-tooltip-cream .ui-tooltip-content{ + border-color: #F9E98E; + color: #A27D35; +} + + .ui-tooltip-cream .ui-tooltip-content{ + background-color: #FBF7AA; + } + + .ui-tooltip-cream .ui-tooltip-titlebar{ + background-color: #F0DE7D; + } + + .ui-tooltip-cream .ui-state-default .ui-tooltip-icon{ + background-position: -82px 0; + } + + +/*! Red tooltip style */ +.ui-tooltip-red .ui-tooltip-titlebar, +.ui-tooltip-red .ui-tooltip-content{ + border-color: #D95252; + color: #912323; +} + + .ui-tooltip-red .ui-tooltip-content{ + background-color: #F78B83; + } + + .ui-tooltip-red .ui-tooltip-titlebar{ + background-color: #F06D65; + } + + .ui-tooltip-red .ui-state-default .ui-tooltip-icon{ + background-position: -102px 0; + } + + .ui-tooltip-red .ui-tooltip-icon{ + border-color: #D95252; + } + + .ui-tooltip-red .ui-tooltip-titlebar .ui-state-hover{ + border-color: #D95252; + } + + +/*! Green tooltip style */ +.ui-tooltip-green .ui-tooltip-titlebar, +.ui-tooltip-green .ui-tooltip-content{ + border-color: #90D93F; + color: #3F6219; +} + + .ui-tooltip-green .ui-tooltip-content{ + background-color: #CAED9E; + } + + .ui-tooltip-green .ui-tooltip-titlebar{ + background-color: #B0DE78; + } + + .ui-tooltip-green .ui-state-default .ui-tooltip-icon{ + background-position: -42px 0; + } + + +/*! Blue tooltip style */ +.ui-tooltip-blue .ui-tooltip-titlebar, +.ui-tooltip-blue .ui-tooltip-content{ + border-color: #ADD9ED; + color: #5E99BD; +} + + .ui-tooltip-blue .ui-tooltip-content{ + background-color: #E5F6FE; + } + + .ui-tooltip-blue .ui-tooltip-titlebar{ + background-color: #D0E9F5; + } + + .ui-tooltip-blue .ui-state-default .ui-tooltip-icon{ + background-position: -2px 0; + } + +/*! Add shadows to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE6+, Safari 2+ */ +.ui-tooltip-shadow{ + -webkit-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); + box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); +} + + .ui-tooltip-shadow .ui-tooltip-titlebar, + .ui-tooltip-shadow .ui-tooltip-content{ + filter: progid:DXImageTransform.Microsoft.Shadow(Color='gray', Direction=135, Strength=3); + -ms-filter:"progid:DXImageTransform.Microsoft.Shadow(Color='gray', Direction=135, Strength=3)"; + + _margin-bottom: -3px; /* IE6 */ + .margin-bottom: -3px; /* IE7 */ + } + + +/*! Add rounded corners to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE9+, Safari 2+ */ +.ui-tooltip-rounded, +.ui-tooltip-rounded .ui-tooltip-content, +.ui-tooltip-tipsy, +.ui-tooltip-tipsy .ui-tooltip-content, +.ui-tooltip-youtube, +.ui-tooltip-youtube .ui-tooltip-content{ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; +} + +.ui-tooltip-rounded .ui-tooltip-titlebar, +.ui-tooltip-tipsy .ui-tooltip-titlebar, +.ui-tooltip-youtube .ui-tooltip-titlebar{ + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.ui-tooltip-rounded .ui-tooltip-titlebar + .ui-tooltip-content, +.ui-tooltip-tipsy .ui-tooltip-titlebar + .ui-tooltip-content, +.ui-tooltip-youtube .ui-tooltip-titlebar + .ui-tooltip-content{ + -moz-border-radius: 0 0 5px 5px; + -webkit-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; +} + + +/*! Youtube tooltip style */ +.ui-tooltip-youtube{ + -webkit-box-shadow: 0 0 3px #333; + -moz-box-shadow: 0 0 3px #333; + box-shadow: 0 0 3px #333; +} + + .ui-tooltip-youtube .ui-tooltip-titlebar, + .ui-tooltip-youtube .ui-tooltip-content{ + _margin-bottom: 0; /* IE6 */ + .margin-bottom: 0; /* IE7 */ + + background: transparent; + background: rgba(0, 0, 0, 0.85); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)"; + + color: white; + border-color: #CCCCCC; + } + + .ui-tooltip-youtube .ui-tooltip-icon{ + border-color: #222; + } + + .ui-tooltip-youtube .ui-tooltip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/* jQuery TOOLS Tooltip style */ +.ui-tooltip-jtools{ + background: #232323; + background: rgba(0, 0, 0, 0.7); + background-image: -moz-linear-gradient(top, #717171, #232323); + background-image: -webkit-gradient(linear, left top, left bottom, from(#717171), to(#232323)); + + border: 2px solid #ddd; + border: 2px solid rgba(241,241,241,1); + + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + + -webkit-box-shadow: 0 0 12px #333; + -moz-box-shadow: 0 0 12px #333; + box-shadow: 0 0 12px #333; +} + + /* IE Specific */ + .ui-tooltip-jtools .ui-tooltip-titlebar{ + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)"; + } + .ui-tooltip-jtools .ui-tooltip-content{ + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)"; + } + + .ui-tooltip-jtools .ui-tooltip-titlebar, + .ui-tooltip-jtools .ui-tooltip-content{ + background: transparent; + color: white; + border: 0 dashed transparent; + } + + .ui-tooltip-jtools .ui-tooltip-icon{ + border-color: #555; + } + + .ui-tooltip-jtools .ui-tooltip-titlebar .ui-state-hover{ + border-color: #333; + } + + +/* Cluetip style */ +.ui-tooltip-cluetip{ + -webkit-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); + -moz-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); + box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); +} + + .ui-tooltip-cluetip .ui-tooltip-titlebar{ + background-color: #87876A; + color: white; + border: 0 dashed transparent; + } + + .ui-tooltip-cluetip .ui-tooltip-content{ + background-color: #D9D9C2; + color: #111; + border: 0 dashed transparent; + } + + .ui-tooltip-cluetip .ui-tooltip-icon{ + border-color: #808064; + } + + .ui-tooltip-cluetip .ui-tooltip-titlebar .ui-state-hover{ + border-color: #696952; + color: #696952; + } + + +/* Tipsy style */ +.ui-tooltip-tipsy{ + border: 0; +} + + .ui-tooltip-tipsy .ui-tooltip-titlebar, + .ui-tooltip-tipsy .ui-tooltip-content{ + _margin-bottom: 0; /* IE6 */ + .margin-bottom: 0; /* IE7 */ + + background: transparent; + background: rgba(0, 0, 0, .87); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)"; + + color: white; + border: 0px transparent; + + font-size: 11px; + font-family: 'Lucida Grande', sans-serif; + font-weight: bold; + line-height: 16px; + text-shadow: 0 1px black; + } + + .ui-tooltip-tipsy .ui-tooltip-titlebar{ + padding: 6px 35px 0 10; + } + + .ui-tooltip-tipsy .ui-tooltip-content{ + padding: 6px 10; + } + + .ui-tooltip-tipsy .ui-tooltip-icon{ + border-color: #222; + text-shadow: none; + } + + .ui-tooltip-tipsy .ui-tooltip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/* Tipped style */ +.ui-tooltip-tipped{ + +} + + .ui-tooltip-tipped .ui-tooltip-titlebar, + .ui-tooltip-tipped .ui-tooltip-content{ + border: 3px solid #959FA9; + + filter: none; -ms-filter: none; + } + + .ui-tooltip-tipped .ui-tooltip-titlebar{ + background: #3A79B8; + background-image: -moz-linear-gradient(top, #3A79B8, #2E629D); + background-image: -webkit-gradient(linear, left top, left bottom, from(#3A79B8), to(#2E629D)); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)"; + + color: white; + font-weight: normal; + font-family: serif; + + border-bottom-width: 0; + -moz-border-radius: 3px 3px 0 0; + -webkit-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + } + + .ui-tooltip-tipped .ui-tooltip-content{ + background-color: #F9F9F9; + color: #454545; + + -moz-border-radius: 0 0 3px 3px; + -webkit-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + } + + .ui-tooltip-tipped .ui-tooltip-icon{ + border: 2px solid #285589; + background: #285589; + } + + .ui-tooltip-tipped .ui-tooltip-icon .ui-icon{ + background-color: #FBFBFB; + color: #555; + } + +/* IE9 fix - removes all filters */ +.ui-tooltip:not(.ie9haxors) div.ui-tooltip-content, +.ui-tooltip:not(.ie9haxors) div.ui-tooltip-titlebar{ + filter: none; + -ms-filter: none; +} \ No newline at end of file diff --git a/data/css/smooth-grinder/images/ui-bg_flat_0_6e4f1c_40x100.png b/data/css/smooth-grinder/images/ui-bg_flat_0_6e4f1c_40x100.png index 84da8ea3a85389dce7b1a2b675e667899b84854d..c5fc3777dd3c9599c00ec446df6796a8a67b0ce4 100644 Binary files a/data/css/smooth-grinder/images/ui-bg_flat_0_6e4f1c_40x100.png and b/data/css/smooth-grinder/images/ui-bg_flat_0_6e4f1c_40x100.png differ diff --git a/data/css/smooth-grinder/images/ui-bg_glass_55_fbf9ee_1x400.png b/data/css/smooth-grinder/images/ui-bg_glass_55_fbf9ee_1x400.png index ad3d6346e00f246102f72f2e026ed0491988b394..b39a6fb27ffbb1f3712e6cfa09e32d8ac084469b 100644 Binary files a/data/css/smooth-grinder/images/ui-bg_glass_55_fbf9ee_1x400.png and b/data/css/smooth-grinder/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/data/css/smooth-grinder/images/ui-bg_highlight-soft_75_dcdcdc_1x100.png b/data/css/smooth-grinder/images/ui-bg_highlight-soft_75_dcdcdc_1x100.png index cb6f952f2dc0fff714668e9c79358437078e6fd3..66acd27c22878fbd9c68d3e8b88ba292d595c118 100644 Binary files a/data/css/smooth-grinder/images/ui-bg_highlight-soft_75_dcdcdc_1x100.png and b/data/css/smooth-grinder/images/ui-bg_highlight-soft_75_dcdcdc_1x100.png differ diff --git a/data/css/smooth-grinder/images/ui-bg_highlight-soft_75_efefef_1x100.png b/data/css/smooth-grinder/images/ui-bg_highlight-soft_75_efefef_1x100.png index 27fa2fa9fb2c8bb3002e94a81cb04a7a039ec69d..077a5024dbd1dd8e8724f41a10bd8314eb57c9b9 100644 Binary files a/data/css/smooth-grinder/images/ui-bg_highlight-soft_75_efefef_1x100.png and b/data/css/smooth-grinder/images/ui-bg_highlight-soft_75_efefef_1x100.png differ diff --git a/data/css/smooth-grinder/images/ui-bg_inset-soft_75_dfdfdf_1x100.png b/data/css/smooth-grinder/images/ui-bg_inset-soft_75_dfdfdf_1x100.png index e6aece058547c64052a118372fded69fa25b1400..c33667aee3d67c6620bdcf7b8a6a7b1c40d4a9ea 100644 Binary files a/data/css/smooth-grinder/images/ui-bg_inset-soft_75_dfdfdf_1x100.png and b/data/css/smooth-grinder/images/ui-bg_inset-soft_75_dfdfdf_1x100.png differ diff --git a/data/css/smooth-grinder/jquery-ui-1.8.13.custom.css b/data/css/smooth-grinder/jquery-ui-1.8.17.custom.css similarity index 87% rename from data/css/smooth-grinder/jquery-ui-1.8.13.custom.css rename to data/css/smooth-grinder/jquery-ui-1.8.17.custom.css index 4721799f0eff0fc3c4a41a7b0883f3a7e842a753..c02748e42696aff5d34567939f22656c3d58307d 100644 --- a/data/css/smooth-grinder/jquery-ui-1.8.13.custom.css +++ b/data/css/smooth-grinder/jquery-ui-1.8.17.custom.css @@ -1,5 +1,5 @@ /* - * jQuery UI CSS Framework 1.8.13 + * jQuery UI CSS Framework 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -13,12 +13,9 @@ .ui-helper-hidden { display: none; } .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } -.ui-helper-clearfix { display: inline-block; } -/* required comment for clearfix to work in Opera \*/ -* html .ui-helper-clearfix { height:1%; } -.ui-helper-clearfix { display:block; } -/* end clearfix */ +.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } +.ui-helper-clearfix:after { clear: both; } +.ui-helper-clearfix { zoom: 1; } .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } @@ -42,7 +39,7 @@ /* - * jQuery UI CSS Framework 1.8.13 + * jQuery UI CSS Framework 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -50,7 +47,7 @@ * * http://docs.jquery.com/UI/Theming/API * - * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller&ctl=themeroller&ctl=themeroller&ctl=themeroller&ffDefault=Verdana,Arial,sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=ffffff&bgTextureHeader=01_flat.png&bgImgOpacityHeader=0&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=dcdcdc&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=efefef&bgTextureDefault=03_highlight_soft.png&bgImgOpacityDefault=75&borderColorDefault=aaaaaa&fcDefault=222222&iconColorDefault=8c291d&bgColorHover=dddddd&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=222222&iconColorHover=222222&bgColorActive=dfdfdf&bgTextureActive=05_inset_soft.png&bgImgOpacityActive=75&borderColorActive=aaaaaa&fcActive=140f06&iconColorActive=8c291d&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=aaaaaa&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=aaaaaa&fcError=8c291d&iconColorError=cd0a0a&bgColorOverlay=6e4f1c&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=35&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=35&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller&ctl=themeroller&ctl=themeroller&ctl=themeroller&ctl=themeroller&ctl=themeroller&ctl=themeroller&ffDefault=Verdana,Arial,sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=ffffff&bgTextureHeader=01_flat.png&bgImgOpacityHeader=0&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=dcdcdc&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=efefef&bgTextureDefault=03_highlight_soft.png&bgImgOpacityDefault=75&borderColorDefault=aaaaaa&fcDefault=222222&iconColorDefault=8c291d&bgColorHover=dddddd&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=222222&iconColorHover=222222&bgColorActive=dfdfdf&bgTextureActive=05_inset_soft.png&bgImgOpacityActive=75&borderColorActive=aaaaaa&fcActive=140f06&iconColorActive=8c291d&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=aaaaaa&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=aaaaaa&fcError=8c291d&iconColorError=cd0a0a&bgColorOverlay=6e4f1c&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=35&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=35&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px */ @@ -282,23 +279,18 @@ ----------------------------------*/ /* Corner radius */ -.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; } -.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } -.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } -.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } -.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } -.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } -.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } -.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } -.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } +.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } /* Overlays */ /* .ui-widget-overlay { background: #6e4f1c url(images/ui-bg_flat_0_6e4f1c_40x100.png) 50% 50% repeat-x; opacity: .35;filter:Alpha(Opacity=35); } -.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000 url(images/ui-bg_flat_0_000000_40x100.png) 50% 50% repeat-x; opacity: .35;filter:Alpha(Opacity=35); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000 url(images/ui-bg_flat_0_000000_40x100.png) 50% 50% repeat-x; opacity: .35;filter:Alpha(Opacity=35); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } */ /* - * jQuery UI Resizable 1.8.13 + * jQuery UI Resizable 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -307,12 +299,7 @@ * http://docs.jquery.com/UI/Resizable#theming */ .ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; - /* http://bugs.jqueryui.com/ticket/7233 - - Resizable: resizable handles fail to work in IE if transparent and content overlaps - */ - background-image:url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=); -} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } @@ -321,8 +308,9 @@ .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* - * jQuery UI Selectable 1.8.13 +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} +/* + * jQuery UI Selectable 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -332,7 +320,7 @@ */ .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } /* - * jQuery UI Accordion 1.8.13 + * jQuery UI Accordion 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -351,7 +339,7 @@ .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } .ui-accordion .ui-accordion-content-active { display: block; } /* - * jQuery UI Autocomplete 1.8.13 + * jQuery UI Autocomplete 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -363,8 +351,9 @@ /* workarounds */ * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + /* - * jQuery UI Menu 1.8.13 + * jQuery UI Menu 1.8.17 * * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -403,7 +392,7 @@ margin: -1px; } /* - * jQuery UI Button 1.8.13 + * jQuery UI Button 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -441,7 +430,7 @@ input.ui-button { padding: .4em 1em; } /* workarounds */ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ /* - * jQuery UI Dialog 1.8.13 + * jQuery UI Dialog 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -462,7 +451,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } .ui-draggable .ui-dialog-titlebar { cursor: move; } /* - * jQuery UI Slider 1.8.13 + * jQuery UI Slider 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -486,7 +475,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad .ui-slider-vertical .ui-slider-range-min { bottom: 0; } .ui-slider-vertical .ui-slider-range-max { top: 0; } /* - * jQuery UI Tabs 1.8.13 + * jQuery UI Tabs 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -504,7 +493,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } .ui-tabs .ui-tabs-hide { display: none !important; } /* - * jQuery UI Progressbar 1.8.13 + * jQuery UI Progressbar 1.8.17 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. @@ -512,5 +501,5 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad * * http://docs.jquery.com/UI/Progressbar#theming */ -.ui-progressbar { height:1.3em; text-align: left; } +.ui-progressbar { height:1.3em; text-align: left; overflow: hidden; } .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/data/css/tablesorter.css b/data/css/tablesorter.css index 6c262d5679276ff81adfe4ac35f740a244903d3d..d8b64ed69e8049a5b7f3392726f589310b4dbca1 100644 --- a/data/css/tablesorter.css +++ b/data/css/tablesorter.css @@ -1,32 +1,83 @@ -/* tables */ -table.tablesorter thead tr .header { -/* background-image: url(../images/tablesorter/bg.gif); */ - cursor: pointer; - background-repeat: no-repeat; - background-position: center right; - padding-right: 18px; -} -table.tablesorter thead tr th, table.tablesorter tfoot tr th { - border: 1px solid #241109; - padding: 3px; - font-weight:700; -} -/* -table.tablesorter thead tr .headerSortUp { - background-image: url(../images/tablesorter/asc.gif); -} -table.tablesorter thead tr .headerSortDown { - background-image: url(../images/tablesorter/desc.gif); -} -*/ -table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp { +/* SB Theme */ +table.tablesorter { + width: 100%; + margin-left:auto; + margin-right:auto; + text-align:left; + color: #000; + background-color: #fff; + border-spacing: 0; +} +table.tablesorter th, +table.tablesorter td { + padding: 4px; + border-left: #fff 1px solid; + border-top: #fff 1px solid; +} +/* remove extra border from left edge */ +table.tablesorter th:first-child, +table.tablesorter td:first-child { + border-left: none; +} +table.tablesorter th { + border-collapse: collapse; + background-color: #333; + color: #fff; + text-shadow: -1px -1px 0 rgba(0,0,0,0.3); + text-align: center; +} +table.tablesorter .tablesorter-header { +/* background-image: url(../images/tablesorter/bg.gif); */ + background-repeat: no-repeat; + background-position: center right; + padding: 4px 18px 4px 4px; + cursor: pointer; +} +table.tablesorter th.tablesorter-headerSortUp { + background-color: #57442B; +/* background-image: url(../images/tablesorter/asc.gif); */ +} +table.tablesorter th.tablesorter-headerSortDown { background-color: #57442B; +/* background-image: url(../images/tablesorter/desc.gif); */ +} + +/* Zebra Widget - row alternating colors */ +table.tablesorter tr.odd td { + background-color: #f5f1e4; +} +table.tablesorter tr.even td { + background-color: #dfdacf; +} +/* filter widget */ +table.tablesorter input.tablesorter-filter { + width: 98%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +table.tablesorter tr.tablesorter-filter, +table.tablesorter tr.tablesorter-filter td { + text-align: center; + background: #eee; +} +/* optional disabled input styling */ +table.tablesorter input.tablesorter-filter.disabled { + display: none; +} + + +/* xtra css for sb */ +.tablesorter-header-inner { + text-align: center; + padding: 0 2px; +} +tr.tablesorter-stickyHeader { + background-color: #fff; + padding: 2px 0; } -table.tablesorter tbody tr.even td { - background-color:#f5f1e4; - color: #000000; + +table.tablesorter tfoot a { + color:#fff; + text-decoration: none; } -table.tablesorter tbody tr.odd td { - background-color:#dfdacf; - color: #000000; -} \ No newline at end of file diff --git a/data/images/flags/cs.png b/data/images/flags/cs.png new file mode 100644 index 0000000000000000000000000000000000000000..06309073da5b109a6d93d24d6395f9ef2217748a Binary files /dev/null and b/data/images/flags/cs.png differ diff --git a/data/images/flags/da.png b/data/images/flags/da.png new file mode 100644 index 0000000000000000000000000000000000000000..e2993d3c59ae78855f777c158a6aae6c1fb5c843 Binary files /dev/null and b/data/images/flags/da.png differ diff --git a/data/images/flags/de.png b/data/images/flags/de.png new file mode 100644 index 0000000000000000000000000000000000000000..ac4a977362738ca7daa20784717f10f9617136b4 Binary files /dev/null and b/data/images/flags/de.png differ diff --git a/data/images/flags/el.png b/data/images/flags/el.png new file mode 100644 index 0000000000000000000000000000000000000000..8651ade7cbe030e85efc811a844d8f366c97a50c Binary files /dev/null and b/data/images/flags/el.png differ diff --git a/data/images/flags/en.png b/data/images/flags/en.png new file mode 100644 index 0000000000000000000000000000000000000000..10f451fe85c41c6c9a06d543a57114ae2f87ecc1 Binary files /dev/null and b/data/images/flags/en.png differ diff --git a/data/images/flags/es.png b/data/images/flags/es.png new file mode 100644 index 0000000000000000000000000000000000000000..c2de2d7111e3cb59cf6511dd2ab045e824bdb43e Binary files /dev/null and b/data/images/flags/es.png differ diff --git a/data/images/flags/fi.png b/data/images/flags/fi.png new file mode 100644 index 0000000000000000000000000000000000000000..14ec091b802cf24ebd9f8825f81cd2f6e360b46d Binary files /dev/null and b/data/images/flags/fi.png differ diff --git a/data/images/flags/fr.png b/data/images/flags/fr.png new file mode 100644 index 0000000000000000000000000000000000000000..8332c4ec23c853944c29b02d7b32a88033f48a71 Binary files /dev/null and b/data/images/flags/fr.png differ diff --git a/data/images/flags/he.png b/data/images/flags/he.png new file mode 100644 index 0000000000000000000000000000000000000000..31b61bc7a7345cddeecfb0790d3898a1539d6314 Binary files /dev/null and b/data/images/flags/he.png differ diff --git a/data/images/flags/hr.png b/data/images/flags/hr.png new file mode 100644 index 0000000000000000000000000000000000000000..b7882bc84f13e08029e0e2c241072e6b22c80fd5 Binary files /dev/null and b/data/images/flags/hr.png differ diff --git a/data/images/flags/hu.png b/data/images/flags/hu.png new file mode 100644 index 0000000000000000000000000000000000000000..9d6c4eac91f288fab0dbf07068998ba19bb0c7a1 Binary files /dev/null and b/data/images/flags/hu.png differ diff --git a/data/images/flags/it.png b/data/images/flags/it.png new file mode 100644 index 0000000000000000000000000000000000000000..89692f74f051cd43503744c3dab65c8ba773b7e2 Binary files /dev/null and b/data/images/flags/it.png differ diff --git a/data/images/flags/ja.png b/data/images/flags/ja.png new file mode 100644 index 0000000000000000000000000000000000000000..4fbc123814ef5e2b2af77e93591ee53715954319 Binary files /dev/null and b/data/images/flags/ja.png differ diff --git a/data/images/flags/ko.png b/data/images/flags/ko.png new file mode 100644 index 0000000000000000000000000000000000000000..c1179b53a0e7dc3b8c66df4856484df009959117 Binary files /dev/null and b/data/images/flags/ko.png differ diff --git a/data/images/flags/nl.png b/data/images/flags/nl.png new file mode 100644 index 0000000000000000000000000000000000000000..fe44791e32b790949b0317ab3c258864b9024ebe Binary files /dev/null and b/data/images/flags/nl.png differ diff --git a/data/images/flags/no.png b/data/images/flags/no.png new file mode 100644 index 0000000000000000000000000000000000000000..160b6b5b79db15e623fa55e5774e5d160b933180 Binary files /dev/null and b/data/images/flags/no.png differ diff --git a/data/images/flags/pl.png b/data/images/flags/pl.png new file mode 100644 index 0000000000000000000000000000000000000000..d413d010b5b097c4e0a4604eba86dad79567ed16 Binary files /dev/null and b/data/images/flags/pl.png differ diff --git a/data/images/flags/pt.png b/data/images/flags/pt.png new file mode 100644 index 0000000000000000000000000000000000000000..ece79801506ecf8c42397349b4fa2cfe8176b999 Binary files /dev/null and b/data/images/flags/pt.png differ diff --git a/data/images/flags/ru.png b/data/images/flags/ru.png new file mode 100644 index 0000000000000000000000000000000000000000..47da4214fd9edb383687c1d4f84fe8b42a51ceb2 Binary files /dev/null and b/data/images/flags/ru.png differ diff --git a/data/images/flags/sl.png b/data/images/flags/sl.png new file mode 100644 index 0000000000000000000000000000000000000000..e66e7789518537003d82e905d3d7c89a8632001d Binary files /dev/null and b/data/images/flags/sl.png differ diff --git a/data/images/flags/sv.png b/data/images/flags/sv.png new file mode 100644 index 0000000000000000000000000000000000000000..1994653dac1fc1c6ee3c9fcb35c8af97f16eefc7 Binary files /dev/null and b/data/images/flags/sv.png differ diff --git a/data/images/flags/tr.png b/data/images/flags/tr.png new file mode 100644 index 0000000000000000000000000000000000000000..39ca7f79166f0dacbbda8028ce2a1ac9b1abdb90 Binary files /dev/null and b/data/images/flags/tr.png differ diff --git a/data/images/flags/zh.png b/data/images/flags/zh.png new file mode 100644 index 0000000000000000000000000000000000000000..89144146219e6fbec7eaa89e1bf4b073d299569e Binary files /dev/null and b/data/images/flags/zh.png differ diff --git a/data/images/menu/backlog_view16.png b/data/images/menu/backlog_view16.png new file mode 100644 index 0000000000000000000000000000000000000000..352c1025debb8e01e0a3061ded6e33b513984e49 Binary files /dev/null and b/data/images/menu/backlog_view16.png differ diff --git a/data/images/menu/backlog_view16_over.png b/data/images/menu/backlog_view16_over.png new file mode 100644 index 0000000000000000000000000000000000000000..2496a61662ad4258073fb8900e482d6f25f53f68 Binary files /dev/null and b/data/images/menu/backlog_view16_over.png differ diff --git a/data/images/menu/config_index16.png b/data/images/menu/config_index16.png new file mode 100644 index 0000000000000000000000000000000000000000..3f6807c06dc27b8d5a162160339010dff54fbb7b Binary files /dev/null and b/data/images/menu/config_index16.png differ diff --git a/data/images/menu/config_index16_over.png b/data/images/menu/config_index16_over.png new file mode 100644 index 0000000000000000000000000000000000000000..adbbad1fd4ce17f5f44637a3aa997b98df7a9b30 Binary files /dev/null and b/data/images/menu/config_index16_over.png differ diff --git a/data/images/menu/home16.png b/data/images/menu/home16.png new file mode 100644 index 0000000000000000000000000000000000000000..59bff9743368bb3e1e6bbc96c7c15efb9fc1655a Binary files /dev/null and b/data/images/menu/home16.png differ diff --git a/data/images/menu/home16_over.png b/data/images/menu/home16_over.png new file mode 100644 index 0000000000000000000000000000000000000000..461b68dfa669d9fc233ad6ff781546aaee36013b Binary files /dev/null and b/data/images/menu/home16_over.png differ diff --git a/data/images/menu/manage16.png b/data/images/menu/manage16.png new file mode 100644 index 0000000000000000000000000000000000000000..623cb0e747d8fe2f9d9b4383c12d713364292094 Binary files /dev/null and b/data/images/menu/manage16.png differ diff --git a/data/images/menu/manage16_over.png b/data/images/menu/manage16_over.png new file mode 100644 index 0000000000000000000000000000000000000000..232d47d6e44936d7ff92e57e997834b887b2857a Binary files /dev/null and b/data/images/menu/manage16_over.png differ diff --git a/data/images/menu/viewlog_errors16.png b/data/images/menu/viewlog_errors16.png new file mode 100644 index 0000000000000000000000000000000000000000..6e55d22ebe4996bbcb6b850fbdd8c4ed5a1944fe Binary files /dev/null and b/data/images/menu/viewlog_errors16.png differ diff --git a/data/images/menu/viewlog_errors16_over.png b/data/images/menu/viewlog_errors16_over.png new file mode 100644 index 0000000000000000000000000000000000000000..0d1b93627a35ce64e99518f4e8e10c1847c1546f Binary files /dev/null and b/data/images/menu/viewlog_errors16_over.png differ diff --git a/data/images/notifiers/boxcar.gif b/data/images/notifiers/boxcar.gif new file mode 100644 index 0000000000000000000000000000000000000000..b78ed132ecce51e68779575669071da637752e8c Binary files /dev/null and b/data/images/notifiers/boxcar.gif differ diff --git a/data/images/notifiers/nma.jpg b/data/images/notifiers/nma.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b22ba96fec2323b557eede65cec0d8d7e16a0a99 Binary files /dev/null and b/data/images/notifiers/nma.jpg differ diff --git a/data/images/notifiers/pushover.gif b/data/images/notifiers/pushover.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff4de49e067d56707cb7ee810053c94d5679af31 Binary files /dev/null and b/data/images/notifiers/pushover.gif differ diff --git a/data/images/notifiers/pytivo.gif b/data/images/notifiers/pytivo.gif new file mode 100644 index 0000000000000000000000000000000000000000..121e4fde799bc185ed950a4bfd5780401a31ba47 Binary files /dev/null and b/data/images/notifiers/pytivo.gif differ diff --git a/data/images/notifiers/trakt.gif b/data/images/notifiers/trakt.gif new file mode 100644 index 0000000000000000000000000000000000000000..7d448ec0a1c80ef252725d23d519e64a72cd3352 Binary files /dev/null and b/data/images/notifiers/trakt.gif differ diff --git a/data/images/providers/btn.gif b/data/images/providers/btn.gif new file mode 100644 index 0000000000000000000000000000000000000000..7164eb61adbbcdca32818d35fb76712c55637c79 Binary files /dev/null and b/data/images/providers/btn.gif differ diff --git a/data/images/providers/nzbs_org_old.gif b/data/images/providers/nzbs_org_old.gif new file mode 100644 index 0000000000000000000000000000000000000000..3281578792ebd51f963965deb383ffda3f8f6062 Binary files /dev/null and b/data/images/providers/nzbs_org_old.gif differ diff --git a/data/interfaces/default/apiBuilder.tmpl b/data/interfaces/default/apiBuilder.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..b948b0097d5435014264c0d1ef0ddc8f703864e6 --- /dev/null +++ b/data/interfaces/default/apiBuilder.tmpl @@ -0,0 +1,370 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>API Builder</title> +<script type="text/javascript" charset="utf-8"> +<!-- +sbRoot = "$sbRoot"; +//--> +</script> +<script type="text/javascript" src="$sbRoot/js/jquery-1.7.1.min.js"></script> +<script type="text/javascript" src="$sbRoot/js/apibuilder.js"></script> + +<style type="text/css"> +<!-- +#apibuilder select { padding: 2px 2px 2px 6px; display: block; float: left; margin: auto 8px 4px auto; +} +#apibuilder select option { padding: 1px 6px; line-height: 1.2em; } +#apibuilder .disabled { color: #ccc; } +#apibuilder .action { background-color: #efefef; } +--> +</style> + +<script type="text/javascript"> +var hide_empty_list=true; +var disable_empty_list=true; + +addListGroup("api", "Command"); + +addOption("Command", "SickBeard", "?cmd=sb", 1); //make default +addList("Command", "SickBeard.AddRootDir", "?cmd=sb.addrootdir", "sb.addrootdir", "", "", "action"); +addOption("Command", "SickBeard.CheckScheduler", "?cmd=sb.checkscheduler", "", "", "action"); +addList("Command", "SickBeard.DeleteRootDir", "?cmd=sb.deleterootdir", "sb.deleterootdir", "", "", "action"); +addOption("Command", "SickBeard.ForceSearch", "?cmd=sb.forcesearch", "", "", "action"); +addOption("Command", "SickBeard.GetDefaults", "?cmd=sb.getdefaults", "", "", "action"); +addOption("Command", "SickBeard.GetMessages", "?cmd=sb.getmessages", "", "", "action"); +addOption("Command", "SickBeard.GetRootDirs", "?cmd=sb.getrootdirs", "", "", "action"); +addList("Command", "SickBeard.PauseBacklog", "?cmd=sb.pausebacklog", "sb.pausebacklog", "", "", "action"); +addOption("Command", "SickBeard.Ping", "?cmd=sb.ping", "", "", "action"); +addOption("Command", "SickBeard.Restart", "?cmd=sb.restart", "", "", "action"); +addList("Command", "SickBeard.SearchTVDB", "?cmd=sb.searchtvdb", "sb.searchtvdb", "", "", "action"); +addList("Command", "SickBeard.SetDefaults", "?cmd=sb.setdefaults", "sb.setdefaults", "", "", "action"); +addOption("Command", "SickBeard.Shutdown", "?cmd=sb.shutdown", "", "", "action"); +addList("Command", "Coming Episodes", "?cmd=future", "future"); +addList("Command", "Episode", "?cmd=episode", "episode"); +addList("Command", "Episode.Search", "?cmd=episode.search", "episode.search", "", "", "action"); +addList("Command", "Episode.SetStatus", "?cmd=episode.setstatus", "episode.setstatus", "", "", "action"); +addList("Command", "Scene Exceptions", "?cmd=exceptions", "exceptions"); +addList("Command", "History", "?cmd=history", "history"); +addOption("Command", "History.Clear", "?cmd=history.clear", "", "", "action"); +addOption("Command", "History.Trim", "?cmd=history.trim", "", "", "action"); +addList("Command", "Logs", "?cmd=logs", "logs"); +addList("Command", "Show", "?cmd=show", "tvdbid"); +addList("Command", "Show.AddExisting", "?cmd=show.addexisting", "show.addexisting", "", "", "action"); +addList("Command", "Show.AddNew", "?cmd=show.addnew", "show.addnew", "", "", "action"); +addList("Command", "Show.Cache", "?cmd=show.cache", "tvdbid", "", "", "action"); +addList("Command", "Show.Delete", "?cmd=show.delete", "tvdbid", "", "", "action"); +addList("Command", "Show.GetBanner", "?cmd=show.getbanner", "tvdbid", "", "", "action"); +addList("Command", "Show.GetPoster", "?cmd=show.getposter", "tvdbid", "", "", "action"); +addList("Command", "Show.GetQuality", "?cmd=show.getquality", "tvdbid", "", "", "action"); +addList("Command", "Show.Pause", "?cmd=show.pause", "show.pause", "", "", "action"); +addList("Command", "Show.Refresh", "?cmd=show.refresh", "tvdbid", "", "", "action"); +addList("Command", "Show.SeasonList", "?cmd=show.seasonlist", "show.seasonlist", "", "", "action"); +addList("Command", "Show.Seasons", "?cmd=show.seasons", "seasons", "", "", "action"); +addList("Command", "Show.SetQuality", "?cmd=show.setquality", "show.setquality", "", "", "action"); +addList("Command", "Show.Stats", "?cmd=show.stats", "tvdbid", "", "", "action"); +addList("Command", "Show.Update", "?cmd=show.update", "tvdbid", "", "", "action"); +addList("Command", "Shows", "?cmd=shows", "shows"); +addOption("Command", "Shows.Stats", "?cmd=shows.stats", "", "", "action"); + +// addOption("tvdbid", "Optional Param", "", 1); +#for $curShow in $sortedShowList: +addOption("tvdbid", "$curShow.name", "&tvdbid=$curShow.tvdbid"); +#end for + +addOption("logs", "Optional Param", "", 1); +addOption("logs", "Debug", "&min_level=debug"); +addOption("logs", "Info", "&min_level=info"); +addOption("logs", "Warning", "&min_level=warning"); +addOption("logs", "Error", "&min_level=error"); + +addOption("sb.setdefaults", "Optional Param", "", 1); +addList("sb.setdefaults", "Exclude Paused Shows on ComingEps", "&future_show_paused=0", "sb.setdefaults-status"); +addList("sb.setdefaults", "Include Paused Shows on ComingEps", "&future_show_paused=1", "sb.setdefaults-status"); + +addOption("sb.setdefaults-status", "Optional Param", "", 1); +addList("sb.setdefaults-status", "Wanted", "&status=wanted", "sb.setdefaults-opt"); +addList("sb.setdefaults-status", "Skipped", "&status=skipped", "sb.setdefaults-opt"); +addList("sb.setdefaults-status", "Archived", "&status=archived", "sb.setdefaults-opt"); +addList("sb.setdefaults-status", "Ignored", "&status=ignored", "sb.setdefaults-opt"); + +addOption("sb.setdefaults-opt", "Optional Param", "", 1); +addList("sb.setdefaults-opt", "No Season Folder", "&season_folder=0", "quality"); +addList("sb.setdefaults-opt", "Use Season Folder", "&season_folder=1", "quality"); + +addOption("shows", "Optional Param", "", 1); +addOption("shows", "Show Only Paused", "&paused=1"); +addOption("shows", "Show Only Not Paused", "&paused=0"); +addOption("shows", "Sort by Show Name", "&sort=name"); +addOption("shows", "Sort by TVDB ID", "&sort=id"); + +addList("show.addexisting", "C:\\temp\\show1", "&location=C:\\temp\\show1", "show.addexisting-tvdbid"); +addList("show.addexisting", "D:\\Temp\\show2", "&location=D:\\Temp\\show2", "show.addexisting-tvdbid"); +addList("show.addexisting", "S:\\TV\\Ancient Aliens", "&location=S:\\TV\\Ancient Aliens", "show.addexisting-tvdbid"); +addList("show.addexisting", "S:\\TV\\Chuck", "&location=S:\\TV\\Chuck", "show.addexisting-tvdbid"); + +addList("show.addexisting-tvdbid", "101501 (Ancient Aliens)", "&tvdbid=101501", "show.addexisting-opt"); +addList("show.addexisting-tvdbid", "80348 (Chuck)", "&tvdbid=80348", "show.addexisting-opt"); + +addOption("show.addexisting-opt", "Optional Param", "", 1); +addList("show.addexisting-opt", "No Season Folder", "&season_folder=0", "quality"); +addList("show.addexisting-opt", "Use Season Folder", "&season_folder=1", "quality"); + +addList("show.addnew", "101501 (Ancient Aliens)", "&tvdbid=101501", "show.addnew-loc"); +addList("show.addnew", "80348 (Chuck)", "&tvdbid=80348", "show.addnew-loc"); + +addOption("show.addnew-loc", "Optional Param", "", 1); +addList("show.addnew-loc", "C:\\Temp", "&location=C:\\temp", "show.addnew-status"); +addList("show.addnew-loc", "D:\\Temp", "&location=D:\\Temp", "show.addnew-status"); +addList("show.addnew-loc", "S:\\TV", "&location=S:\\TV", "show.addnew-status"); +addList("show.addnew-loc", "/usr/bin", "&location=/usr/bin", "show.addnew-status"); + +addOption("show.addnew-status", "Optional Param", "", 1); +addList("show.addnew-status", "Wanted", "&status=wanted", "show.addnew-opt"); +addList("show.addnew-status", "Skipped", "&status=skipped", "show.addnew-opt"); +addList("show.addnew-status", "Archived", "&status=archived", "show.addnew-opt"); +addList("show.addnew-status", "Ignored", "&status=ignored", "show.addnew-opt"); + +addOption("show.addnew-opt", "Optional Param", "", 1); +addList("show.addnew-opt", "No Season Folder", "&season_folder=0", "quality"); +addList("show.addnew-opt", "Use Season Folder", "&season_folder=1", "quality"); + +addOptGroup("sb.searchtvdb", "Search by Name"); +addList("sb.searchtvdb", "Lost", "&name=Lost", "sb.searchtvdb-lang"); +addList("sb.searchtvdb", "office", "&name=office", "sb.searchtvdb-lang"); +addList("sb.searchtvdb", "OffiCE", "&name=OffiCE", "sb.searchtvdb-lang"); +addList("sb.searchtvdb", "Leno", "&name=leno", "sb.searchtvdb-lang"); +addList("sb.searchtvdb", "Top Gear", "&name=Top Gear", "sb.searchtvdb-lang"); +endOptGroup("sb.searchtvdb"); +addOptGroup("sb.searchtvdb", "Search by TVDBID"); +addList("sb.searchtvdb", "73739", "&tvdbid=73739", "sb.searchtvdb-lang"); +addList("sb.searchtvdb", "74608", "&tvdbid=74608", "sb.searchtvdb-lang"); +addList("sb.searchtvdb", "199051", "&tvdbid=199051", "sb.searchtvdb-lang"); +addList("sb.searchtvdb", "123456 (invalid show)", "&tvdbid=123456", "sb.searchtvdb-lang"); +endOptGroup("sb.searchtvdb"); + +addOption("sb.searchtvdb-lang", "Optional Param", "", 1); +addOption("sb.searchtvdb-lang", "Chinese", "&lang=zh"); // 27 +addOption("sb.searchtvdb-lang", "Croatian", "&lang=hr"); // 31 +addOption("sb.searchtvdb-lang", "Czech", "&lang=cs"); // 28 +addOption("sb.searchtvdb-lang", "Danish", "&lang=da"); // 10 +addOption("sb.searchtvdb-lang", "Dutch", "&lang=nl"); // 13 +addOption("sb.searchtvdb-lang", "English", "&lang=en"); // 7 +addOption("sb.searchtvdb-lang", "Finnish", "&lang=fi"); // 11 -- Suomeksi +addOption("sb.searchtvdb-lang", "French", "&lang=fr"); // 17 +addOption("sb.searchtvdb-lang", "German", "&lang=de"); // 14 +addOption("sb.searchtvdb-lang", "Greek", "&lang=el"); // 20 +addOption("sb.searchtvdb-lang", "Hebrew", "&lang=he"); // 24 +addOption("sb.searchtvdb-lang", "Hungarian", "&lang=hu"); // 19 -- Magyar +addOption("sb.searchtvdb-lang", "Italian", "&lang=it"); // 15 +addOption("sb.searchtvdb-lang", "Japanese", "&lang=ja"); // 25 +addOption("sb.searchtvdb-lang", "Korean", "&lang=ko"); // 32 +addOption("sb.searchtvdb-lang", "Norwegian", "&lang=no"); // 9 +addOption("sb.searchtvdb-lang", "Polish", "&lang=pl"); // 18 +addOption("sb.searchtvdb-lang", "Portuguese", "&lang=pt");// 26 +addOption("sb.searchtvdb-lang", "Russian", "&lang=ru"); // 22 +addOption("sb.searchtvdb-lang", "Slovenian", "&lang=sl"); // 30 +addOption("sb.searchtvdb-lang", "Spanish", "&lang=es"); // 16 +addOption("sb.searchtvdb-lang", "Swedish", "&lang=sv"); // 8 +addOption("sb.searchtvdb-lang", "Turkish", "&lang=tr"); // 21 + +#for $curShow in $sortedShowList: +addList("seasons", "$curShow.name", "&tvdbid=$curShow.tvdbid", "seasons-$curShow.tvdbid"); +#end for + +#for $curShow in $sortedShowList: +addList("show.seasonlist", "$curShow.name", "&tvdbid=$curShow.tvdbid", "show.seasonlist-sort"); +#end for + +addOption("show.seasonlist-sort", "Optional Param", "", 1); +addOption("show.seasonlist-sort", "Sort by Ascending", "&sort=asc"); + +#for $curShow in $sortedShowList: +addList("show.setquality", "$curShow.name", "&tvdbid=$curShow.tvdbid", "quality"); +#end for + +//build out generic quality options +addOptGroup("quality", "Quality Templates"); +addOption("quality", "SD", "&initial=sdtv|sddvd"); +addOption("quality", "HD", "&initial=hdtv|hdwebdl|hdbluray"); +addOption("quality", "ANY", "&initial=sdtv|sddvd|hdtv|hdwebdl|hdbluray|unknown"); +endOptGroup("quality"); +addOptGroup("quality", "Inital (Custom)"); +addList("quality", "SD TV", "&initial=sdtv", "quality-archive"); +addList("quality", "SD DVD", "&initial=sddvd", "quality-archive"); +addList("quality", "HD TV", "&initial=hdtv", "quality-archive"); +addList("quality", "720p Web-DL", "&initial=hdwebdl", "quality-archive"); +addList("quality", "720p BluRay", "&initial=hdbluray", "quality-archive"); +addList("quality", "1080p BluRay", "&initial=fullhdbluray", "quality-archive"); +addList("quality", "Unknown", "&initial=unknown", "quality-archive"); +endOptGroup("quality"); +addOptGroup("quality", "Random (Custom)"); +addList("quality", "SD DVD/720p Web-DL", "&initial=sddvd|hdwebdl", "quality-archive"); +addList("quality", "SD TV/HD TV", "&initial=sdtv|hdtv", "quality-archive"); +endOptGroup("quality"); + +addOption("quality-archive", "Optional Param", "", 1); +addOptGroup("quality-archive", "Archive (Custom)"); +addList("quality-archive", "SD DVD", "&archive=sddvd"); +addList("quality-archive", "HD TV", "&archive=hdtv"); +addList("quality-archive", "720p Web-DL", "&archive=hdwebdl"); +addList("quality-archive", "720p BluRay", "&archive=hdbluray"); +addList("quality-archive", "1080p BluRay", "&archive=fullhdbluray"); +addList("quality-archive", "Unknown", "&archive=unknown"); +endOptGroup("quality-archive"); +addOptGroup("quality-archive", "Random (Custom)"); +addList("quality-archive", "HD TV/1080p BluRay", "&archive=hdtv|fullhdbluray"); +addList("quality-archive", "720p Web-DL/720p BluRay", "&archive=hdwebdl|hdbluray"); +endOptGroup("quality-archive"); + +// build out each show's season list for season cmd +#for $curShow in $seasonSQLResults: +addOption("seasons-$curShow", "Optional Param", "", 1); + #for $curShowSeason in $seasonSQLResults[$curShow]: +addOption("seasons-$curShow", "$curShowSeason.season", "&season=$curShowSeason.season"); + #end for +#end for + +#for $curShow in $sortedShowList: +addList("episode", "$curShow.name", "&tvdbid=$curShow.tvdbid", "episode-$curShow.tvdbid"); +#end for + +// build out each show's season+episode list for episode cmd +#for $curShow in $episodeSQLResults: + #for $curShowSeason in $episodeSQLResults[$curShow]: +addList("episode-$curShow", "$curShowSeason.season x $curShowSeason.episode", "&season=$curShowSeason.season&episode=$curShowSeason.episode", "episode-$curShow-full"); + #end for +addOption("episode-$curShow-full", "Optional Param", "", 1); +addOption("episode-$curShow-full", "Show Full Path", "&full_path=1"); +#end for + +// build out tvshow list for episode.search +#for $curShow in $sortedShowList: +addList("episode.search", "$curShow.name", "&tvdbid=$curShow.tvdbid", "episode.search-$curShow.tvdbid"); +#end for + +// build out each show's season+episode list for episode.search cmd +#for $curShow in $episodeSQLResults: + #for $curShowSeason in $episodeSQLResults[$curShow]: +addOption("episode.search-$curShow", "$curShowSeason.season x $curShowSeason.episode", "&season=$curShowSeason.season&episode=$curShowSeason.episode"); + #end for +#end for + +// build out tvshow list for episode.setstatus +#for $curShow in $sortedShowList: +addList("episode.setstatus", "$curShow.name", "&tvdbid=$curShow.tvdbid", "episode.setstatus-$curShow.tvdbid"); +#end for + +// build out each show's season+episode list for episode.setstatus cmd +#for $curShow in $episodeSQLResults: + #for $curShowSeason in $episodeSQLResults[$curShow]: +addList("episode.setstatus-$curShow", "$curShowSeason.season x $curShowSeason.episode", "&season=$curShowSeason.season&episode=$curShowSeason.episode", "episode-status-$curShow"); + #end for +addOption("episode-status-$curShow", "Wanted", "&status=wanted"); +addOption("episode-status-$curShow", "Skipped", "&status=skipped"); +addOption("episode-status-$curShow", "Archived", "&status=archived"); +addOption("episode-status-$curShow", "Ignored", "&status=ignored"); +#end for + +addOption("future", "Optional Param", "", 1); +addList("future", "Sort by Date", "&sort=date", "future-type"); +addList("future", "Sort by Network", "&sort=network", "future-type"); +addList("future", "Sort by Show Name", "&sort=show", "future-type"); + +addOption("future-type", "Optional Param", "", 1); +addList("future-type", "Show All Types", "&type=today|missed|soon|later", "future-paused"); +addList("future-type", "Show Today", "&type=today", "future-paused"); +addList("future-type", "Show Missed", "&type=missed", "future-paused"); +addList("future-type", "Show Soon", "&type=soon", "future-paused"); +addList("future-type", "Show Later", "&type=later", "future-paused"); +addList("future-type", "Show Today & Missed", "&type=today|missed", "future-paused"); + +addOption("future-paused", "Optional Param", "", 1); +addOption("future-paused", "Include Paused Shows", "&paused=1"); +addOption("future-paused", "Exclude Paused Shows", "&paused=0"); + +addOption("history", "Optional Param", "", 1); +addList("history", "Show Only Downloaded", "&type=downloaded", "history-type"); +addList("history", "Show Only Snatched", "&type=snatched", "history-type"); +//addOptGroup("history", "Limit Results"); +addList("history", "Limit Results (2)", "&limit=2", "history-limit"); +addList("history", "Limit Results (25)", "&limit=25", "history-limit"); +addList("history", "Limit Results (50)", "&limit=50", "history-limit"); +//endOptGroup("history"); + +addOption("history-type", "Optional Param", "", 1); +addOption("history-type", "Limit Results (2)", "&limit=2"); +addOption("history-type", "Limit Results (25)", "&limit=25"); +addOption("history-type", "Limit Results (50)", "&limit=50"); + +addOption("history-limit", "Optional Param", "", 1); +addOption("history-limit", "Show Only Downloaded", "&type=downloaded"); +addOption("history-limit", "Show Only Snatched", "&type=snatched"); + +addOption("exceptions", "Optional Param", "", 1); +#for $curShow in $sortedShowList: +addOption("exceptions", "$curShow.name", "&tvdbid=$curShow.tvdbid"); +#end for + +addOption("sb.pausebacklog", "Optional Param", "", 1); +addOption("sb.pausebacklog", "Pause", "&pause=1"); +addOption("sb.pausebacklog", "Unpause", "&pause=0"); + +addList("sb.addrootdir", "C:\\Temp", "&location=C:\\Temp", "sb.addrootdir-opt"); +addList("sb.addrootdir", "/usr/bin", "&location=/usr/bin/", "sb.addrootdir-opt"); +addList("sb.addrootdir", "S:\\Invalid_Location", "&location=S:\\Invalid_Location", "sb.addrootdir-opt"); + +addOption("sb.addrootdir-opt", "Optional Param", "", 1); +addOption("sb.addrootdir-opt", "Default", "&default=1"); +addOption("sb.addrootdir-opt", "Not Default", "&default=0"); + +addOption("sb.deleterootdir", "C:\\Temp", "&location=C:\\Temp", "", 1); +addOption("sb.deleterootdir", "/usr/bin", "&location=/usr/bin/"); +addOption("sb.deleterootdir", "S:\\Invalid_Location", "&location=S:\\Invalid_Location"); + +#for $curShow in $sortedShowList: +addList("show.pause", "$curShow.name", "&tvdbid=$curShow.tvdbid", "show.pause-opt"); +#end for +addOption("show.pause-opt", "Optional Param", "", 1); +addOption("show.pause-opt", "Unpause", "&pause=0"); +addOption("show.pause-opt", "Pause", "&pause=1"); + +</script> +</head> + +<body onload="initListGroup('api', document.apibuilder.firstlevel, document.apibuilder.secondlevel, document.apibuilder.thirdlevel, document.apibuilder.forthlevel, document.apibuilder.fifthlevel, document.apibuilder.sixthlevel, document.apibuilder.seventhlevel)"> + +<form name="apibuilder" id="apibuilder" action=""> +<table align="center"> + <tr> + <td> + <input type="text" size="40" id="apikey" name="apikey" value="$apikey"> + <input type="checkbox" id="debug" class="global"><label for="debug"> Debug?</label> + <input type="checkbox" id="profile" class="global"><label for="profile"> Profile?</label> + <input type="checkbox" id="help" class="global"><label for="help"> Help?</label> + </td> + </tr> + <tr> + <td> + <select name="firstlevel"><option></option></select> + <select name="secondlevel"><option></option></select> + <select name="thirdlevel"><option></option></select> + <select name="forthlevel"><option></option></select> + <select name="fifthlevel"><option></option></select> + <select name="sixthlevel"><option></option></select> + <select name="seventhlevel"><option></option></select> + <div style="float: left; "> + <input type="button" value="Reset" onclick="resetListGroup('api',1)" /> + <input type="button" value="Go" onclick="goListGroup(this.form['apikey'].value, this.form['seventhlevel'].value, this.form['sixthlevel'].value, this.form['fifthlevel'].value, this.form['forthlevel'].value, this.form['thirdlevel'].value, this.form['secondlevel'].value, this.form['firstlevel'].value)" /> + </div> + </td> + </tr> +</table> +</form> + +<div id="apiResponse"></div> + +</body> + +</html> diff --git a/data/interfaces/default/comingEpisodes.tmpl b/data/interfaces/default/comingEpisodes.tmpl index e49977e75784149d14c881863211a743c88b12f0..71e387f797764a3908a88e3995c060f85df5bff8 100644 --- a/data/interfaces/default/comingEpisodes.tmpl +++ b/data/interfaces/default/comingEpisodes.tmpl @@ -25,85 +25,53 @@ <script type="text/javascript" src="$sbRoot/js/plotTooltip.js"></script> <script type="text/javascript" charset="utf-8"> <!-- -\$.tablesorter.addParser({ - id: 'nextAirDate', - is: function(s) { - return false; - }, - format: function(s) { - if (s == '') - return '9999-99-99'; - else - return s; - }, - type: 'text' -}); - \$.tablesorter.addParser({ id: 'loadingNames', is: function(s) { return false; - }, - format: function(s) { + }, + format: function(s) { if (s.indexOf('Loading...') == 0) - return s.replace('Loading...','!!!'); - else if (s.indexOf('The ') == 0) - return s.replace('The ', '') - else if (s.indexOf('A ') == 0) - return s.replace('A ', '') - else - return s; + return s.replace('Loading...','000'); + return (s || '').replace(/^(The|A)\s/i,''); }, type: 'text' }); - \$.tablesorter.addParser({ id: 'quality', is: function(s) { return false; }, - format: function(s) { - return s.toLowerCase().replace('hd',3).replace('sd',1).replace('any',0).replace('best',2).replace('custom',4); + format: function(s) { + return s.replace('hd',3).replace('sd',1).replace('any',0).replace('best',2).replace('custom',4); }, type: 'numeric' }); -//http://web.archive.org/web/20080801073104/http://www.jdempster.com/category/code/jquery/tablesortercookiewidget/ -\$.tablesorter.addWidget({ - id: 'cookie', - format: function(table) { - var sortList = table.config.sortList; - var tablesorterCookieJar = \$.cookieJar('tablesorter'); - if ( sortList.length > 0) { - tablesorterCookieJar.set(\$(table).attr('id'), sortList); - } else { - var sortList = tablesorterCookieJar.get(\$(table).attr('id')); - if (sortList && sortList.length > 0) { - jQuery(table).trigger('sorton', [sortList]); - } - } - } -}); -\$(document).ready(function(){ +\$(document).ready(function(){ -#set $sort_codes = {'date': 2, 'show': 3, 'network': 4} +#set $sort_codes = {'date': 0, 'show': 1, 'network': 4} #if $sort not in $sort_codes: $sort = 'date' #end if - sortList = [[$sort_codes[$sort],0]]; + sortList = [[$sort_codes[$sort],0]]; \$("#showListTable:has(tbody tr)").tablesorter({ + widgets: ['stickyHeaders'], sortList: sortList, + textExtraction: { + 5: function(node) { return \$(node).find("span").text().toLowerCase(); } + }, headers: { - 0: { sorter: false}, - 1: { sorter: false}, - 2: { sorter: 'nextAirDate' }, - 3: { sorter: 'loadingNames' }, + 0: { sorter: 'isoDate' }, + 1: { sorter: 'loadingNames' }, + 2: { sorter: false }, + 3: { sorter: false }, 4: { sorter: 'loadingNames' }, 5: { sorter: 'quality' }, - 6: { sorter: false}, - 7: { sorter: false} + 6: { sorter: false }, + 7: { sorter: false } } }); @@ -119,7 +87,7 @@ <br/> <table id="showListTable" class="sickbeardTable tablesorter" cellspacing="1" border="0" cellpadding="0"> - <thead><tr><th class="nowrap">Next Ep</th><th>Next Ep Name</th><th>Airdate</th><th>Show</th><th>Network</th><th>Quality</th><th>tvDB</th><th>Search</th></tr></thead> + <thead><tr><th>Airdate</th><th>Show</th><th class="nowrap">Next Ep</th><th>Next Ep Name</th><th>Network</th><th>Quality</th><th>tvDB</th><th>Search</th></tr></thead> <tbody> #for $cur_result in $sql_results: @@ -143,25 +111,25 @@ <!-- start $cur_result["show_name"] //--> <tr class="$show_div"> - <td class="nowrap"> - #if $cur_result["description"] != "" and $cur_result["description"] != None: - <img alt="" src="$sbRoot/images/info32.png" height="16" width="16" class="plotInfo" id="plot_info_<%=str(cur_result["showid"])+"_"+str(cur_result["season"])+"_"+str(cur_result["episode"])%>" /> - #end if - <span><%="%02ix%02i" % (int(cur_result["season"]), int(cur_result["episode"])) %></span> - </td> - <td>$cur_result["name"]</td> <td align="center" class="nowrap">$datetime.date.fromordinal(int($cur_result["airdate"]))</td> <td class="tvShow"><a href="$sbRoot/home/displayShow?show=${cur_result["showid"]}">$cur_result["show_name"]</a> #if int($cur_result["paused"]): <span class="pause">[paused]</span> #end if </td> + <td class="nowrap" align="center"><%="%02ix%02i" % (int(cur_result["season"]), int(cur_result["episode"])) %></td> + <td> + #if $cur_result["description"] != "" and $cur_result["description"] != None: + <img alt="" src="$sbRoot/images/info32.png" height="16" width="16" class="plotInfo" id="plot_info_<%=str(cur_result["showid"])+"_"+str(cur_result["season"])+"_"+str(cur_result["episode"])%>" /> + #end if + $cur_result["name"] + </td> <td align="center">$cur_result["network"]</td> <td align="center"> #if int($cur_result["quality"]) in $qualityPresets: -$qualityPresetStrings[int($cur_result["quality"])] + <span class="quality $qualityPresetStrings[int($cur_result["quality"])]">$qualityPresetStrings[int($cur_result["quality"])]</span> #else: -Custom + <span class="quality Custom">Custom</span> #end if </td> <td align="center"><a href="http://www.thetvdb.com/?tab=series&id=${cur_result["showid"]}" onclick="window.open(this.href, '_blank'); return false;" title="http://www.thetvdb.com/?tab=series&id=${cur_result["showid"]}"><img alt="[info]" height="16" width="16" src="$sbRoot/images/thetvdb16.png" /></a></td> @@ -281,11 +249,10 @@ Custom <td style="vertical-align: top;"> <span class="title">Airs:</span> <span>$cur_result["airs"] on $cur_result["network"]</span> #if int($cur_result["quality"]) in $qualityPresets: -[<span class="title">$qualityPresetStrings[int($cur_result["quality"])]</span>] + [<span class="title">$qualityPresetStrings[int($cur_result["quality"])]</span>]<br /> #else: -[<span class="title">Custom</span>] + [<span class="title">Custom</span>]<br /> #end if - <br /> #if $cur_result["description"] == '': <div class="ep_summary" style="margin-left:0;display:block !important;">[There is no summary added for this episode]</div> #else: @@ -312,5 +279,5 @@ window.setInterval( "location.reload(true)", 600000); // Refresh every 10 minute //--> </script> -<!--<script type="text/javascript" src="$sbRoot/js/tableClick.js"></script>--> +<script type="text/javascript" src="$sbRoot/js/tableClick.js"></script> #include $os.path.join($sickbeard.PROG_DIR, "data/interfaces/default/inc_bottom.tmpl") diff --git a/data/interfaces/default/config_general.tmpl b/data/interfaces/default/config_general.tmpl index ee7bc51e4e2c04a68142c97402657964b7065083..8eb0e30187d0f4da3569a00b8447a6f3fe7c8484 100644 --- a/data/interfaces/default/config_general.tmpl +++ b/data/interfaces/default/config_general.tmpl @@ -21,7 +21,7 @@ <form id="configForm" action="saveGeneral" method="post"> <div id="config-components"> - + <div id="core-component-group1" class="component-group clearfix"> <div class="component-group-desc"> @@ -63,15 +63,16 @@ </div><!-- /component-group1 //--> - <div id="core-component-group3" class="component-group clearfix"> + <div id="core-component-group2" class="component-group clearfix"> <div class="component-group-desc"> <h3>Web Interface</h3> <p>It is recommended that you enable a username and password to secure Sick Beard from being tampered with remotely.</p> - <p><b>Some options may require a manual restart to take effect.</b></p> + <p><b>These options require a manual restart to take effect.</b></p> </div> <fieldset class="component-group-list"> + <div class="field-pair"> <input type="checkbox" name="web_ipv6" id="web_ipv6" #if $sickbeard.WEB_IPV6 then "checked=\"checked\"" else ""#/> <label class="clearfix" for="web_ipv6"> @@ -121,9 +122,75 @@ </label> </div> + <div class="field-pair"> + <label class="clearfix"> + <input type="checkbox" name="enable_https" class="enabler" id="enable_https" #if $sickbeard.ENABLE_HTTPS then "checked=\"checked\"" else ""#/> + <span class="component-title">Enable HTTPS</span> + <span class="component-desc">Enable accessing the interface from a HTTPS address.</span> + </label> + </div> + + <div id="content_enable_https"> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">HTTPS Certificate</span> + <input type="text" name="https_cert" value="$sickbeard.HTTPS_CERT" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">File name or path to HTTPS Certificate.</span> + </label> + </div> + + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">HTTPS Key</span> + <input type="text" name="https_key" value="$sickbeard.HTTPS_KEY" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">File name or path to HTTPS Key.</span> + </label> + </div> + </div> + + <input type="submit" class="config_submitter" value="Save Changes" /> + </fieldset> + </div><!-- /component-group2 //--> + + <div id="core-component-group4" class="component-group clearfix"> + + <div class="component-group-desc"> + <h3>API</h3> + <p>Allow 3rd party programs to interact with Sick-Beard.</p> + </div> + + <fieldset class="component-group-list"> + <div class="field-pair"> + <input type="checkbox" name="use_api" class="enabler" id="use_api" #if $sickbeard.USE_API then "checked=\"checked\"" else ""#/> + <label class="clearfix" for="use_api"> + <span class="component-title">Enable API</span> + <span class="component-desc">Allow the use of the Sick-Beard API.</span> + </label> + </div> + + <div id="content_use_api"> + <div class="field-pair"> + <label class="nocheck clearfix" for="api_key"> + <span class="component-title">API Key</span> + <input type="text" name="api_key" id="api_key" value="$sickbeard.API_KEY" size="40" readonly="readonly" /> + <input type="button" id="generate_new_apikey" value="Generate"> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Used to give 3rd party programs limited access to Sick-Beard.</span> + </label> + </div> + </div> + <input type="submit" class="config_submitter" value="Save Changes" /> </fieldset> - </div><!-- /component-group3 //--> + </div><!-- /component-group4 //--> <br/><input type="submit" class="config_submitter" value="Save Changes" /><br/> </div><!-- /config-components --> diff --git a/data/interfaces/default/config_notifications.tmpl b/data/interfaces/default/config_notifications.tmpl index 5eff910842b37393aee71dfdf0f71bad9e665f19..5cd55d651af62581b779a2e630e84c9cc3870516 100755 --- a/data/interfaces/default/config_notifications.tmpl +++ b/data/interfaces/default/config_notifications.tmpl @@ -11,19 +11,21 @@ <script type="text/javascript" src="$sbRoot/js/config.js"></script> <div id="config"> -<div id="config-content"> + <div id="config-content"> + <form id="configForm" action="saveNotifications" method="post"> + <div id="config-components"> -<form id="configForm" action="saveNotifications" method="post"> - <div id="config-components"> + <br /> + <h1>Home Theater</h1> + <br /> - <div id="core-component-group1" class="component-group clearfix"> + <div class="component-group clearfix"> <div class="component-group-desc"> - <h3><a href="http://xbmc.org/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/xbmc.gif" alt="XBMC" title="XBMC" width="16" height="16" /> XBMC</a></h3> + <h3><a href="http://xbmc.org/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/xbmc.gif" alt="" title="XBMC" width="16" height="16" /> XBMC </a></h3> <p>A free and open source cross-platform media center and home entertainment system software with a 10-foot user interface designed for the living-room TV.</p> </div> - <fieldset class="component-group-list"> <div class="field-pair"> <input type="checkbox" class="enabler" name="use_xbmc" id="use_xbmc" #if $sickbeard.USE_XBMC then "checked=\"checked\"" else ""# /> @@ -34,91 +36,82 @@ </div> <div id="content_use_xbmc"> - <div class="field-pair"> - <input type="checkbox" name="xbmc_notify_onsnatch" id="xbmc_notify_onsnatch" #if $sickbeard.XBMC_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="xbmc_notify_onsnatch"> - <span class="component-title">Notify on Snatch</span> - <span class="component-desc">Send notification when we start a download?</span> - </label> - </div> - - <div class="field-pair"> - <input type="checkbox" name="xbmc_notify_ondownload" id="xbmc_notify_ondownload" #if $sickbeard.XBMC_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="xbmc_notify_ondownload"> - <span class="component-title">Notify on Download</span> - <span class="component-desc">Send notification when we finish a download?</span> - </label> - </div> - - <div class="field-pair"> - <input type="checkbox" name="xbmc_update_library" id="xbmc_update_library" #if $sickbeard.XBMC_UPDATE_LIBRARY then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="xbmc_update_library"> - <span class="component-title">Update Library</span> - <span class="component-desc">Update XBMC library when we finish a download?</span> - </label> - </div> - - <div class="field-pair"> - <input type="checkbox" name="xbmc_update_full" id="xbmc_update_full" #if $sickbeard.XBMC_UPDATE_FULL then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="xbmc_update_full"> - <span class="component-title">Full Library Update</span> - <span class="component-desc">Do a full library update if per-show fails?</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">XBMC IP:Port</span> - <input type="text" name="xbmc_host" id="xbmc_host" value="$sickbeard.XBMC_HOST" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Host running XBMC (eg. 192.168.1.100:8080)</span> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">(multiple host strings can be separated by commas)</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">XBMC Username</span> - <input type="text" name="xbmc_username" id="xbmc_username" value="$sickbeard.XBMC_USERNAME" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Username of your XBMC server (blank for none)</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">XBMC Password</span> - <input type="password" name="xbmc_password" id="xbmc_password" value="$sickbeard.XBMC_PASSWORD" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Password of your XBMC server (blank for none)</span> - </label> - </div> - - <div class="testNotification" id="testXBMC-result">Click below to test.</div> - <input type="button" value="Test XBMC" id="testXBMC" /> - <input type="submit" class="config_submitter" value="Save Changes" /> - - </div><!-- /enabler_xbmc //--> + <div class="field-pair"> + <input type="checkbox" name="xbmc_notify_onsnatch" id="xbmc_notify_onsnatch" #if $sickbeard.XBMC_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="xbmc_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="xbmc_notify_ondownload" id="xbmc_notify_ondownload" #if $sickbeard.XBMC_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="xbmc_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="xbmc_update_library" id="xbmc_update_library" #if $sickbeard.XBMC_UPDATE_LIBRARY then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="xbmc_update_library"> + <span class="component-title">Update Library</span> + <span class="component-desc">Update XBMC library when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="xbmc_update_full" id="xbmc_update_full" #if $sickbeard.XBMC_UPDATE_FULL then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="xbmc_update_full"> + <span class="component-title">Full Library Update</span> + <span class="component-desc">Do a full library update if per-show fails?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">XBMC IP:Port</span> + <input type="text" name="xbmc_host" id="xbmc_host" value="$sickbeard.XBMC_HOST" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Host running XBMC (eg. 192.168.1.100:8080)</span> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">(multiple host strings can be separated by commas)</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">XBMC Username</span> + <input type="text" name="xbmc_username" id="xbmc_username" value="$sickbeard.XBMC_USERNAME" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Username of your XBMC server (blank for none)</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">XBMC Password</span> + <input type="password" name="xbmc_password" id="xbmc_password" value="$sickbeard.XBMC_PASSWORD" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Password of your XBMC server (blank for none)</span> + </label> + </div> + <div class="testNotification" id="testXBMC-result">Click below to test.</div> + <input type="button" value="Test XBMC" id="testXBMC" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_xbmc //--> </fieldset> - </div><!-- /component-group //--> + </div><!-- /xbmc component-group //--> - <div id="core-component-group2" class="component-group clearfix"> + <div class="component-group clearfix"> <div class="component-group-desc"> - <h3><a href="http://www.plexapp.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/plex.gif" alt="Plex Media Server" title="Plex Media Server" width="16" height="16" /> Plex Media Server</a></h3> + <h3><a href="http://www.plexapp.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/plex.gif" alt="" title="Plex Media Server" width="16" height="16" /> Plex Media Server </a></h3> <p>Experience your media on a visually stunning, easy to use interface on your Mac connected to your TV. Your media library has never looked this good!</p> </div> - <fieldset class="component-group-list"> <div class="field-pair"> <input type="checkbox" class="enabler" name="use_plex" id="use_plex" #if $sickbeard.USE_PLEX then "checked=\"checked\"" else ""# /> @@ -129,233 +122,296 @@ </div> <div id="content_use_plex"> - <div class="field-pair"> - <input type="checkbox" name="plex_notify_onsnatch" id="plex_notify_onsnatch" #if $sickbeard.PLEX_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="plex_notify_onsnatch"> - <span class="component-title">Notify on Snatch</span> - <span class="component-desc">Send notification when we start a download?</span> - </label> - </div> + <div class="field-pair"> + <input type="checkbox" name="plex_notify_onsnatch" id="plex_notify_onsnatch" #if $sickbeard.PLEX_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="plex_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="plex_notify_ondownload" id="plex_notify_ondownload" #if $sickbeard.PLEX_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="plex_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="plex_update_library" id="plex_update_library" #if $sickbeard.PLEX_UPDATE_LIBRARY then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="plex_update_library"> + <span class="component-title">Update Library</span> + <span class="component-desc">Update Plex Media Server library when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Plex Media Server IP:Port</span> + <input type="text" name="plex_server_host" id="plex_server_host" value="$sickbeard.PLEX_SERVER_HOST" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Host running Plex Media Server (eg. 192.168.1.100:32400)</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Plex Client IP:Port</span> + <input type="text" name="plex_host" id="plex_host" value="$sickbeard.PLEX_HOST" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Host running Plex Client (eg. 192.168.1.100:3000)</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Plex Client Username</span> + <input type="text" name="plex_username" id="plex_username" value="$sickbeard.PLEX_USERNAME" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Username of your Plex client API (blank for none)</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Plex Client Password</span> + <input type="password" name="plex_password" id="plex_password" value="$sickbeard.PLEX_PASSWORD" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Password of your Plex client API (blank for none)</span> + </label> + </div> + <div class="testNotification" id="testPLEX-result">Click below to test.</div> + <input type="button" value="Test Plex Media Server" id="testPLEX" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_plex --> - <div class="field-pair"> - <input type="checkbox" name="plex_notify_ondownload" id="plex_notify_ondownload" #if $sickbeard.PLEX_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="plex_notify_ondownload"> - <span class="component-title">Notify on Download</span> - <span class="component-desc">Send notification when we finish a download?</span> - </label> - </div> - - <div class="field-pair"> - <input type="checkbox" name="plex_update_library" id="plex_update_library" #if $sickbeard.PLEX_UPDATE_LIBRARY then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="plex_update_library"> - <span class="component-title">Update Library</span> - <span class="component-desc">Update Plex Media Server library when we finish a download?</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Plex Media Server IP:Port</span> - <input type="text" name="plex_server_host" id="plex_server_host" value="$sickbeard.PLEX_SERVER_HOST" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Host running Plex Media Server (eg. 192.168.1.100:32400)</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Plex Client IP:Port</span> - <input type="text" name="plex_host" id="plex_host" value="$sickbeard.PLEX_HOST" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Host running Plex Client (eg. 192.168.1.100:3000)</span> - </label> - </div> + </fieldset> + </div><!-- /plex component-group --> - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Plex Client Username</span> - <input type="text" name="plex_username" id="plex_username" value="$sickbeard.PLEX_USERNAME" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Username of your Plex client API (blank for none)</span> - </label> - </div> + <div class="component-group clearfix"> + <div class="component-group-desc"> + <h3><a href="http://www.popcornhour.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/nmj.gif" alt="" title="Networked Media Jukebox" width="16" height="16" /> NMJ </a></h3> + <p>The Networked Media Jukebox, or NMJ, is the official media jukebox interface made available for the Popcorn Hour 200-series.</p> + </div> + <fieldset class="component-group-list"> <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Plex Client Password</span> - <input type="password" name="plex_password" id="plex_password" value="$sickbeard.PLEX_PASSWORD" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Password of your Plex client API (blank for none)</span> + <input type="checkbox" class="enabler" name="use_nmj" id="use_nmj" #if $sickbeard.USE_NMJ then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_nmj"> + <span class="component-title">Enable</span> + <span class="component-desc">Should Sick Beard send update commands to NMJ?</span> </label> </div> - <div class="testNotification" id="testPLEX-result">Click below to test.</div> - <input type="button" value="Test Plex Media Server" id="testPLEX" /> - <input type="submit" class="config_submitter" value="Save Changes" /> - - </div><!-- /enabler_plex --> + <div id="content_use_nmj"> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Popcorn IP address</span> + <input type="text" name="nmj_host" id="nmj_host" value="$sickbeard.NMJ_HOST" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">IP of Popcorn 200-series (eg. 192.168.1.100)</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Get Settings</span> + <input type="button" value="Get Settings" id="settingsNMJ" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">The Popcorn Hour device must be powered on and NMJ running.</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">NMJ Database</span> + <input type="text" name="nmj_database" id="nmj_database" value="$sickbeard.NMJ_DATABASE" size="35" #if $sickbeard.NMJ_DATABASE then "readonly=\"readonly\"" else ""# /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Automatically filled via the 'Get Settings' button.</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">NMJ Mount URL</span> + <input type="text" name="nmj_mount" id="nmj_mount" value="$sickbeard.NMJ_MOUNT" size="35" #if $sickbeard.NMJ_MOUNT then "readonly=\"readonly\"" else ""# /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Automatically filled via the 'Get Settings' button.</span> + </label> + </div> + <div class="testNotification" id="testNMJ-result">Click below to test.</div> + <input type="button" value="Test NMJ" id="testNMJ" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_nmj //--> </fieldset> - </div><!-- /component-group --> + </div><!-- /nmj component-group //--> - <div id="core-component-group3" class="component-group clearfix"> + <div class="component-group clearfix"> <div class="component-group-desc"> - <h3><a href="http://growl.info/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/growl.gif" alt="Growl" title="Growl" width="16" height="16" /> Growl</a></h3> - <p>A cross-platform unobtrusive global notification system.</p> + <h3><a href="http://synology.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/synoindex.gif" alt="" title="Synology Indexer" width="16" height="16" /> Synology Indexer </a></h3> + <p>Synology Indexer is the daemon running on the Synology NAS to build its media database.</p> </div> <fieldset class="component-group-list"> <div class="field-pair"> - <input type="checkbox" class="enabler" name="use_growl" id="use_growl" #if $sickbeard.USE_GROWL then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="use_growl"> + <input type="checkbox" class="enabler" name="use_synoindex" id="use_synoindex" #if $sickbeard.USE_SYNOINDEX then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_synoindex"> <span class="component-title">Enable</span> - <span class="component-desc">Should Sick Beard send Growl notifications?</span> - </label> - </div> - - <div id="content_use_growl"> - <div class="field-pair"> - <input type="checkbox" name="growl_notify_onsnatch" id="growl_notify_onsnatch" #if $sickbeard.GROWL_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="growl_notify_onsnatch"> - <span class="component-title">Notify on Snatch</span> - <span class="component-desc">Send notification when we start a download?</span> - </label> - </div> - - <div class="field-pair"> - <input type="checkbox" name="growl_notify_ondownload" id="growl_notify_ondownload" #if $sickbeard.GROWL_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="growl_notify_ondownload"> - <span class="component-title">Notify on Download</span> - <span class="component-desc">Send notification when we finish a download?</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Growl IP:Port</span> - <input type="text" name="growl_host" id="growl_host" value="$sickbeard.GROWL_HOST" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Host running Growl (eg. 192.168.1.100:23053)</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Growl Password</span> - <input type="password" name="growl_password" id="growl_password" value="$sickbeard.GROWL_PASSWORD" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">May leave blank if Sick Beard is on the same host.</span> + <span class="component-desc">Should Sick Beard send notifications to the synoindex daemon?<br /><br /> + </span> </label> - <label class="nocheck clearfix"> + <label class="nocheck clearfix" for="use_synoindex"> <span class="component-title"> </span> - <span class="component-desc">Otherwise Growl <b>requires</b> a password to be used.</span> + <span class="component-desc">Note: Requires SB to be running on your Synology NAS.</span> </label> </div> - <div class="testNotification" id="testGrowl-result">Click below to register and test Growl, this is required for Growl notifications to work.</div> - <input type="button" value="Register Growl" id="testGrowl" /> - <input type="submit" class="config_submitter" value="Save Changes" /> - - </div><!-- /content_use_growl //--> + <div id="content_use_synoindex"> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_pytivo //--> </fieldset> - </div><!-- /component-group //--> + </div><!-- /synoindex component-group //--> + - <div id="core-component-group4" class="component-group clearfix"> - + <div class="component-group clearfix"> <div class="component-group-desc"> - <h3><a href="http://www.twitter.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/twitter.gif" alt="Twitter" title="Twitter" width="16" height="16" /> Twitter</a></h3> - <p>A social networking and microblogging service, enabling its users to send and read other users' messages called tweets.</p> + <h3><a href="http://pytivo.sourceforge.net/wiki/index.php/PyTivo" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/pytivo.gif" alt="" title="pyTivo" width="16" height="16" /> pyTivo </a></h3> + <p>pyTivo is both an HMO and GoBack server. This notifier will load the completed downloads to your Tivo.</p> </div> - <fieldset class="component-group-list"> <div class="field-pair"> - <input type="checkbox" class="enabler" name="use_twitter" id="use_twitter" #if $sickbeard.USE_TWITTER then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="use_twitter"> + <input type="checkbox" class="enabler" name="use_pytivo" id="use_pytivo" #if $sickbeard.USE_PYTIVO then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_pytivo"> <span class="component-title">Enable</span> - <span class="component-desc">Should Sick Beard post tweets on Twitter?</span> + <span class="component-desc">Should Sick Beard send notifications to pyTivo?<br /><br /></span> </label> - <label class="nocheck clearfix" for="use_twitter"> + <label class="nocheck clearfix" for="use_pytivo"> <span class="component-title"> </span> - <span class="component-desc">You may want to use a second account.</span> - </label> - </div> + <span class="component-desc">Requires the downloaded files to be accessible to pyTivo.</span> + </label> + </div> + + <div id="content_use_pytivo"> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">pyTivo IP:Port</span> + <input type="text" name="pytivo_host" id="pytivo_host" value="$sickbeard.PYTIVO_HOST" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Host running pyTivo (eg. 192.168.1.1:9032)</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">pyTivo Share name</span> + <input type="text" name="pytivo_share_name" id="pytivo_share_name" value="$sickbeard.PYTIVO_SHARE_NAME" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Value used in pyTivo Web Configuration to name the share.</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Tivo Name</span> + <input type="text" name="pytivo_tivo_name" id="pytivo_tivo_name" value="$sickbeard.PYTIVO_TIVO_NAME" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Messages & Settings > Account & System Information > System Information > DVR name</span> + </label> + </div> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_pytivo //--> - <div id="content_use_twitter"> - <div class="field-pair"> - <input type="checkbox" name="twitter_notify_onsnatch" id="twitter_notify_onsnatch" #if $sickbeard.TWITTER_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="twitter_notify_onsnatch"> - <span class="component-title">Notify on Snatch</span> - <span class="component-desc">Send notification when we start a download?</span> - </label> - </div> + </fieldset> + </div><!-- /component-group //--> - <div class="field-pair"> - <input type="checkbox" name="twitter_notify_ondownload" id="twitter_notify_ondownload" #if $sickbeard.TWITTER_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="twitter_notify_ondownload"> - <span class="component-title">Notify on Download</span> - <span class="component-desc">Send notification when we finish a download?</span> - </label> - </div> - <div class="field-pair"> - <label class="clearfix"> - <span class="component-title">Step One</span> - </label> - <label class="nocheck clearfix"> - <span class="component-desc">Click the "Request Authorization" button.<br/> This will open a new page containing an auth key.<br/> Note: if nothing happens check your popup blocker.<br/></span> - <input type="button" value="Request Authorization" id="twitterStep1" /> - </label> - </div> + <br /> + <h1>Devices</h1> + <br /> - <div class="field-pair"> - <label class="clearfix"> - <span class="component-title">Step Two</span> - </label> - <label class="nocheck clearfix"> - <span class="component-desc">Enter the key Twitter gave you below, and click "Verify Key".<br/></span> - <input type="text" id="twitter_key" value="" size="35" /><br /> - </label> - <label class="nocheck clearfix"> - <input type="button" value="Verify Key" id="twitterStep2" /> - </label> - </div> + <div class="component-group clearfix"> + <div class="component-group-desc"> + <h3><a href="http://growl.info/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/growl.gif" alt="" title="Growl" width="16" height="16" /> Growl </a></h3> + <p>A cross-platform unobtrusive global notification system.</p> + </div> + <fieldset class="component-group-list"> <div class="field-pair"> - <label class="clearfix"> - <span class="component-title">Step Three</span> + <input type="checkbox" class="enabler" name="use_growl" id="use_growl" #if $sickbeard.USE_GROWL then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_growl"> + <span class="component-title">Enable</span> + <span class="component-desc">Should Sick Beard send Growl notifications?</span> </label> </div> - <div class="testNotification" id="testTwitter-result">Click below to test.</div> - <input type="button" value="Test Twitter" id="testTwitter" /> - <input type="submit" class="config_submitter" value="Save Changes" /> - - </div><!-- /content_use_twitter //--> + <div id="content_use_growl"> + <div class="field-pair"> + <input type="checkbox" name="growl_notify_onsnatch" id="growl_notify_onsnatch" #if $sickbeard.GROWL_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="growl_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="growl_notify_ondownload" id="growl_notify_ondownload" #if $sickbeard.GROWL_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="growl_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Growl IP:Port</span> + <input type="text" name="growl_host" id="growl_host" value="$sickbeard.GROWL_HOST" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Host running Growl (eg. 192.168.1.100:23053)</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Growl Password</span> + <input type="password" name="growl_password" id="growl_password" value="$sickbeard.GROWL_PASSWORD" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">May leave blank if Sick Beard is on the same host.</span> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Otherwise Growl <b>requires</b> a password to be used.</span> + </label> + </div> + <div class="testNotification" id="testGrowl-result">Click below to register and test Growl, this is required for Growl notifications to work.</div> + <input type="button" value="Register Growl" id="testGrowl" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_growl //--> </fieldset> - </div><!-- /component-group //--> - - <div id="core-component-group5" class="component-group clearfix"> + </div><!-- /growl component-group //--> + + <div class="component-group clearfix"> <div class="component-group-desc"> <h3><a href="http://www.prowlapp.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/prowl.gif" alt="Prowl" title="Prowl" width="16" height="16" /> Prowl</a></h3> <p>A Growl client for iOS.</p> </div> - <fieldset class="component-group-list"> <div class="field-pair"> <input type="checkbox" class="enabler" name="use_prowl" id="use_prowl" #if $sickbeard.USE_PROWL then "checked=\"checked\"" else ""# /> @@ -366,66 +422,60 @@ </div> <div id="content_use_prowl"> - <div class="field-pair"> - <input type="checkbox" name="prowl_notify_onsnatch" id="prowl_notify_onsnatch" #if $sickbeard.PROWL_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="prowl_notify_onsnatch"> - <span class="component-title">Notify on Snatch</span> - <span class="component-desc">Send notification when we start a download?</span> - </label> - </div> - - <div class="field-pair"> - <input type="checkbox" name="prowl_notify_ondownload" id="prowl_notify_ondownload" #if $sickbeard.PROWL_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="prowl_notify_ondownload"> - <span class="component-title">Notify on Download</span> - <span class="component-desc">Send notification when we finish a download?</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Prowl API key:</span> - <input type="text" name="prowl_api" id="prowl_api" value="$sickbeard.PROWL_API" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Get your key at: <a href="https://www.prowlapp.com/api_settings.php" onclick="window.open(this.href, '_blank'); return false;">https://www.prowlapp.com/api_settings.php</a></span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Prowl priority:</span> - <select id="prowl_priority" name="prowl_priority"> - <option value="-2" #if $sickbeard.PROWL_PRIORITY == "-2" then 'selected="selected"' else ""#>Very Low</option> - <option value="-1" #if $sickbeard.PROWL_PRIORITY == "-1" then 'selected="selected"' else ""#>Moderate</option> - <option value="0" #if $sickbeard.PROWL_PRIORITY == "0" then 'selected="selected"' else ""#>Normal</option> - <option value="1" #if $sickbeard.PROWL_PRIORITY == "1" then 'selected="selected"' else ""#>High</option> - <option value="2" #if $sickbeard.PROWL_PRIORITY == "2" then 'selected="selected"' else ""#>Emergency</option> - </select> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Priority of Prowl messages from Sick-Beard.</span> - </label> - </div> - - <div class="testNotification" id="testProwl-result">Click below to test.</div> - <input type="button" value="Test Prowl" id="testProwl" /> - <input type="submit" class="config_submitter" value="Save Changes" /> - + <div class="field-pair"> + <input type="checkbox" name="prowl_notify_onsnatch" id="prowl_notify_onsnatch" #if $sickbeard.PROWL_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="prowl_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="prowl_notify_ondownload" id="prowl_notify_ondownload" #if $sickbeard.PROWL_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="prowl_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Prowl API key:</span> + <input type="text" name="prowl_api" id="prowl_api" value="$sickbeard.PROWL_API" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Get your key at: <a href="https://www.prowlapp.com/api_settings.php" onclick="window.open(this.href, '_blank'); return false;">https://www.prowlapp.com/api_settings.php</a></span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Prowl priority:</span> + <select id="prowl_priority" name="prowl_priority"> + <option value="-2" #if $sickbeard.PROWL_PRIORITY == "-2" then 'selected="selected"' else ""#>Very Low</option> + <option value="-1" #if $sickbeard.PROWL_PRIORITY == "-1" then 'selected="selected"' else ""#>Moderate</option> + <option value="0" #if $sickbeard.PROWL_PRIORITY == "0" then 'selected="selected"' else ""#>Normal</option> + <option value="1" #if $sickbeard.PROWL_PRIORITY == "1" then 'selected="selected"' else ""#>High</option> + <option value="2" #if $sickbeard.PROWL_PRIORITY == "2" then 'selected="selected"' else ""#>Emergency</option> + </select> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Priority of Prowl messages from Sick-Beard.</span> + </label> + </div> + <div class="testNotification" id="testProwl-result">Click below to test.</div> + <input type="button" value="Test Prowl" id="testProwl" /> + <input type="submit" class="config_submitter" value="Save Changes" /> </div><!-- /content_use_prowl //--> </fieldset> - </div><!-- /component-group //--> + </div><!-- /prowl component-group //--> - <div id="core-component-group6" class="component-group clearfix"> + <div class="component-group clearfix"> <div class="component-group-desc"> - <h3><a href="http://notifo.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/notifo.gif" alt="Notifo" title="Notifo" width="16" height="16" /> Notifo</a></h3> + <h3><a href="http://notifo.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/notifo.gif" alt="" title="Notifo" width="16" height="16" /> Notifo </a></h3> <p>A platform for push-notifications to either mobile or desktop clients</p> </div> - <fieldset class="component-group-list"> <div class="field-pair"> <input type="checkbox" class="enabler" name="use_notifo" id="use_notifo" #if $sickbeard.USE_NOTIFO then "checked=\"checked\"" else ""# /> @@ -436,61 +486,54 @@ </div> <div id="content_use_notifo"> - <div class="field-pair"> - <input type="checkbox" name="notifo_notify_onsnatch" id="notifo_notify_onsnatch" #if $sickbeard.NOTIFO_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="notifo_notify_onsnatch"> - <span class="component-title">Notify on Snatch</span> - <span class="component-desc">Send notification when we start a download?</span> - </label> - </div> - - <div class="field-pair"> - <input type="checkbox" name="notifo_notify_ondownload" id="notifo_notify_ondownload" #if $sickbeard.NOTIFO_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="notifo_notify_ondownload"> - <span class="component-title">Notify on Download</span> - <span class="component-desc">Send notification when we finish a download?</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Notifo Username</span> - <input type="text" name="notifo_username" id="notifo_username" value="$sickbeard.NOTIFO_USERNAME" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Username of your Notifo account</span> - </label> - </div> - - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Notifo API secret</span> - <input type="password" name="notifo_apisecret" id="notifo_apisecret" value="$sickbeard.NOTIFO_APISECRET" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Get your API key at: <a href="http://notifo.com/user/settings" onclick="window.open(this.href, '_blank'); return false;">http://notifo.com/user/settings</a></span> - </label> - </div> - - <div class="testNotification" id="testNotifo-result">Click below to test.</div> - <input type="button" value="Test Notifo" id="testNotifo" /> - <input type="submit" class="config_submitter" value="Save Changes" /> - + <div class="field-pair"> + <input type="checkbox" name="notifo_notify_onsnatch" id="notifo_notify_onsnatch" #if $sickbeard.NOTIFO_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="notifo_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="notifo_notify_ondownload" id="notifo_notify_ondownload" #if $sickbeard.NOTIFO_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="notifo_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Notifo Username</span> + <input type="text" name="notifo_username" id="notifo_username" value="$sickbeard.NOTIFO_USERNAME" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Username of your Notifo account</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Notifo API secret</span> + <input type="password" name="notifo_apisecret" id="notifo_apisecret" value="$sickbeard.NOTIFO_APISECRET" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Get your API key at: <a href="http://notifo.com/user/settings" onclick="window.open(this.href, '_blank'); return false;">http://notifo.com/user/settings</a></span> + </label> + </div> + <div class="testNotification" id="testNotifo-result">Click below to test.</div> + <input type="button" value="Test Notifo" id="testNotifo" /> + <input type="submit" class="config_submitter" value="Save Changes" /> </div><!-- /content_use_notifo //--> </fieldset> + </div><!-- /notifo component-group //--> - </div> - - <div id="core-component-group7" class="component-group clearfix"> + <div class="component-group clearfix"> <div class="component-group-desc"> - <h3><a href="http://library.gnome.org/devel/libnotify/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/libnotify.gif" alt="Libnotify" title="Libnotify" width="16" height="16" /> Libnotify</a></h3> + <h3><a href="http://library.gnome.org/devel/libnotify/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/libnotify.gif" alt="" title="Libnotify" width="16" height="16" /> Libnotify </a></h3> <p>The standard desktop notification API for Linux/*nix systems. This notifier will only function if the pynotify module is installed (Ubuntu/Debian package <a href="apt:python-notify">python-notify</a>).</p> </div> - <fieldset class="component-group-list"> <div class="field-pair"> <input type="checkbox" class="enabler" name="use_libnotify" id="use_libnotify" #if $sickbeard.USE_LIBNOTIFY then "checked=\"checked\"" else ""# /> @@ -501,130 +544,320 @@ </div> <div id="content_use_libnotify"> - <div class="field-pair"> - <input type="checkbox" name="libnotify_notify_onsnatch" id="libnotify_notify_onsnatch" #if $sickbeard.LIBNOTIFY_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="libnotify_notify_onsnatch"> - <span class="component-title">Notify on Snatch</span> - <span class="component-desc">Send notification when we start a download?</span> - </label> - </div> - - <div class="field-pair"> - <input type="checkbox" name="libnotify_notify_ondownload" id="libnotify_notify_ondownload" #if $sickbeard.LIBNOTIFY_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="libnotify_notify_ondownload"> - <span class="component-title">Notify on Download</span> - <span class="component-desc">Send notification when we finish a download?</span> - </label> - </div> - - <div class="testNotification" id="testLibnotify-result">Click below to test.</div> - <input type="button" value="Test Libnotify" id="testLibnotify" /> - <input type="submit" class="config_submitter" value="Save Changes" /> - + <div class="field-pair"> + <input type="checkbox" name="libnotify_notify_onsnatch" id="libnotify_notify_onsnatch" #if $sickbeard.LIBNOTIFY_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="libnotify_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="libnotify_notify_ondownload" id="libnotify_notify_ondownload" #if $sickbeard.LIBNOTIFY_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="libnotify_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="testNotification" id="testLibnotify-result">Click below to test.</div> + <input type="button" value="Test Libnotify" id="testLibnotify" /> + <input type="submit" class="config_submitter" value="Save Changes" /> </div><!-- /content_use_libnotify //--> </fieldset> - </div><!-- /component-group //--> + </div><!-- /libnotify component-group //--> - <div id="core-component-group8" class="component-group clearfix"> + <div class="component-group clearfix"> <div class="component-group-desc"> - <h3><a href="http://www.popcornhour.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/nmj.gif" alt="Networked Media Jukebox" title="Networked Media Jukebox" width="16" height="16" /> NMJ</a></h3> - <p>The Networked Media Jukebox, or NMJ, is the official media jukebox interface made available for the Popcorn Hour 200-series.</p> + <h3><a href="http://pushover.net/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/pushover.gif" alt="" title="Pushover" width="16" height="16" /> Pushover </a></h3> + <p>Pushover makes it easy to send real-time notifications to your Android and iOS devices.</p> </div> - <fieldset class="component-group-list"> <div class="field-pair"> - <input type="checkbox" class="enabler" name="use_nmj" id="use_nmj" #if $sickbeard.USE_NMJ then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="use_nmj"> + <input type="checkbox" class="enabler" name="use_pushover" id="use_pushover" #if $sickbeard.USE_PUSHOVER then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_pushover"> <span class="component-title">Enable</span> - <span class="component-desc">Should Sick Beard send update commands to NMJ?</span> - </label> - </div> + <span class="component-desc">Should Sick Beard send notifications through Pushover?</span> + </label> + </div> + + <div id="content_use_pushover"> + <div class="field-pair"> + <input type="checkbox" name="pushover_notify_onsnatch" id="pushover_notify_onsnatch" #if $sickbeard.PUSHOVER_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="pushover_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="pushover_notify_ondownload" id="pushover_notify_ondownload" #if $sickbeard.PUSHOVER_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="pushover_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title"></span> + <input type="text" name="pushover_userkey" id="pushover_userkey" value="$sickbeard.PUSHOVER_USERKEY" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">User key of your Pushover account</span> + </label> + </div> + <div class="testNotification" id="testPushover-result">Click below to test.</div> + <input type="button" value="Test Pushover" id="testPushover" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_pushover //--> - <div id="content_use_nmj"> - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Popcorn IP address</span> - <input type="text" name="nmj_host" id="nmj_host" value="$sickbeard.NMJ_HOST" size="35" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">IP of Popcorn 200-series (eg. 192.168.1.100)</span> - </label> - </div> + </fieldset> + </div><!-- /pushover component-group //--> + <div class="component-group clearfix"> + <div class="component-group-desc"> + <h3><a href="http://boxcar.io/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/boxcar.gif" alt="" title="Boxcar" width="16" height="16" /> Boxcar </a></h3> + <p>Read your messages where and when you want them! A subscription will be send if needed.</p> + </div> + <fieldset class="component-group-list"> <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">Get Settings</span> - <input type="button" value="Get Settings" id="settingsNMJ" /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">The Popcorn Hour device must be powered on and NMJ running.</span> - </label> - </div> + <input type="checkbox" class="enabler" name="use_boxcar" id="use_boxcar" #if $sickbeard.USE_BOXCAR then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_boxcar"> + <span class="component-title">Enable</span> + <span class="component-desc">Should Sick Beard send notifications through Boxcar?</span> + </label> + </div> + + <div id="content_use_boxcar"> + <div class="field-pair"> + <input type="checkbox" name="boxcar_notify_onsnatch" id="boxcar_notify_onsnatch" #if $sickbeard.BOXCAR_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="boxcar_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="boxcar_notify_ondownload" id="boxcar_notify_ondownload" #if $sickbeard.BOXCAR_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="boxcar_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Boxcar Username</span> + <input type="text" name="boxcar_username" id="boxcar_username" value="$sickbeard.BOXCAR_USERNAME" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Username of your Boxcar account</span> + </label> + </div> + <div class="testNotification" id="testBoxcar-result">Click below to test.</div> + <input type="button" value="Test Boxcar" id="testBoxcar" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_boxcar //--> + + </fieldset> + </div><!-- /boxcar component-group //--> - <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">NMJ Database</span> - <input type="text" name="nmj_database" id="nmj_database" value="$sickbeard.NMJ_DATABASE" size="35" #if $sickbeard.NMJ_DATABASE then "readonly=\"readonly\"" else ""# /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Automatically filled via the 'Get Settings' button.</span> - </label> - </div> + <div class="component-group clearfix"> + <div class="component-group-desc"> + <h3><a href="http://nma.usk.bz" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/nma.jpg" alt="" title="NMA" width="16" height="16" /> Notify My Android </a></h3> + <p>Notify My Android is a Prowl-like Android App and API that offers an easy way to send notifications from your application directly to your Android device.</p> + </div> + <fieldset class="component-group-list"> <div class="field-pair"> - <label class="nocheck clearfix"> - <span class="component-title">NMJ Mount URL</span> - <input type="text" name="nmj_mount" id="nmj_mount" value="$sickbeard.NMJ_MOUNT" size="35" #if $sickbeard.NMJ_MOUNT then "readonly=\"readonly\"" else ""# /> - </label> - <label class="nocheck clearfix"> - <span class="component-title"> </span> - <span class="component-desc">Automatically filled via the 'Get Settings' button.</span> - </label> - </div> + <input type="checkbox" class="enabler" name="use_nma" id="use_nma" #if $sickbeard.USE_NMA then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_nma"> + <span class="component-title">Enable</span> + <span class="component-desc">Should Sick Beard send NMA notifications?</span> + </label> + </div> + + <div id="content_use_nma"> + <div class="field-pair"> + <input type="checkbox" name="nma_notify_onsnatch" id="nma_notify_onsnatch" #if $sickbeard.NMA_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="nma_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="nma_notify_ondownload" id="nma_notify_ondownload" #if $sickbeard.NMA_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="nma_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">NMA API key:</span> + <input type="text" name="nma_api" id="nma_api" value="$sickbeard.NMA_API" size="55" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Multiple keys must be seperated by a , (comma). Up to a maximum of 5</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">NMA priority:</span> + <select id="nma_priority" name="nma_priority"> + <option value="-2" #if $sickbeard.NMA_PRIORITY == "-2" then 'selected="selected"' else ""#>Very Low</option> + <option value="-1" #if $sickbeard.NMA_PRIORITY == "-1" then 'selected="selected"' else ""#>Moderate</option> + <option value="0" #if $sickbeard.NMA_PRIORITY == "0" then 'selected="selected"' else ""#>Normal</option> + <option value="1" #if $sickbeard.NMA_PRIORITY == "1" then 'selected="selected"' else ""#>High</option> + <option value="2" #if $sickbeard.NMA_PRIORITY == "2" then 'selected="selected"' else ""#>Emergency</option> + </select> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Priority of NMA messages from Sick-Beard.</span> + </label> + </div> + <div class="testNotification" id="testNMA-result">Click below to test.</div> + <input type="button" value="Test NMA" id="testNMA" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_nma //--> - <div class="testNotification" id="testNMJ-result">Click below to test.</div> - <input type="button" value="Test NMJ" id="testNMJ" /> - <input type="submit" class="config_submitter" value="Save Changes" /> - </div><!-- /content_use_nmj //--> </fieldset> - </div><!-- /component-group //--> + </div><!-- /nma component-group //--> + - <div id="core-component-group9" class="component-group clearfix"> + <br /> + <h1>Online</h1> + <br /> + + + <div class="component-group clearfix"> <div class="component-group-desc"> - <h3><a href="http://synology.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/synoindex.gif" alt="Synology Indexer" title="Synology Indexer" width="16" height="16" /> Synology Indexer</a></h3> - <p>Synology Indexer is the daemon running on the Synology NAS to build its media database.</p> + <h3><a href="http://www.twitter.com/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/twitter.gif" alt="" title="Twitter" width="16" height="16" /> Twitter </a></h3> + <p>A social networking and microblogging service, enabling its users to send and read other users' messages called tweets.</p> </div> - <fieldset class="component-group-list"> <div class="field-pair"> - <input type="checkbox" name="use_synoindex" id="use_synoindex" #if $sickbeard.USE_SYNOINDEX then "checked=\"checked\"" else ""# /> - <label class="clearfix" for="use_synoindex"> + <input type="checkbox" class="enabler" name="use_twitter" id="use_twitter" #if $sickbeard.USE_TWITTER then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_twitter"> <span class="component-title">Enable</span> - <span class="component-desc">Should Sick Beard send notifications to the synoindex daemon?<br /><br /> - </span> + <span class="component-desc">Should Sick Beard post tweets on Twitter?</span> </label> - <label class="nocheck clearfix" for="use_synoindex"> + <label class="nocheck clearfix" for="use_twitter"> <span class="component-title"> </span> - <span class="component-desc">Note: Requires SB to be running on your Synology NAS.</span> + <span class="component-desc">You may want to use a second account.</span> </label> </div> - <input type="submit" class="config_submitter" value="Save Changes" /> + + <div id="content_use_twitter"> + <div class="field-pair"> + <input type="checkbox" name="twitter_notify_onsnatch" id="twitter_notify_onsnatch" #if $sickbeard.TWITTER_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="twitter_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="twitter_notify_ondownload" id="twitter_notify_ondownload" #if $sickbeard.TWITTER_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="twitter_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="clearfix"> + <span class="component-title">Step One</span> + </label> + <label class="nocheck clearfix"> + <span class="component-desc">Click the "Request Authorization" button.<br/> This will open a new page containing an auth key.<br/> Note: if nothing happens check your popup blocker.<br/></span> + <input type="button" value="Request Authorization" id="twitterStep1" /> + </label> + </div> + <div class="field-pair"> + <label class="clearfix"> + <span class="component-title">Step Two</span> + </label> + <label class="nocheck clearfix"> + <span class="component-desc">Enter the key Twitter gave you below, and click "Verify Key".<br/></span> + <input type="text" id="twitter_key" value="" size="35" /><br /> + </label> + <label class="nocheck clearfix"> + <input type="button" value="Verify Key" id="twitterStep2" /> + </label> + </div> + <div class="field-pair"> + <label class="clearfix"> + <span class="component-title">Step Three</span> + </label> + </div> + <div class="testNotification" id="testTwitter-result">Click below to test.</div> + <input type="button" value="Test Twitter" id="testTwitter" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_twitter //--> + </fieldset> - </div><!-- /component-group //--> + </div><!-- /twitter component-group //--> - <br/><input type="submit" class="config_submitter" value="Save Changes" /><br/> - </div><!-- /config-components //--> + <div class="component-group clearfix"> + <div class="component-group-desc"> + <h3><a href="http://trakt.tv/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/trakt.gif" alt="" title="Trakt" width="16" height="16" /> Trakt </a></h3> + <p>trakt helps keep a record of what TV shows and movies you are watching. Based on your favorites, trakt recommends additional shows and movies you'll enjoy!</p> + </div> + <fieldset class="component-group-list"> + <div class="field-pair"> + <input type="checkbox" class="enabler" name="use_trakt" id="use_trakt" #if $sickbeard.USE_TRAKT then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_trakt"> + <span class="component-title">Enable</span> + <span class="component-desc">Should Sick Beard send Trakt.tv notifications?</span> + </label> + </div> + + <div id="content_use_trakt"> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Trakt Username</span> + <input type="text" name="trakt_username" id="trakt_username" value="$sickbeard.TRAKT_USERNAME" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Username of your Trakt account.</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Trakt Password</span> + <input type="password" name="trakt_password" id="trakt_password" value="$sickbeard.TRAKT_PASSWORD" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Password of your Trakt account.</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title">Trakt API key:</span> + <input type="text" name="trakt_api" id="trakt_api" value="$sickbeard.TRAKT_API" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">Get your key at: <a href="http://trakt.tv/settings/api" onclick="window.open(this.href, '_blank'); return false;">http://trakt.tv/settings/api</a></span> + </label> + </div> + <div class="testNotification" id="testTrakt-result">Click below to test.</div> + <input type="button" value="Test Trakt" id="testTrakt" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_trakt //--> -</form> + </fieldset> + </div><!-- /trakt component-group //--> -</div></div> + <br/><input type="submit" class="config_submitter" value="Save Changes" /><br/> + </div><!-- /config-components //--> + </form> + </div> +</div> <div class="clearfix"></div> #include $os.path.join($sickbeard.PROG_DIR, "data/interfaces/default/inc_bottom.tmpl") diff --git a/data/interfaces/default/config_providers.tmpl b/data/interfaces/default/config_providers.tmpl old mode 100644 new mode 100755 index 5054118aa2a915b7527272784c500364b9210034..50b810a661bbf2f6cf71a2f077968bc3b28043c3 --- a/data/interfaces/default/config_providers.tmpl +++ b/data/interfaces/default/config_providers.tmpl @@ -77,7 +77,7 @@ var show_nzb_providers = #if $sickbeard.USE_NZBS then "true" else "false"#; <span class="component-title jumbo">Configure Provider:</span> <span class="component-desc"> #set $provider_config_list = [] - #for $cur_provider in ("nzbs_org", "nzbs_r_us", "newzbin", "nzbmatrix", "tvtorrents"): + #for $cur_provider in ("nzbs_r_us", "newzbin", "nzbmatrix", "tvtorrents", "btn"): #set $cur_provider_obj = $sickbeard.providers.getProviderClass($cur_provider) #if $cur_provider_obj.providerType == $GenericProvider.NZB and not $sickbeard.USE_NZBS: #continue @@ -119,7 +119,7 @@ var show_nzb_providers = #if $sickbeard.USE_NZBS then "true" else "false"#; </div> #end for - +<!-- <div class="providerDiv" id="nzbs_orgDiv"> <div class="field-pair"> <label class="clearfix"> @@ -134,7 +134,7 @@ var show_nzb_providers = #if $sickbeard.USE_NZBS then "true" else "false"#; </label> </div> </div> - +--> <div class="providerDiv" id="nzbmatrixDiv"> <div class="field-pair"> <label class="clearfix"> @@ -195,6 +195,33 @@ var show_nzb_providers = #if $sickbeard.USE_NZBS then "true" else "false"#; </div> </div> +<div class="providerDiv" id="btnDiv"> + <div class="field-pair"> + <label class="clearfix"> + <span class="component-title">BTN User ID:</span> + <input class="component-desc" type="text" name="btn_user_id" value="$sickbeard.BTN_USER_ID" /> + </label> + </div> + <div class="field-pair"> + <label class="clearfix"> + <span class="component-title">BTN Auth Token:</span> + <input class="component-desc" type="text" name="btn_auth_token" value="$sickbeard.BTN_AUTH_TOKEN" size="32" /> + </label> + </div> + <div class="field-pair"> + <label class="clearfix"> + <span class="component-title">BTN Passkey:</span> + <input class="component-desc" type="text" name="btn_passkey" value="$sickbeard.BTN_PASSKEY" size="32" /> + </label> + </div> + <div class="field-pair"> + <label class="clearfix"> + <span class="component-title">BTN Authkey:</span> + <input class="component-desc" type="text" name="btn_authkey" value="$sickbeard.BTN_AUTHKEY" size="32" /> + </label> + </div> +</div> + <!-- end div for editing providers --> <input type="submit" class="config_submitter" value="Save Changes" /><br/> diff --git a/data/interfaces/default/config_search.tmpl b/data/interfaces/default/config_search.tmpl index 600b29f1440e9154accff420629b793f4cb9d4fa..1c6c9963008e76ee4926a68d6eb679cb158c34bd 100644 --- a/data/interfaces/default/config_search.tmpl +++ b/data/interfaces/default/config_search.tmpl @@ -214,6 +214,9 @@ </div> <div class="clearfix"></div> + + <div class="testNotification" id="testSABnzbd-result">Click below to test.</div> + <input type="button" value="Test SABnzbd" id="testSABnzbd" class="test-button"/> <input type="submit" class="config_submitter" value="Save Changes" /><br/> </div><!-- /content_use_nzbs //--> diff --git a/data/interfaces/default/displayShow.tmpl b/data/interfaces/default/displayShow.tmpl index d7c3dc6aa7e29820363e62df509c9268afdd4e92..a1b5649076bf2188c609bbe0f1e5e6a9f9de56d9 100644 --- a/data/interfaces/default/displayShow.tmpl +++ b/data/interfaces/default/displayShow.tmpl @@ -83,9 +83,9 @@ replace with: <b><%=", ".join([Quality.qualityStrings[x] for x in bestQualities] #end if #end if </td></tr> - <tr><td class="showLegend">Language:</td><td>$show.lang</td></tr> + <tr><td class="showLegend">Language:</td><td><img src="$sbRoot/images/flags/${show.lang}.png" width="16" height="11" alt="" /> $show.lang</td></tr> <tr><td class="showLegend">Season Folders: </td><td><img src="$sbRoot/images/#if $show.seasonfolders == 1 then "yes16.png\" alt=\"Y" else "no16.png\" alt=\"N"#" width="16" height="16" /></td></tr> - <tr><td class="showLegend">Active: </td><td><img src="$sbRoot/images/#if int($show.paused) == 0 then "yes16.png\" alt=\"Y" else "no16.png\" alt=\"N"#" width="16" height="16" /></td></tr> + <tr><td class="showLegend">Paused: </td><td><img src="$sbRoot/images/#if int($show.paused) == 1 then "yes16.png\" alt=\"Y" else "no16.png\" alt=\"N"#" width="16" height="16" /></td></tr> <tr><td class="showLegend">Air-by-Date: </td><td><img src="$sbRoot/images/#if int($show.air_by_date) == 1 then "yes16.png\" alt=\"Y" else "no16.png\" alt=\"N"#" width="16" height="16" /></td></tr> </table> </div> @@ -148,12 +148,12 @@ Change selected episodes to <td align="center"><img src="$sbRoot/images/#if $epResult["hastbn"] == 1 then "tbn.gif\" alt=\"Y" else "tbn-no.gif\" alt=\"N"#" width="23" height="11" /></td> <td align="center">$epResult["episode"]</td> <td> - $epResult["name"] - #if $epResult["description"] != "" and $epResult["description"] != None: - <img src="$sbRoot/images/info32.png" height="16" class="plotInfo" alt="" id="plot_info_$show.tvdbid<%="_"+str(epResult["season"])+"_"+str(epResult["episode"])%>" /> - #end if + $epResult["name"] + #if $epResult["description"] != "" and $epResult["description"] != None: + <img src="$sbRoot/images/info32.png" height="16" class="plotInfo" alt="" id="plot_info_$show.tvdbid<%="_"+str(epResult["season"])+"_"+str(epResult["episode"])%>" /> + #end if </td> - <td align="center">#if int($epResult["airdate"]) == 1 then "never" else $datetime.date.fromordinal(int($epResult["airdate"]))#</td> + <td align="center" class="nowrap">#if int($epResult["airdate"]) == 1 then "never" else $datetime.date.fromordinal(int($epResult["airdate"]))#</td> <td> #if $epLoc and $show._location and $epLoc.lower().startswith($show._location.lower()): $epLoc[len($show._location)+1:] diff --git a/data/interfaces/default/editShow.tmpl b/data/interfaces/default/editShow.tmpl index f9ccdc245937fa4a75dc1c76f710267df92a184d..dea417faf93467df2049b0d28a0acc91b9b09d3f 100644 --- a/data/interfaces/default/editShow.tmpl +++ b/data/interfaces/default/editShow.tmpl @@ -9,6 +9,7 @@ #set global $topmenu="home"# #import os.path #include $os.path.join($sickbeard.PROG_DIR, "data/interfaces/default/inc_top.tmpl") + <script type="text/javascript" charset="utf-8"> <!-- \$(document).ready(function(){ @@ -17,21 +18,26 @@ var resultStr = ''; if (data.results.length == 0) { - resultStr = '<option value="$show.lang" selected="selected">$show.lang</option>'; + flag = ' class="flag" style="background-image:url($sbRoot/images/flags/${show.lang}.png)"'; + resultStr = '<option value="$show.lang" selected="selected" + flag>$show.lang</option>'; } else { var current_lang_added = false; \$.each(data.results, function(index, obj){ + if (obj == "$show.lang") { selected = ' selected="selected"'; current_lang_added = true; } - else + else { selected = ''; + } - resultStr += '<option value="' + obj + '"' + selected + '>' + obj + '</option>'; + flag = ' class="flag" style="background-image:url($sbRoot/images/flags/' + obj + '.png);"'; + resultStr += '<option value="' + obj + '"' + selected + flag + '>' + obj + '</option>'; }); if (!current_lang_added) resultStr += '<option value="$show.lang" selected="selected">$show.lang</option>'; + } \$('#tvdbLangSelect').html(resultStr) @@ -62,9 +68,9 @@ This <b>DOES NOT</b> allow Sick Beard to download non-english TV episodes!<br /> Use Season Folders: <input type="checkbox" name="seasonfolders" #if $show.seasonfolders == 1 then "checked=\"checked\"" else ""# /><br /><br /> Paused: <input type="checkbox" name="paused" #if $show.paused == 1 then "checked=\"checked\"" else ""# /><br /><br /> -Air by date: +Air by date: <input type="checkbox" name="air_by_date" #if $show.air_by_date == 1 then "checked=\"checked\"" else ""# /><br /> -(check this if the show is released as Show.03.02.2010 rather than Show.S02E03) +(check this if the show is released as Show.03.02.2010 rather than Show.S02E03) <br /><br /> <input type="submit" value="Submit" /> </form> diff --git a/data/interfaces/default/history.tmpl b/data/interfaces/default/history.tmpl index 63b5ef19e96e8ba51e8234a97927950c337c0259..de073c784b25a00c8668e91e82dfe6a4c1013042 100644 --- a/data/interfaces/default/history.tmpl +++ b/data/interfaces/default/history.tmpl @@ -18,20 +18,36 @@ \$(document).ready(function() { \$("#historyTable:has(tbody tr)").tablesorter({ - widgets: ['zebra'], - sortList: [[0,1]] - }); + widgets: ['zebra', 'stickyHeaders', 'filter'], + sortList: [[0,1]], + textExtraction: { + 4: function(node) { return \$(node).find("span").text().toLowerCase(); } + } + }); + \$('#limit').change(function(){ + url = '$sbRoot/history/?limit='+\$(this).val() + window.location.href = url + }); }); //--> </script> +<div class="h2footer align-right"><b>Limit:</b> + <select name="limit" id="limit"> + <option value="100" #if $limit == "100" then "selected=\"selected\"" else ""#>100</option> + <option value="250" #if $limit == "250" then "selected=\"selected\"" else ""#>250</option> + <option value="500" #if $limit == "500" then "selected=\"selected\"" else ""#>500</option> + <option value="0" #if $limit == "0" then "selected=\"selected\"" else ""#>All</option> + </select> +</div><br/> + <table id="historyTable" class="sickbeardTable tablesorter" cellspacing="1" border="0" cellpadding="0"> <thead><tr><th class="nowrap">Time</th><th>Episode</th><th>Action</th><th>Provider</th><th>Quality</th></tr></thead> <tbody> #for $hItem in $historyResults: #set $curStatus, $curQuality = $Quality.splitCompositeStatus(int($hItem["action"])) <tr> - <td>$datetime.datetime.strptime(str($hItem["date"]), $history.dateFormat)</td> + <td class="nowrap">$datetime.datetime.strptime(str($hItem["date"]), $history.dateFormat)</td> <td><a href="$sbRoot/home/displayShow?show=$hItem["showid"]#season-$hItem["season"]">$hItem["show_name"] - <%=str(hItem["season"]) +"x"+ "%02i" % int(hItem["episode"]) %></a></td> <td align="center">$statusStrings[$curStatus]</td> <td align="center"> @@ -56,7 +72,7 @@ #end if #end if </td> - <td align="center">$Quality.qualityStrings[$curQuality]</td> + <td align="center"><span class="quality $Quality.qualityStrings[$curQuality]">$Quality.qualityStrings[$curQuality]</span></td> </tr> #end for </tbody> diff --git a/data/interfaces/default/home.tmpl b/data/interfaces/default/home.tmpl index e2ec818c274b3f727edaa7b8e89f4d05edcf79b3..98e14045397c04991917d2dbda7882304b7b8a33 100644 --- a/data/interfaces/default/home.tmpl +++ b/data/interfaces/default/home.tmpl @@ -19,34 +19,16 @@ <script type="text/javascript" charset="utf-8"> <!-- -\$.tablesorter.addParser({ - id: 'nextAirDate', - is: function(s) { - return false; - }, - format: function(s) { - if (s == '') - return '9999-99-99'; - else - return s; - }, - type: 'text' -}); \$.tablesorter.addParser({ id: 'loadingNames', is: function(s) { return false; - }, - format: function(s) { + }, + format: function(s) { if (s.indexOf('Loading...') == 0) - return s.replace('Loading...','!!!'); - else if (s.indexOf('The ') == 0) - return s.replace('The ', '') - else if (s.indexOf('A ') == 0) - return s.replace('A ', '') - else - return s; + return s.replace('Loading...','000'); + return (s || '').replace(/^(The|A)\s/i,''); }, type: 'text' }); @@ -57,7 +39,7 @@ return false; }, format: function(s) { - return s.toLowerCase().replace('hd',3).replace('sd',1).replace('any',0).replace('best',2).replace('custom',4); + return s.replace('hd',3).replace('sd',1).replace('any',0).replace('best',2).replace('custom',4); }, type: 'numeric' }); @@ -68,7 +50,7 @@ return false; }, format: function(s) { - match = s.match(/^\<\!\-\-(.*)\-\-\>/) + match = s.match(/^(.*)/); if (match == null || match[1] == "?") return -10; @@ -84,54 +66,21 @@ type: 'numeric' }); -\$.tablesorter.addParser({ - id: 'active', - is: function(s) { - return false; - }, - format: function(s) { - if (s == '') - return '~~'; - else - return s; - }, - type: 'text' -}); - -//http://web.archive.org/web/20080801073104/http://www.jdempster.com/category/code/jquery/tablesortercookiewidget/ -\$.tablesorter.addWidget({ - id: 'cookie', - format: function(table) { - var sortList = table.config.sortList; - var tablesorterCookieJar = \$.cookieJar('tablesorter'); - if ( sortList.length > 0) { - tablesorterCookieJar.set(\$(table).attr('id'), sortList); - } else { - var sortList = tablesorterCookieJar.get(\$(table).attr('id')); - if (sortList && sortList.length > 0) { - jQuery(table).trigger('sorton', [sortList]); - } - } - } -}); - \$(document).ready(function(){ - // workaround: the tablesorter cookie widget does not support a defaulted sortList set within the $.tablesorter() instantiation - var tablesorterCookieJar = \$.cookieJar('tablesorter'); - var sortList = tablesorterCookieJar.get('showListTable'); - if (!sortList || !sortList.length) - sortList = [[5,1],[1,0]]; - - \$("#showListTable").tablesorter({ - sortList: sortList, - widgets: ['cookie','zebra'], + \$("#showListTable:has(tbody tr)").tablesorter({ + sortList: [[5,1],[1,0]], + textExtraction: { + 3: function(node) { return \$(node).find("span").text().toLowerCase(); }, + 4: function(node) { return \$(node).find("span").text(); }, + 5: function(node) { return \$(node).find("img").attr("alt"); } + }, + widgets: ['saveSort', 'zebra', 'stickyHeaders'], headers: { - 0: { sorter: 'nextAirDate' }, + 0: { sorter: 'isoDate' }, 1: { sorter: 'loadingNames' }, 3: { sorter: 'quality' }, - 4: { sorter: 'eps' }, - 5: { sorter: 'active' } + 4: { sorter: 'eps' } } }); @@ -196,8 +145,9 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name)) #set $den = 1 #end if + <tr> - <td align="center">#if len($curEp) != 0 then $curEp[0].airdate else ""#</td> + <td align="center" class="nowrap">#if len($curEp) != 0 then $curEp[0].airdate else ""#</td> <td class="tvShow"><a href="$sbRoot/home/displayShow?show=$curShow.tvdbid">$curShow.name</a></td> <td>$curShow.network</td> #if $curShow.quality in $qualityPresets: @@ -205,7 +155,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name)) #else: <td align="center"><span class="quality Custom">Custom</span></td> #end if - <td align="center"><!--$dlStat--><div id="progressbar$curShow.tvdbid" style="position:relative;"></div> + <td align="center"><span style="display: none;">$dlStat</span><div id="progressbar$curShow.tvdbid" style="position:relative;"></div> <script type="text/javascript"> <!-- \$(function() { diff --git a/data/interfaces/default/inc_qualityChooser.tmpl b/data/interfaces/default/inc_qualityChooser.tmpl index a1ef1589be73119c868424fce9613d5f2845fcf0..a4be61632ed322128445b56df2756acae9cdfd32 100644 --- a/data/interfaces/default/inc_qualityChooser.tmpl +++ b/data/interfaces/default/inc_qualityChooser.tmpl @@ -25,11 +25,11 @@ <div id="customQuality"> <div class="component-group-desc"> - <p>One of the <b>Inital</b> quality selections must be obtained before Sick Beard will attempt to process the <b>Archive</b> selections.</p> + <p>One of the <b>Initial</b> quality selections must be obtained before Sick Beard will attempt to process the <b>Archive</b> selections.</p> </div> <div class="float-left" style="margin-left: 50px;"> -<h3 style="text-align: center;">Inital</h3> +<h3 style="text-align: center;">Initial</h3> #set $anyQualityList = filter(lambda x: x > $Quality.NONE, $Quality.qualityStrings) <select id="anyQualities" name="anyQualities" multiple="multiple" size="$len($anyQualityList)"> #for $curQuality in sorted($anyQualityList): diff --git a/data/interfaces/default/inc_top.tmpl b/data/interfaces/default/inc_top.tmpl index 5ba87f6b7c6d4ff07bdd1975d84451e074eb310d..51ae9fb95d5014dbd71799de367a1469bbef7248 100644 --- a/data/interfaces/default/inc_top.tmpl +++ b/data/interfaces/default/inc_top.tmpl @@ -15,9 +15,10 @@ <link rel="stylesheet" type="text/css" href="$sbRoot/css/comingEpisodes.css" /> <link rel="stylesheet" type="text/css" href="$sbRoot/css/config.css" /> <link rel="stylesheet" type="text/css" href="$sbRoot/css/jquery.pnotify.default.css" /> - <link rel="stylesheet" type="text/css" href="$sbRoot/css/smooth-grinder/jquery-ui-1.8.13.custom.css" /> + <link rel="stylesheet" type="text/css" href="$sbRoot/css/smooth-grinder/jquery-ui-1.8.17.custom.css" /> <link rel="stylesheet" type="text/css" href="$sbRoot/css/superfish.css" /> <link rel="stylesheet" type="text/css" href="$sbRoot/css/tablesorter.css"/> + <link rel="stylesheet" type="text/css" href="$sbRoot/css/jquery.qtip2.css"/> <link rel="stylesheet" type="text/css" media="only screen and (max-device-width: 480px)" href="$sbRoot/css/iphone.css" /> <style type="text/css"> @@ -26,9 +27,9 @@ .sf-sub-indicator { background: url("$sbRoot/images/arrows.png") no-repeat -10px -100px; } .sf-shadow ul { background: url("$sbRoot/images/shadow.png") no-repeat bottom right; } -table.tablesorter thead tr .header { background-image: url("$sbRoot/images/tablesorter/bg.gif"); } -table.tablesorter thead tr .headerSortUp { background-image: url("$sbRoot/images/tablesorter/asc.gif"); } -table.tablesorter thead tr .headerSortDown { background-image: url("$sbRoot/images/tablesorter/desc.gif"); } +th.tablesorter-header { background-image: url("$sbRoot/images/tablesorter/bg.gif"); } +th.tablesorter-headerSortUp { background-image: url("$sbRoot/images/tablesorter/asc.gif"); } +th.tablesorter-headerSortDown { background-image: url("$sbRoot/images/tablesorter/desc.gif"); } .ui-autocomplete-loading { background: white url("$sbRoot/images/loading16.gif") right center no-repeat; } .browserDialog.busy .ui-dialog-buttonpane { background: url("$sbRoot/images/loading.gif") 10px 50% no-repeat !important; } @@ -55,23 +56,28 @@ table.tablesorter thead tr .headerSortDown { background-image: url("$sbRoot/imag .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url("$sbRoot/css/smooth-grinder/images/ui-icons_cd0a0a_256x240.png"); } .ui-widget-overlay { background: #aaaaaa url("$sbRoot/css/smooth-grinder/images/ui-bg_flat_0_000000_40x100.png") 50% 50% repeat; opacity: .35;filter:Alpha(Opacity=35); } -.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000 url("$sbRoot/css/smooth-grinder/images/ui-bg_flat_0_000000_40x100.png") 50% 50% repeat-x; opacity: .35;filter:Alpha(Opacity=35); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000 url("$sbRoot/css/smooth-grinder/images/ui-bg_flat_0_000000_40x100.png") 50% 50% repeat-x; opacity: .35;filter:Alpha(Opacity=35); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } + +#if $sickbeard.NEWEST_VERSION_STRING: +.ui-pnotify { top: 30px !important; } +#end if //--> </style> - <script type="text/javascript" src="$sbRoot/js/jquery-1.6.1.min.js"></script> - <script type="text/javascript" src="$sbRoot/js/jquery-ui-1.8.13.custom.min.js"></script> + <script type="text/javascript" src="$sbRoot/js/jquery-1.7.1.min.js"></script> + <script type="text/javascript" src="$sbRoot/js/jquery-ui-1.8.17.custom.min.js"></script> <script type="text/javascript" src="$sbRoot/js/superfish-1.4.8.js"></script> <script type="text/javascript" src="$sbRoot/js/supersubs-0.2b.js"></script> <script type="text/javascript" src="$sbRoot/js/jquery.cookie.js"></script> <script type="text/javascript" src="$sbRoot/js/jquery.cookiejar.js"></script> <script type="text/javascript" src="$sbRoot/js/jquery.json-2.2.min.js"></script> <script type="text/javascript" src="$sbRoot/js/jquery.selectboxes.min.js"></script> - <script type="text/javascript" src="$sbRoot/js/jquery.tablesorter-2.0.3.min.js"></script> - <script type="text/javascript" src="$sbRoot/js/tools.tooltip-1.2.5.min.js"></script> - <script type="text/javascript" src="$sbRoot/js/jquery.pnotify-1.0.1.min.js"></script> + <script type="text/javascript" src="$sbRoot/js/jquery.tablesorter-2.1.10.min.js"></script> + <script type="text/javascript" src="$sbRoot/js/jquery.tablesorter.widgets.min.js"></script> + <script type="text/javascript" src="$sbRoot/js/jquery.qtip-2011-11-14.min.js"></script> + <script type="text/javascript" src="$sbRoot/js/jquery.pnotify-1.0.2.min.js"></script> <script type="text/javascript" src="$sbRoot/js/jquery.expand-1.3.8.js"></script> - <script type="text/javascript" src="$sbRoot/js/jquery.form-2.69.js"></script> + <script type="text/javascript" src="$sbRoot/js/jquery.form-2.92.js"></script> <script type="text/javascript" charset="utf-8"> <!-- @@ -121,11 +127,11 @@ table.tablesorter thead tr .headerSortDown { background-image: url("$sbRoot/imag \$("#NAV$topmenu").addClass("current"); \$("a.confirm").bind("click",function(e) { + \$('#MainMenu.sf-menu').hideSuperfishUl(); e.preventDefault(); var target = \$( this ).attr('href'); - if ( confirm("Are you sure you want to " + \$(this).prop('text') + "?") ) + if ( confirm("Are you sure you want to " + \$(this).text() + "?") ) location.href = target; - \$('#MainMenu.sf-menu').hideSuperfishUl(); return false; }); @@ -149,30 +155,33 @@ table.tablesorter thead tr .headerSortDown { background-image: url("$sbRoot/imag <span id="versiontext">alpha $sickbeard.version.SICKBEARD_VERSION</span> </div> <ul id="MainMenu" class="sf-menu"> - <li id="NAVsystem" class="first"><a href="#" class="navIcon"><img src="$sbRoot/images/menu/system18.png" alt="" width="18" height="18" /></a> + <li id="NAVsystem" class="first"><a href="#" class="navIcon" onclick="return false;"><img src="$sbRoot/images/menu/system18.png" alt="" width="18" height="18" /></a> <ul> <li><a href="$sbRoot/manage/manageSearches/forceVersionCheck"><img src="$sbRoot/images/menu/update16.png" alt="" width="16" height="16" />Force Version Check</a></li> <li><a href="$sbRoot/home/restart/?pid=$sbPID" class="confirm"><img src="$sbRoot/images/menu/restart16.png" alt="" width="16" height="16" />Restart</a></li> <li><a href="$sbRoot/home/shutdown/" class="confirm"><img src="$sbRoot/images/menu/shutdown16.png" alt="" width="16" height="16" />Shutdown</a></li> </ul> </li> - <li id="NAVhome"><a href="$sbRoot/home">Home</a> + <li id="NAVhome"><a href="$sbRoot/home/">Home</a> <ul> + <li><a href="$sbRoot/home/"><img src="$sbRoot/images/menu/home16.png" alt="" width="16" height="16" />Home</a></li> <li><a href="$sbRoot/home/addShows/"><img src="$sbRoot/images/menu/addshow16.png" alt="" width="16" height="16" />Add Shows</a></li> <li><a href="$sbRoot/home/postprocess/"><img src="$sbRoot/images/menu/postprocess16.png" alt="" width="16" height="16" />Manual Post-Processing</a></li> </ul> </li> - <li id="NAVcomingEpisodes"><a href="$sbRoot/comingEpisodes">Coming Episodes</a></li> - <li id="NAVhistory"><a href="$sbRoot/history">History</a></li> - <li id="NAVmanage"><a href="$sbRoot/manage">Manage</a> + <li id="NAVcomingEpisodes"><a href="$sbRoot/comingEpisodes/">Coming Episodes</a></li> + <li id="NAVhistory"><a href="$sbRoot/history/">History</a></li> + <li id="NAVmanage"><a href="$sbRoot/manage/">Manage</a> <ul> - <li><a href="$sbRoot/manage/backlogOverview"><img src="$sbRoot/images/menu/backlog16.png" alt="" width="16" height="16" />Backlog Overview</a></li> - <li><a href="$sbRoot/manage/manageSearches"><img src="$sbRoot/images/menu/managesearches16.png" alt="" width="16" height="16" />Manage Searches</a></li> - <li><a href="$sbRoot/manage/episodeStatuses"><img src="$sbRoot/images/menu/backlog16.png" alt="" width="16" height="16" />Episode Status Management</a></li> + <li><a href="$sbRoot/manage/"><img src="$sbRoot/images/menu/manage16.png" alt="" width="16" height="16" />Mass Update</a></li> + <li><a href="$sbRoot/manage/backlogOverview/"><img src="$sbRoot/images/menu/backlog_view16.png" alt="" width="16" height="16" />Backlog Overview</a></li> + <li><a href="$sbRoot/manage/manageSearches/"><img src="$sbRoot/images/menu/managesearches16.png" alt="" width="16" height="16" />Manage Searches</a></li> + <li><a href="$sbRoot/manage/episodeStatuses/"><img src="$sbRoot/images/menu/backlog16.png" alt="" width="16" height="16" />Episode Status Management</a></li> </ul> </li> - <li id="NAVconfig"><a href="$sbRoot/config">Config</a> + <li id="NAVconfig"><a href="$sbRoot/config/">Config</a> <ul> + <li><a href="$sbRoot/config/"><img src="$sbRoot/images/menu/config_index16.png" alt="" width="16" height="16" />Help & Info</a></li> <li><a href="$sbRoot/config/general/"><img src="$sbRoot/images/menu/config16.png" alt="" width="16" height="16" />General</a></li> <li><a href="$sbRoot/config/search/"><img src="$sbRoot/images/menu/config16.png" alt="" width="16" height="16" />Search Settings</a></li> <li><a href="$sbRoot/config/providers/"><img src="$sbRoot/images/menu/config16.png" alt="" width="16" height="16" />Search Providers</a></li> @@ -180,9 +189,10 @@ table.tablesorter thead tr .headerSortDown { background-image: url("$sbRoot/imag <li><a href="$sbRoot/config/notifications/"><img src="$sbRoot/images/menu/config16.png" alt="" width="16" height="16" />Notifications</a></li> </ul> </li> - <li id="NAVerrorlogs"><a href="$sbRoot/errorlogs">$logPageTitle</a> + <li id="NAVerrorlogs"><a href="$sbRoot/errorlogs/">$logPageTitle</a> <ul> - <li><a href="$sbRoot/errorlogs/viewlog"><img src="$sbRoot/images/menu/viewlog16.png" alt="" width="16" height="16" />View Log</a></li> + <li><a href="$sbRoot/errorlogs/"><img src="$sbRoot/images/menu/viewlog_errors16.png" alt="" width="16" height="16" />View Log (Errors)</a></li> + <li><a href="$sbRoot/errorlogs/viewlog/"><img src="$sbRoot/images/menu/viewlog16.png" alt="" width="16" height="16" />View Log</a></li> </ul> </li> <li id="donate"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JA8M7VDY89SQ4" onclick="window.open(this.href); return false;"><img src="$sbRoot/images/paypal/btn_donate_LG.gif" alt="[donate]" /></a></li> @@ -214,4 +224,4 @@ table.tablesorter thead tr .headerSortDown { background-image: url("$sbRoot/imag <div id="contentWrapper"> <div id="content"> -<h1>#if $varExists('header') then $header else $title#</h1> +<h1 class="title">#if $varExists('header') then $header else $title#</h1> diff --git a/data/interfaces/default/manage.tmpl b/data/interfaces/default/manage.tmpl index 6e940a9c5acb67f3235109bcc0eadcc85c1e6c1f..13277862fcac5a36d91aacb278911b30733a0aa3 100644 --- a/data/interfaces/default/manage.tmpl +++ b/data/interfaces/default/manage.tmpl @@ -14,46 +14,42 @@ id: 'showNames', is: function(s) { return false; - }, - format: function(s) { - if (s.indexOf('The ') == 0) - return s.replace('The ', '') - else if (s.indexOf('A ') == 0) - return s.replace('A ', '') - else - return s; + }, + format: function(s) { + return (s || '').replace(/^(The|A)\s/i,''); }, type: 'text' }); - \$.tablesorter.addParser({ - id: 'images', + id: 'quality', is: function(s) { return false; - }, - format: function(s) { - if (s == '') - return '~~'; - else - return s; }, - type: 'text' + format: function(s) { + return s.replace('hd',3).replace('sd',1).replace('any',0).replace('best',2).replace('custom',4); + }, + type: 'numeric' }); \$(document).ready(function() { \$("#massUpdateTable:has(tbody tr)").tablesorter({ - sortList: [[1,0]], - widgets: ['zebra'], + sortList: [[2,0]], + textExtraction: { + 1: function(node) { return \$(node).find("img").attr("alt"); }, + 3: function(node) { return \$(node).find("span").text().toLowerCase(); }, + 4: function(node) { return \$(node).find("img").attr("alt"); }, + 5: function(node) { return \$(node).find("img").attr("alt"); } + }, + widgets: ['zebra', 'stickyHeaders'], headers: { 0: { sorter: false}, - 1: { sorter: 'showNames'}, - 3: { sorter: 'images'}, - 4: { sorter: 'images'}, - 6: { sorter: false}, + 2: { sorter: 'showNames'}, + 3: { sorter: 'quality'}, 7: { sorter: false}, 8: { sorter: false}, - 9: { sorter: false} + 9: { sorter: false}, + 10: { sorter: false} } }); }); @@ -67,6 +63,7 @@ <thead> <tr> <th width="1%">Edit <input type="checkbox" class="bulkCheck" id="editCheck" /></th> + <th class="nowrap">Lang</th> <th class="nowrap">Show Name</th> <th>Quality</th> <th>Season<br/>Folders</th> @@ -81,8 +78,8 @@ </thead> <tfoot> <tr> - <td rowspan="1" colspan="1" align="center"><input type="button" value="Edit Selected Shows" id="submitMassEdit" /></td> - <td rowspan="1" colspan="9" align="right"><input type="button" value="Submit" id="submitMassUpdate" /></td> + <td rowspan="1" colspan="1" class="align-center alt"><input type="button" value="Edit Selected" id="submitMassEdit" /></td> + <td rowspan="1" colspan="10" class="align-right alt"><input type="button" value="Submit" id="submitMassUpdate" /></td> </tr> </tfoot> <tbody> @@ -114,6 +111,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name)) <tr> <td align="center"><input type="checkbox" class="editCheck" id="edit-$curShow.tvdbid" /></td> + <td align="center"><img src="$sbRoot/images/flags/${curShow.lang}.png" width="16" height="11" alt="$curShow.lang" /></td> <td class="tvShow"><a href="$sbRoot/home/displayShow?show=$curShow.tvdbid">$curShow.name</a></td> #if $curShow.quality in $qualityPresets: <td align="center"><span class="quality $qualityPresetStrings[$curShow.quality]">$qualityPresetStrings[$curShow.quality]</span></td> diff --git a/data/interfaces/default/manage_backlogOverview.tmpl b/data/interfaces/default/manage_backlogOverview.tmpl index 3731776d55dc87dd1a8a3aa750a5ca5cf9c4a0a3..8cbc57c554349011177a4d84b3e6f9b500721e69 100644 --- a/data/interfaces/default/manage_backlogOverview.tmpl +++ b/data/interfaces/default/manage_backlogOverview.tmpl @@ -52,7 +52,7 @@ <tr class="$Overview.overviewStrings[$showCats[$curShow.tvdbid][$whichStr]]"> <td align="center">$whichStr</td> <td>$curResult["name"]</td> - <td align="center">#if int($curResult["airdate"]) == 1 then "never" else $datetime.date.fromordinal(int($curResult["airdate"]))#</td> + <td align="center" class="nowrap">#if int($curResult["airdate"]) == 1 then "never" else $datetime.date.fromordinal(int($curResult["airdate"]))#</td> </tr> #end for diff --git a/data/interfaces/default/restart_bare.tmpl b/data/interfaces/default/restart_bare.tmpl index 5c8e93131ba41336d30c18528d9d372fcbaed5b1..150c3281f098014e1bee8f4c90eb01ad61f30814 100644 --- a/data/interfaces/default/restart_bare.tmpl +++ b/data/interfaces/default/restart_bare.tmpl @@ -1,11 +1,22 @@ -<script type="text/javascript" src="$sbRoot/js/jquery-1.6.1.min.js"></script> <script type="text/javascript" charset="utf-8"> <!-- +#try: + #set curSBHost = $sbHost + #set curSBHttpPort = $sbHttpPort + #set curSBHttpsEnabled = $sbHttpsEnabled +#except NameMapper.NotFound: + #set curSBHost = "localhost" + #set curSBHttpPort = $sickbeard.WEB_PORT + #set curSBHttpsEnabled = "False" +#end try sbRoot = "$sbRoot"; +sbHttpPort = "$curSBHttpPort"; +sbHttpsEnabled = "$curSBHttpsEnabled"; +sbHost = "$curSBHost"; //--> </script> -<script type="text/javascript" src="$sbRoot/js/jquery-1.5.1.min.js"></script> +<script type="text/javascript" src="$sbRoot/js/jquery-1.7.1.min.js"></script> <script type="text/javascript" src="$sbRoot/js/restart.js"></script> <h2>Performing Restart</h2> @@ -31,4 +42,3 @@ Loading the home page: <div id="restart_fail_message" style="display: none;"> Error: The restart has timed out, perhaps something prevented Sick Beard from starting again? </div> - diff --git a/data/interfaces/default/viewlogs.tmpl b/data/interfaces/default/viewlogs.tmpl index fda393cc72d01fb75bd98269c1b6f855ffd24f34..95e6e14f8d2d06d881bed0d0903db390ac5c7482 100644 --- a/data/interfaces/default/viewlogs.tmpl +++ b/data/interfaces/default/viewlogs.tmpl @@ -14,7 +14,7 @@ <!-- \$(document).ready(function(){ \$('#minLevel').change(function(){ - url = 'viewlog?minLevel='+\$(this).val() + url = '$sbRoot/errorlogs/viewlog/?minLevel='+\$(this).val() window.location.href = url }); }); diff --git a/data/js/apibuilder.js b/data/js/apibuilder.js new file mode 100644 index 0000000000000000000000000000000000000000..b8c6a0a6a3baf1dcf3ae7f78e5a059d2a37c41ec --- /dev/null +++ b/data/js/apibuilder.js @@ -0,0 +1,635 @@ +// Chained Selects + +// Copyright Xin Yang 2004 +// Web Site: www.yxScripts.com +// EMail: m_yangxin@hotmail.com +// Last Updated: Jan. 31, 2009 + +// This script is free as long as the copyright notice remains intact. + +var _disable_empty_list=false; +var _hide_empty_list=false; + +function goListGroup(apikey, L7, L6, L5, L4, L3, L2, L1){ + var GlobalOptions = ""; + $('.global').each(function(){ + var checked = $(this).prop('checked'); + if(checked) { + GlobalOptions = GlobalOptions + "&" + $(this).attr('id') + "=1"; + } + }); + + // handle the show.getposter / show.getbanner differently as they return an image and not json + if (L1 == "?cmd=show.getposter" || L1 == "?cmd=show.getbanner") { + var imgcache = sbRoot + "/api/" + apikey + "/" + L1 + L2 + GlobalOptions; + var html = imgcache + '<br/><br/><img src="' + sbRoot + '/images/loading16.gif" id="imgcache">'; + $('#apiResponse').html(html); + $.ajax({ + url: sbRoot + "/api/" + apikey + "/" + L1 + L2 + GlobalOptions, + async: false, + cache: false, + dataType: "html", + success: function (img) { + $('#imgcache').attr('src', imgcache); + } + }) + } + else { + var html = sbRoot + "/api/" + apikey + "/" + L1 + L2 + L3 + L4 + L5 + L6 + L7 + GlobalOptions + "<br/><pre>"; + html += $.ajax({ + url: sbRoot + "/api/" + apikey + "/" + L1 + L2 + L3 + L4 + L5 + L6 + L7 + GlobalOptions, + async: false, + dataType: "html", + }).responseText; + + html += '</pre>'; + $('#apiResponse').html(html); + } +} + +// ------ +if (typeof(disable_empty_list)=="undefined") { disable_empty_list=_disable_empty_list; } +if (typeof(hide_empty_list)=="undefined") { hide_empty_list=_hide_empty_list; } + +var cs_goodContent=true, cs_M="M", cs_L="L", cs_G="G", cs_EG="EG"; +var cs_names=new Array(); +var cs_supportDOM=document.createElement; +var cs_nav=navigator.userAgent.toLowerCase(); +var cs_isIE7=(cs_nav.indexOf("msie 7")!=-1 || cs_nav.indexOf("msie 8")!=-1); +var cs_isOpera=(cs_nav.indexOf("opera")!=-1); +var cs_isMac=(cs_nav.indexOf("mac")!=-1); + +function cs_findOBJ(obj,n) { + for (var i=0; i<obj.length; i++) { + if (obj[i].name==n) { return obj[i]; } + } + return null; +} +function cs_findContent(n) { return cs_findOBJ(cs_content,n); } +function cs_findSubContent(n) { return cs_findOBJ(cs_subContent,n); } + +function cs_findM(m,n) { + if (m.name==n) { return m; } + + var sm=null; + for (var i=0; i<m.items.length; i++) { + if (m.items[i].type==cs_M) { + sm=cs_findM(m.items[i],n); + if (sm!=null) { break; } + } + } + return sm; +} + +function cs_subContentOBJ(n,list) { + this.name=n; + this.list=list; + + this.ifm=document.createElement("IFRAME"); + with (this.ifm.style) { + position="absolute"; left="-200px"; top="-200px"; visibility="hidden"; width="100px"; height="100px"; + } + document.body.appendChild(this.ifm); + this.ifm.src=n; +}; cs_subContent=new Array(); + +function cs_contentOBJ(n,obj){ + this.name=n; + this.menu=obj; + this.lists=new Array(); + this.cookie=""; + this.callback=null; + this.count=1; +}; cs_content=new Array(); + +function cs_topmenuOBJ(tm) { + this.name=tm; + this.type=cs_M; + this.items=new Array(); + this.df=","; + this.oidx=0; + + this.addM=cs_addM; this.addL=cs_addL; this.addG=cs_addG, this.endG=cs_endG; +} +function cs_submenuOBJ(dis,link,sub,label,css) { + this.name=sub; + this.type=cs_M; + this.dis=dis; + this.link=link; + this.label=label; + this.css=css; + this.df=","; + this.oidx=0; + + this.addM=cs_addM; this.addL=cs_addL; this.addG=cs_addG, this.endG=cs_endG; + + if (typeof(cs_names[sub])=="undefined") { + this.items=new Array(); + cs_names[sub] = this; + } + else + { + this.items = cs_names[sub].items; + } +} +function cs_linkOBJ(dis,link,label,css) { + this.type=cs_L; + this.dis=dis; + this.link=link; + this.label=label; + this.css=css; +} +function cs_groupOBJ(label,css) { + this.type=cs_G; + this.dis=""; + this.link=""; + this.label=label; + this.css=css; +} +function cs_groupOBJ2() { + this.type=cs_EG; + this.dis=""; + this.link=""; + this.label=""; +} + +function cs_addM(dis,link,sub,label,css) { + var x=new cs_submenuOBJ(dis,link,sub,label,css); + this.items[this.items.length]=x; +} +function cs_addL(dis,link,label,css) { this.items[this.items.length]=new cs_linkOBJ(dis,link,label,css); } +function cs_addG(label,css) { this.items[this.items.length]=new cs_groupOBJ(label,css); } +function cs_endG() { this.items[this.items.length]=new cs_groupOBJ2(); } + +function cs_showMsg(msg) { window.status=msg; } +function cs_badContent(n) { cs_goodContent=false; cs_showMsg("["+n+"] Not Found."); } + +function _setCookie(name, value) { + document.cookie=name+"="+value; +} +function cs_setCookie(name, value) { + setTimeout("_setCookie('"+name+"','"+value+"')",0); +} + +function cs_getCookie(name) { + var cookieRE=new RegExp(name+"=([^;]+)"); + if (document.cookie.search(cookieRE)!=-1) { + return RegExp.$1; + } + else { + return ""; + } +} + +function cs_optionOBJ(type,text,value,label,css) { this.type=type; this.text=text; this.value=value; this.label=label; this.css=css; } +function cs_getOptions(menu,list) { + var opt=new Array(); + for (var i=0; i<menu.items.length; i++) { + opt[i]=new cs_optionOBJ(menu.items[i].type, menu.items[i].dis, menu.items[i].link, menu.items[i].label, menu.items[i].css); + } + if (opt.length==0 && menu.name!="") { + cs_getSubList(menu.name,list); + opt[0]=new cs_optionOBJ(cs_L, "loading ...", "", "", ""); + } + return opt; +} +function cs_emptyList(list) { + if (cs_supportDOM && !cs_isMac && !cs_isIE7) { + while (list.lastChild) { + list.removeChild(list.lastChild); + } + } + else { + for (var i=list.options.length-1; i>=0; i--) { + list.options[i]=null; + } + } +} +function cs_refreshList(list,opt,df,key) { + var l=list.options.length; + var optGroup=null, newOpt=null, optCount=0, optPool=list; + + if (cs_isMac) { + var l=list.options.length; + var iCount=0; + + for (var i=0; i<opt.length; i++) { + if (opt[i].type!=cs_G && opt[i].type!=cs_EG) { + iCount=l+optCount; + + list.options[iCount]=new Option(opt[i].text, opt[i].value, df.indexOf(","+optCount+",")!=-1, df.indexOf(","+optCount+",")!=-1); + list.options[iCount].oidx=optCount; + list.options[iCount].idx=i; + list.options[iCount].key=key; + + if (opt[i].label!="") { + list.options[iCount].label=opt[i].label; + } + if (opt[i].css!="") { + list.options[iCount].className=opt[i].css; + } + + optCount++; + } + } + + return; + } + + for (var i=0; i<opt.length; i++) { + if (opt[i].type==cs_G) { + optGroup=document.createElement("optgroup"); + optGroup.setAttribute("label", opt[i].label); + if (opt[i].css!="") { + optGroup.setAttribute("className", opt[i].css); + } + list.appendChild(optGroup); + optPool=optGroup; + } + else if (opt[i].type==cs_EG) { + optGroup=null; + optPool=list; + } + else { + newOpt=new Option(opt[i].text,opt[i].value); + if (cs_supportDOM && !cs_isIE7) { + optPool.appendChild(newOpt); + } + else { + list.options[l+optCount]=newOpt; + } + + newOpt.oidx=optCount; + newOpt.idx=i; + newOpt.key=key; + + // a workaround for IE, but will screw up with Opera + if (!cs_isOpera) { + newOpt.text=opt[i].text; + newOpt.value=opt[i].value; + } + + if (df.indexOf(","+optCount+",")!=-1) { + newOpt.selected=true; + } + if (opt[i].label!="") { + newOpt.label=opt[i].label; + } + if (opt[i].css!="") { + newOpt.className=opt[i].css; + } + + optCount++; + } + } +} + +function cs_getList(content,key) { + var menu=content.menu; + + if (key!="[]") { + var paths=key.substring(1,key.length-1).split(","); + for (var i=0; i<paths.length; i++) { + menu=menu.items[parseInt(paths[i],10)]; + } + } + + return menu; +} +function cs_getKey(key,idx) { + return "["+(key=="[]"?"":(key.substring(1,key.length-1)+","))+idx+"]"; +} +function cs_getSelected(mode,name,idx,key,df) { + if (mode) { + var cookies=cs_getCookie(name+"_"+idx); + if (cookies!="") { + var mc=cookies.split("-"); + for (var i=0; i<mc.length; i++) { + if (mc[i].indexOf(key)!=-1) { + df=mc[i].substring(key.length); + break; + } + } + } + } + return df; +} + +function cs_updateListGroup(content,idx,mode) { + var menu=null, list=content.lists[idx], options=list.options, has_sublist=false; + var key="", option=",", cookies=""; + + //if (list.selectedIndex<0) { + // list.selectedIndex=0; + //} + + for (var i=0; i<options.length; i++) { + if (options[i].selected) { + if (key!=options[i].key) { + cookies+=key==""?"":((cookies==""?"":"-")+key+option); + + key=options[i].key; + option=","; + menu=cs_getList(content,key); + } + + option+=options[i].oidx+","; + + if (idx+1<content.lists.length) { + if (menu.items.length > options[i].idx && menu.items[options[i].idx].type==cs_M) { + if (!has_sublist) { + has_sublist=true; + cs_emptyList(content.lists[idx+1]); + } + var subkey=cs_getKey(key,options[i].idx), df=cs_getSelected(mode,content.cookie,idx+1,subkey,menu.items[options[i].idx].df); + cs_refreshList(content.lists[idx+1],cs_getOptions(menu.items[options[i].idx],list),df,subkey); + } + } + } + } + + if (key!="") { + cookies+=(cookies==""?"":"-")+key+option; + } + + if (content.cookie) { + cs_setCookie(content.cookie+"_"+idx,cookies); + } + + if (has_sublist && idx+1<content.lists.length) { + if (disable_empty_list) { + content.lists[idx+1].disabled=false; + } + if (hide_empty_list) { + content.lists[idx+1].style.display="block"; + } + cs_updateListGroup(content,idx+1,mode); + } + else { + for (var s=idx+1; s<content.lists.length; s++) { + cs_emptyList(content.lists[s]); + + if (disable_empty_list) { + content.lists[s].disabled=true; + } + if (hide_empty_list) { + content.lists[s].style.display="none"; + } + + if (content.cookie) { + cs_setCookie(content.cookie+"_"+s,""); + } + } + } +} + +function cs_initListGroup(content,mode) { + var key="[]", df=cs_getSelected(mode,content.cookie,0,key,content.menu.df); + + cs_emptyList(content.lists[0]); + cs_refreshList(content.lists[0],cs_getOptions(content.menu,content.lists[0]),df,key); + cs_updateListGroup(content,0,mode); +} + +function cs_updateList() { + var content=this.content; + for (var i=0; i<content.lists.length; i++) { + if (content.lists[i]==this) { + cs_updateListGroup(content,i,content.cookie); + + if (content.callback) { + var opt=""; + for (var j=0; j<this.options.length; j++) { + if (this.options[j].selected) { + if (opt!="") { + opt+=","; + } + if (this.options[j].value!="") { + opt+=this.options[j].value; + } + else if (this.options[j].text!="") { + opt+=this.options[j].text; + } + else if (this.options[j].label!="") { + opt+=this.options[j].label; + } + } + } + content.callback(this,i+1,content.count,opt); + } + + if (this.handler) { + this.handler(); + } + + break; + } + } +} + +function cs_getSubList(n,list) { + if (cs_goodContent && cs_supportDOM) { + var cs_subList=cs_findSubContent(n); + if (cs_subList==null) { + cs_subContent[cs_subContent.length]=new cs_subContentOBJ(n,list); + } + } +} + +function cs_updateSubList(cn,sn) { + var cc=cs_findContent(cn), sc=cs_findContent(sn); + if (cc!=null && sc!=null) { + var cs_sub=cs_findM(cc.menu,sn); + if (cs_sub!=null) { + cs_sub.df=sc.menu.df; + cs_sub.oidx=sc.menu.oidx; + cs_sub.items=sc.menu.items; + } + } + + var cs_subList=cs_findSubContent(sn); + if (cs_subList!=null) { + cs_subList.list.onchange(); + + cs_subList.ifm.src=""; + document.body.removeChild(cs_subList.ifm); + cs_subList.ifm=null; + } +} + +// ------ +function addListGroup(n,tm) { + if (cs_goodContent) { + cs_names[tm]=new cs_topmenuOBJ(tm); + + var c=cs_findContent(n); + if (c==null) { + cs_content[cs_content.length]=new cs_contentOBJ(n,cs_names[tm]); + } + else { + delete(c.menu); c.menu=cs_names[tm]; + } + } +} + +function addList(n,dis,link,sub,df,label,css) { + if (typeof(sub)=="undefined" || sub=="") { + addOption(n,dis,link||"",df||"",label||"",css||""); + } + else if (cs_goodContent) { + if (typeof(cs_names[n])!="undefined") { + cs_names[n].addM(dis,link||"",sub+"",label||"",css||""); + if (typeof(df)!="undefined" && df) { + cs_names[n].df+=cs_names[n].oidx+","; + } + cs_names[n].oidx++; + } + else { + cs_badContent(n); + } + } +} + +function addOption(n,dis,link,df,label,css) { + if (cs_goodContent) { + if (typeof(cs_names[n])!="undefined") { + cs_names[n].addL(dis,link||"",label||"",css||""); + if (typeof(df)!="undefined" && df) { + cs_names[n].df+=cs_names[n].oidx+","; + } + cs_names[n].oidx++; + } + else { + cs_badContent(n); + } + } +} + +function addOptGroup(n,label,css) { + if (cs_goodContent && cs_supportDOM && !cs_isOpera) { + if (typeof(cs_names[n])!="undefined") { + cs_names[n].addG(label,css||""); + } + else { + cs_badContent(n); + } + } +} + +function endOptGroup(n) { + if (cs_goodContent && cs_supportDOM && !cs_isOpera) { + if (typeof(cs_names[n])!="undefined") { + cs_names[n].endG(); + } + else { + cs_badContent(n); + } + } +} + +function initListGroup(n) { + var _content=cs_findContent(n), count=0; + if (_content!=null) { + var content=new cs_contentOBJ("cs_"+_content.count+"_"+n,_content.menu); + content.count=_content.count++; + cs_content[cs_content.length]=content; + + for (var i=1; i<initListGroup.arguments.length; i++) { + if (typeof(arguments[i])=="object" && arguments[i].tagName && arguments[i].tagName=="SELECT") { + content.lists[count]=arguments[i]; + + arguments[i].handler=arguments[i].onchange; + arguments[i].onchange=cs_updateList; + arguments[i].content=content; arguments[i].idx=count++; + } + else if (typeof(arguments[i])=="string" && /^[a-zA-Z_]\w*$/.test(arguments[i])) { + content.cookie=arguments[i]; + } + else if (typeof(arguments[i])=="function") { + content.callback=arguments[i]; + } + else { + cs_showMsg("Warning: Unexpected argument in initListGroup() for ["+n+"]"); + } + } + + if (content.lists.length>0) { + cs_initListGroup(content,content.cookie); + } + } +} + +function initListGroups(n) { + var listCount=0; + for (var i=1; i<initListGroups.arguments.length; i++) { + // opera takes select array as function + if ((typeof(arguments[i])=="object" || typeof(arguments[i])=="function") && arguments[i].length && typeof(arguments[i][0])!="undefined" && arguments[i][0].tagName && arguments[i][0].tagName=="SELECT") { + if (listCount>arguments[i].length || listCount==0) { + listCount=arguments[i].length; + } + } + } + + var _content=cs_findContent(n), count=0, content=null; + if (_content!=null) { + for (var l=0; l<listCount; l++) { + count=0; + content=new cs_contentOBJ("cs_"+_content.count+"_"+n,_content.menu); + content.count=_content.count++; + cs_content[cs_content.length]=content; + + for (var i=1; i<initListGroups.arguments.length; i++) { + if ((typeof(arguments[i])=="object" || typeof(arguments[i])=="function") && arguments[i].length && typeof(arguments[i][0])!="undefined" && arguments[i][0].tagName && arguments[i][0].tagName=="SELECT") { + content.lists[count]=arguments[i][l]; + + arguments[i][l].handler=arguments[i][l].onchange; + arguments[i][l].onchange=cs_updateList; + arguments[i][l].content=content; arguments[i][l].idx=count++; + } + else if (typeof(arguments[i])=="string" && /^[a-zA-Z_]\w*$/.test(arguments[i])) { + content.cookie=arguments[i]+"_"+l; + } + else if (typeof(arguments[i])=="function") { + content.callback=arguments[i]; + } + else { + cs_showMsg("Warning: Unexpected argument in initListGroups() for ["+n+"]"); + } + } + + if (content.lists.length>0) { + cs_initListGroup(content,content.cookie); + } + } + } +} + +function resetListGroup(n,count) { + var content=cs_findContent("cs_"+(count||1)+"_"+n); + if (content!=null && content.lists.length>0) { + cs_initListGroup(content,""); + } +} + +function selectOptions(n,opts,mode) { + var content=cs_findContent(n); + if (content!=null) { + var optss=opts.split(":"), menu=content.menu, path=true; + for (var i=0; i<optss.length; i+=2) { + if (menu.type==cs_M && path) { + path=false; + for (var o=0; o<menu.items.length; o++) { + if (mode==0 && menu.items[o].dis==optss[i] || mode==1 && menu.items[o].link==optss[i] || mode==2 && o==optss[i]) { + path=true; + if (optss[i+1]!="-") { + menu.df=","+o+","; + } + menu=menu.items[o]; + break; + } + } + } + } + } +} +// ------ diff --git a/data/js/browser.js b/data/js/browser.js index 62b9c856a56a0b4e3921ccfbc031405b7c7d1163..d4b15f813800f344858e4ad78d67342e83b35f73 100644 --- a/data/js/browser.js +++ b/data/js/browser.js @@ -1,44 +1,45 @@ -(function(){ +(function () { $.Browser = { defaults: { title: 'Choose Directory', - url: sbRoot+'/browser/', - autocompleteURL: sbRoot+'/browser/complete' + url: sbRoot + '/browser/', + autocompleteURL: sbRoot + '/browser/complete' } }; - var fileBrowserDialog = null; - var currentBrowserPath = null; - var currentRequest = null; + var fileBrowserDialog, currentBrowserPath, currentRequest = null; function browse(path, endpoint) { - if(currentBrowserPath == path) + if (currentBrowserPath === path) { return; - + } + currentBrowserPath = path; - - if(currentRequest) + + if (currentRequest) { currentRequest.abort(); - + } + fileBrowserDialog.dialog('option', 'dialogClass', 'browserDialog busy'); - - currentRequest = $.getJSON(endpoint, { path: path }, function(data){ + + currentRequest = $.getJSON(endpoint, { path: path }, function (data) { fileBrowserDialog.empty(); var first_val = data[0]; var i = 0; - data = jQuery.grep(data, function(value) { + var list, link = null; + data = $.grep(data, function (value) { return i++ != 0; }); $('<h1>').text(first_val.current_path).appendTo(fileBrowserDialog); list = $('<ul>').appendTo(fileBrowserDialog); - $.each(data, function(i, entry) { - link = $("<a href='javascript:void(0)' />").click(function(){ browse(entry.path, endpoint); }).text(entry.name); + $.each(data, function (i, entry) { + link = $("<a href='javascript:void(0)' />").click(function () { browse(entry.path, endpoint); }).text(entry.name); $('<span class="ui-icon ui-icon-folder-collapsed"></span>').prependTo(link); link.hover( - function(){jQuery("span", this).addClass("ui-icon-folder-open"); }, - function(){jQuery("span", this).removeClass("ui-icon-folder-open"); } + function () {$("span", this).addClass("ui-icon-folder-open"); }, + function () {$("span", this).removeClass("ui-icon-folder-open"); } ); link.appendTo(list); }); @@ -47,95 +48,123 @@ }); } - $.fn.nFileBrowser = function(callback, options){ - + $.fn.nFileBrowser = function (callback, options) { + options = $.extend({}, $.Browser.defaults, options); - + // make a fileBrowserDialog object if one doesn't exist already - if(!fileBrowserDialog) { - + if (!fileBrowserDialog) { + // set up the jquery dialog fileBrowserDialog = $('<div id="fileBrowserDialog" style="display:hidden"></div>').appendTo('body').dialog({ dialogClass: 'browserDialog', title: options.title, position: ['center', 40], - minWidth: Math.min($(document).width()-80, 650), + minWidth: Math.min($(document).width() - 80, 650), minHeight: 320, - height: $(document).height()-80, + height: $(document).height() - 80, modal: true, autoOpen: false }); } - + // add the OK/Close buttons to the dialog - fileBrowserDialog.dialog('option', 'buttons', - { - "Ok": function(){ - + fileBrowserDialog.dialog('option', 'buttons', { + "Ok": function () { // store the browsed path to the associated text field //options.field.val(currentBrowserPath); //alert(currentBrowserPath); callback(currentBrowserPath, options); - fileBrowserDialog.dialog("close"); }, - - "Cancel": function(){ + "Cancel": function () { fileBrowserDialog.dialog("close"); } - }); - + // set up the browser and launch the dialog - if (options.initialDir) + var initialDir = ''; + if (options.initialDir) { initialDir = options.initialDir; - else - initialDir = ''; - browse(initialDir, options.url) + } + browse(initialDir, options.url); fileBrowserDialog.dialog('open'); return false; }; - $.fn.fileBrowser = function(options){ + $.fn.fileBrowser = function (options) { options = $.extend({}, $.Browser.defaults, options); - // text field used for the result options.field = $(this); - - if(options.field.autocomplete && options.autocompleteURL) { - options.field.autocomplete({ - source: options.autocompleteURL, - open: function(event, ui) { + + if (options.field.autocomplete && options.autocompleteURL) { + var query = ''; + options.field.autocomplete({ + source: function (request, response) { + //keep track of user submitted search term + query = $.ui.autocomplete.escapeRegex(request.term); + $.ajax({ + url: options.autocompleteURL, + data: request, + dataType: "json", + success: function (data, item) { + //implement a startsWith filter for the results + var matcher = new RegExp("^" + query, "i"); + var a = $.grep(data, function (item, index) { + return matcher.test(item); + }); + response(a); + } + }); + }, + open: function (event, ui) { $(".ui-autocomplete li.ui-menu-item a").removeClass("ui-corner-all"); $(".ui-autocomplete li.ui-menu-item:odd a").addClass("ui-menu-item-alternate"); } - }); + }) + .data("autocomplete")._renderItem = function (ul, item) { + //highlight the matched search term from the item -- note that this is global and will match anywhere + var result_item = item.label; + var x = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + query + ")(?![^<>]*>)(?![^&;]+;)", "gi"); + result_item = result_item.replace(x, function (FullMatch, n) { + return '<b>' + FullMatch + '</b>'; + }); + return $("<li></li>") + .data("item.autocomplete", item) + .append("<a class='nowrap'>" + result_item + "</a>") + .appendTo(ul); + }; } - // if the text field is empty and we're given a key then populate it with the last browsed value from a cookie - if(options.key && options.field.val().length == 0 && (path = $.cookie('fileBrowser-' + options.key))) + var initialDir, path, callback, ls = false; + // if the text field is empty and we're given a key then populate it with the last browsed value from localStorage + try { ls = !!(localStorage.getItem); } catch (e) {} + if (ls && options.key) { + path = localStorage['fileBrowser-' + options.key]; + } + if (options.key && options.field.val().length === 0 && (path)) { options.field.val(path); - - callback = function(path, options){ + } + + callback = function (path, options) { // store the browsed path to the associated text field options.field.val(path); - - // use a cookie to remember for next time - if(options.key) - $.cookie('fileBrowser-' + options.key, path); - - } - initialDir = options.field.val() || (options.key && $.cookie('fileBrowser-' + options.key)) || ''; - - options = $.extend(options, {initialDir: initialDir}) - + // use a localStorage to remember for next time -- no ie6/7 + if (ls && options.key) { + localStorage['fileBrowser-' + options.key] = path; + } + + }; + + initialDir = options.field.val() || (options.key && path) || ''; + + options = $.extend(options, {initialDir: initialDir}); + // append the browse button and give it a click behavior - return options.field.addClass('fileBrowserField').after($('<input type="button" value="Browse…" class="fileBrowser" />').click(function(){ - + return options.field.addClass('fileBrowserField').after($('<input type="button" value="Browse…" class="fileBrowser" />').click(function () { $(this).nFileBrowser(callback, options); - return false; })); }; diff --git a/data/js/config.js b/data/js/config.js index 71f1b6aaef5b8f45bcdbe74336e5f97e977d9b0d..a5cee0c747072a31278bf117f51c25bbdf3b24c4 100644 --- a/data/js/config.js +++ b/data/js/config.js @@ -13,24 +13,36 @@ $(document).ready(function(){ // bind 'myForm' and provide a simple callback function $('#configForm').ajaxForm({ - beforeSubmit: function(){ - $('.config_submitter').each(function(){ - $(this).attr("disabled", "disabled"); - $(this).after('<span><img src="'+sbRoot+'/images/loading16.gif"> Saving...</span>'); - $(this).hide(); - }); - }, - success: function(){ - setTimeout('config_success()', 2000) - } - }); + beforeSubmit: function(){ + $('.config_submitter').each(function(){ + $(this).attr("disabled", "disabled"); + $(this).after('<span><img src="'+sbRoot+'/images/loading16.gif"> Saving...</span>'); + $(this).hide(); + }); + }, + success: function(){ + setTimeout('config_success()', 2000) + } + }); + + $('#api_key').click(function(){ $('#api_key').select() }); + $("#generate_new_apikey").click(function(){ + $.get(sbRoot + '/config/general/generateKey', + function(data){ + if (data.error != undefined) { + alert(data.error); + return; + } + $('#api_key').val(data); + }); + }); }); function config_success(){ - $('.config_submitter').each(function(){ - $(this).removeAttr("disabled"); - $(this).next().remove(); - $(this).show(); - }); + $('.config_submitter').each(function(){ + $(this).removeAttr("disabled"); + $(this).next().remove(); + $(this).show(); + }); } \ No newline at end of file diff --git a/data/js/configNotifications.js b/data/js/configNotifications.js index cacfdd02ee001c7d7c3e46bbe16be09cfa3ae8d0..a9ed18fe89ab90b22dee734f49f2e014562cd9e4 100644 --- a/data/js/configNotifications.js +++ b/data/js/configNotifications.js @@ -45,6 +45,20 @@ $(document).ready(function(){ function (data){ $('#testNotifo-result').html(data); }); }); + $('#testBoxcar').click(function(){ + $('#testBoxcar-result').html(loading); + var boxcar_username = $("#boxcar_username").val(); + $.get(sbRoot+"/home/testBoxcar", {'username': boxcar_username}, + function (data){ $('#testBoxcar-result').html(data); }); + }); + + $('#testPushover').click(function(){ + $('#testPushover-result').html(loading); + var pushover_userkey = $("#pushover_userkey").val(); + $.get(sbRoot+"/home/testPushover", {'userKey': pushover_userkey}, + function (data){ $('#testPushover-result').html(data); }); + }); + $('#testLibnotify').click(function(){ $('#testLibnotify-result').html(loading); $.get(sbRoot+"/home/testLibnotify", @@ -110,4 +124,22 @@ $(document).ready(function(){ $.get(sbRoot+"/home/testNMJ", {'host': nmj_host, 'database': nmj_database, 'mount': nmj_mount}, function (data){ $('#testNMJ-result').html(data); }); }); + + $('#testTrakt').click(function(){ + $('#testTrakt-result').html(loading); + var trakt_api = $("#trakt_api").val(); + var trakt_username = $("#trakt_username").val(); + var trakt_password = $("#trakt_password").val(); + + $.get(sbRoot+"/home/testTrakt", {'api': trakt_api, 'username': trakt_username, 'password': trakt_password}, + function (data){ $('#testTrakt-result').html(data); }); + }); + + $('#testNMA').click(function(){ + $('#testNMA-result').html(loading); + var nma_api = $("#nma_api").val(); + var nma_priority = $("#nma_priority").val(); + var nma_result = $.get(sbRoot+"/home/testNMA", {'nma_api': nma_api, 'nma_priority': nma_priority}, + function (data){ $('#testNMA-result').html(data); }); + }); }); diff --git a/data/js/configSearch.js b/data/js/configSearch.js index c85317fdab11c5d73d37d67595db7993ada4e7b2..3d73b9c7135dafa23ea9c86ba903558e35a83f7b 100644 --- a/data/js/configSearch.js +++ b/data/js/configSearch.js @@ -1,5 +1,6 @@ $(document).ready(function(){ - + var loading = '<img src="'+sbRoot+'/images/loading16.gif" height="16" width="16" />'; + function toggle_torrent_title(){ if ($('#use_torrents').prop('checked')) $('#no-torrents').show(); @@ -14,14 +15,20 @@ $(document).ready(function(){ if (selectedProvider == "blackhole") { $('#blackhole_settings').show(); $('#sabnzbd_settings').hide(); + $('#testSABnzbd').hide(); + $('#testSABnzbd-result').hide(); $('#nzbget_settings').hide(); } else if (selectedProvider == "nzbget") { $('#blackhole_settings').hide(); $('#sabnzbd_settings').hide(); + $('#testSABnzbd').hide(); + $('#testSABnzbd-result').hide(); $('#nzbget_settings').show(); } else { $('#blackhole_settings').hide(); $('#sabnzbd_settings').show(); + $('#testSABnzbd').show(); + $('#testSABnzbd-result').show(); $('#nzbget_settings').hide(); } @@ -31,6 +38,17 @@ $(document).ready(function(){ $(this).nzb_method_handler(); + $('#testSABnzbd').click(function(){ + $('#testSABnzbd-result').html(loading); + var sab_host = $("input=[name='sab_host']").val(); + var sab_username = $("input=[name='sab_username']").val(); + var sab_password = $("input=[name='sab_password']").val(); + var sab_apiKey = $("input=[name='sab_apikey']").val(); + + $.get(sbRoot+"/home/testSABnzbd", {'host': sab_host, 'username': sab_username, 'password': sab_password, 'apikey': sab_apiKey}, + function (data){ $('#testSABnzbd-result').html(data); }); + }); + $('#use_torrents').click(function(){ toggle_torrent_title(); }); diff --git a/data/js/displayShow.js b/data/js/displayShow.js index 8cda4203dee2564443e744da0fdae1b5a48e983b..af26f4772ecd5fce1642424406fd7e202fcd8cec 100644 --- a/data/js/displayShow.js +++ b/data/js/displayShow.js @@ -1,7 +1,7 @@ $(document).ready(function(){ - $('#sbRoot').ajaxEpSearch({'colorRow': true}); - + $('#sbRoot').ajaxEpSearch({'colorRow': true}); + $('#seasonJump').change(function() { var id = $(this).val(); if (id && id != 'jump') { @@ -54,6 +54,30 @@ $(document).ready(function(){ }); }); + var lastCheck = null; + $('.epCheck').click(function(event) { + + if(!lastCheck || !event.shiftKey) { + lastCheck = this; + return; + } + + var check = this; + var found = 0; + + $('.epCheck').each(function() { + switch (found) { + case 2: return false; + case 1: this.checked = lastCheck.checked; + } + + if (this == check || this == lastCheck) + found++; + }); + + lastClick = this; + }); + // selects all visible episode checkboxes. $('.seriesCheck').click(function(){ $('.epCheck:visible').each(function(){ diff --git a/data/js/jquery-1.6.1.min.js b/data/js/jquery-1.6.1.min.js deleted file mode 100644 index b2ac1747f3cbb4fb3f9c2224905daf3f0bef21fd..0000000000000000000000000000000000000000 --- a/data/js/jquery-1.6.1.min.js +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * jQuery JavaScript Library v1.6.1 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu May 12 15:04:36 2011 -0400 - */ -(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!cj[a]){var b=f("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),c.body.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write("<!doctype><html><body></body></html>");b=cl.createElement(a),cl.body.appendChild(b),d=f.css(b,"display"),c.body.removeChild(ck)}cj[a]=d}return cj[a]}function cu(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function ct(){cq=b}function cs(){setTimeout(ct,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bF.test(a)?d(a,e):b_(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)b_(a+"["+e+"]",b[e],c,d);else d(a,b)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bU,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bQ),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bD(a,b,c){var d=b==="width"?bx:by,e=b==="width"?a.offsetWidth:a.offsetHeight;if(c==="border")return e;f.each(d,function(){c||(e-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?e+=parseFloat(f.css(a,"margin"+this))||0:e-=parseFloat(f.css(a,"border"+this+"Width"))||0});return e}function bn(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bm(a){f.nodeName(a,"input")?bl(a):a.getElementsByTagName&&f.grep(a.getElementsByTagName("input"),bl)}function bl(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bk(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bj(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bi(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bh(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function X(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(S.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function W(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function O(a,b){return(a&&a!=="*"?a+".":"")+b.replace(A,"`").replace(B,"&")}function N(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(y,"")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function L(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function F(){return!0}function E(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function H(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(H,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=d.userAgent,x,y,z,A=Object.prototype.toString,B=Object.prototype.hasOwnProperty,C=Array.prototype.push,D=Array.prototype.slice,E=String.prototype.trim,F=Array.prototype.indexOf,G={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.1",length:0,size:function(){return this.length},toArray:function(){return D.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?C.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(D.apply(this,arguments),"slice",D.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:C,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;y.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!y){y=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",z,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",z),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&H()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):G[A.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!B.call(a,"constructor")&&!B.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||B.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:E?function(a){return a==null?"":E.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?C.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(F)return F.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=D.call(arguments,2),g=function(){return a.apply(c,f.concat(D.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf("compatible")<0&&v.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){G["[object "+b+"]"]=b.toLowerCase()}),x=e.uaMatch(w),x.browser&&(e.browser[x.browser]=!0,e.browser.version=x.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?z=function(){c.removeEventListener("DOMContentLoaded",z,!1),e.ready()}:c.attachEvent&&(z=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",z),e.ready())});return e}(),g="done fail isResolved isRejected promise then always pipe".split(" "),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j==="array"?e.done.apply(e,i):j==="function"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[c,"reject"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g](h)}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement("div"),b=c.documentElement,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r;a.setAttribute("className","t"),a.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};f=c.createElement("select"),g=f.appendChild(c.createElement("option")),h=a.getElementsByTagName("input")[0],j={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},h.checked=!0,j.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,j.optDisabled=!g.disabled;try{delete a.test}catch(s){j.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function b(){j.noCloneEvent=!1,a.detachEvent("onclick",b)}),a.cloneNode(!0).fireEvent("onclick")),h=c.createElement("input"),h.value="t",h.setAttribute("type","radio"),j.radioValue=h.value==="t",h.setAttribute("checked","checked"),a.appendChild(h),k=c.createDocumentFragment(),k.appendChild(a.firstChild),j.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",l=c.createElement("body"),m={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"};for(q in m)l.style[q]=m[q];l.appendChild(a),b.insertBefore(l,b.firstChild),j.appendChecked=h.checked,j.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,j.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",j.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",n=a.getElementsByTagName("td"),r=n[0].offsetHeight===0,n[0].style.display="",n[1].style.display="none",j.reliableHiddenOffsets=r&&n[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(i=c.createElement("div"),i.style.width="0",i.style.marginRight="0",a.appendChild(i),j.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(i,null)||{marginRight:0}).marginRight,10)||0)===0),l.innerHTML="",b.removeChild(l);if(a.attachEvent)for(q in{submit:1,change:1,focusin:1})p="on"+q,r=p in a,r||(a.setAttribute(p,"return;"),r=typeof a[p]=="function"),j[q+"Bubbles"]=r;return j}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a=="object")return this.each(function(){f.data(this,a)});var j=a.split(".");j[1]=j[1]?"."+j[1]:"";if(c===b){d=this.triggerHandler("getData"+j[1]+"!",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler("setData"+j[1]+"!",d),f.data(this,a,c),b.triggerHandler("changeData"+j[1]+"!",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||"fx")+"mark",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||"fx";var e=d+"mark",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,"mark"))}},queue:function(a,c,d){if(a){c=(c||"fx")+"queue";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e;d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+"queue",!0),m(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\n\t\r]/g,o=/\s+/,p=/\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u=/\:/,v,w;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.addClass(a.call(this,b,c.attr("class")||""))});if(a&&typeof a=="string"){var b=(a||"").split(o);for(var c=0,d=this.length;c<d;c++){var e=this[c];if(e.nodeType===1)if(!e.className)e.className=a;else{var g=" "+e.className+" ",h=e.className;for(var i=0,j=b.length;i<j;i++)g.indexOf(" "+b[i]+" ")<0&&(h+=" "+b[i]);e.className=f.trim(h)}}}return this},removeClass:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.removeClass(a.call(this,b,c.attr("class")))});if(a&&typeof a=="string"||a===b){var c=(a||"").split(o);for(var d=0,e=this.length;d<e;d++){var g=this[d];if(g.nodeType===1&&g.className)if(a){var h=(" "+g.className+" ").replace(n," ");for(var i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){var d=f(this);d.toggleClass(a.call(this,c,d.attr("class"),b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(n," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;return(e.value||"").replace(p,"")}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute("disabled")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,"optgroup"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);c=j&&f.attrFix[c]||c,i=f.attrHooks[c],i||(!t.test(c)||typeof d!="boolean"&&d!==b&&d.toLowerCase()!==c.toLowerCase()?v&&(f.nodeName(a,"form")||u.test(c))&&(i=v):i=w);if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j)return i.get(a,c);h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);c=i&&f.propFix[c]||c,h=f.propHooks[c];return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return a[f.propFix[c]||c]?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=b),a.setAttribute(c,c.toLowerCase()));return c}},f.attrHooks.value={get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return a.value},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=Object.prototype.hasOwnProperty,y=/\.(.*)$/,z=/^(?:textarea|input|select)$/i,A=/\./g,B=/ /g,C=/[^\w\s.|`]/g,D=function(a){return a.replace(C,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=E;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=E);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),D).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete t[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf("!")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem -)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,O(a.origType,a.selector),f.extend({},a,{handler:N,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,O(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?F:E):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=F;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=F;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=F,this.stopPropagation()},isDefaultPrevented:E,isPropagationStopped:E,isImmediatePropagationStopped:E};var G=function(a){var b=a.relatedTarget;a.type=a.data;try{if(b&&b!==c&&!b.parentNode)return;while(b&&b!==this)b=b.parentNode;b!==this&&f.event.handle.apply(this,arguments)}catch(d){}},H=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?H:G,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?H:G)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,"form"))f.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&f(b).closest("form").length&&L("submit",this,arguments)}),f.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&f(b).closest("form").length&&a.keyCode===13&&L("submit",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,".specialSubmit")}});if(!f.support.changeBubbles){var I,J=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},K=function(c){var d=c.target,e,g;if(!!z.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=J(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:K,beforedeactivate:K,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&K.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&K.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",J(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in I)f.event.add(this,c+".specialChange",I[c]);return z.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return z.test(this.nodeName)}},I=f.event.special.change.filters,I.focus=I.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a=="object"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,"lastToggle"+a.guid)||0)%d;f.data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var M={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};f.each(["live","die"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a=="object"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c==="die"&&!a&&g&&g.charAt(0)==="."){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||E,d=b;a=(a||"").split(" ");while((h=a[i++])!=null){j=y.exec(h),k="",j&&(k=j[0],h=h.replace(y,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,M[h]?(a.push(M[h]+k),h=h+k):h=(M[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],"live."+O(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind("live."+O(h,m),e)}return this}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("parentNode",b,f,a,e,c)},"~":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("previousSibling",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[":"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var P=/Until$/,Q=/^(?:parents|prevUntil|prevAll)/,R=/,/,S=/^.[^:#\[\.,]*$/,T=Array.prototype.slice,U=f.expr.match.POS,V={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(X(this,a,!1),"not",a)},filter:function(a){return this.pushStack(X(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=U.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=U.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(W(c[0])||W(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=T.call(arguments);P.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!V[a]?f.unique(e):e,(this.length>1||R.test(d))&&Q.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y=/ jQuery\d+="(?:\d+|null)"/g,Z=/^\s+/,$=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,_=/<([\w:]+)/,ba=/<tbody/i,bb=/<|&#?\w+;/,bc=/<(?:script|object|embed|option|style)/i,bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Y,""):null;if(typeof a=="string"&&!bc.test(a)&&(f.support.leadingWhitespace||!Z.test(a))&&!bg[(_.exec(a)||["",""])[1].toLowerCase()]){a=a.replace($,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bh(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bn)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i=b&&b[0]?b[0].ownerDocument||b[0]:c;a.length===1&&typeof a[0]=="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!bc.test(a[0])&&(f.support.checkClone||!bd.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bj(a,d),e=bk(a),g=bk(d);for(h=0;e[h];++h)bj(e[h],g[h])}if(b){bi(a,d);if(c){e=bk(a),g=bk(d);for(h=0;e[h];++h)bi(e[h],g[h])}}return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument|| -b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bb.test(k))k=b.createTextNode(k);else{k=k.replace($,"<$1></$2>");var l=(_.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=ba.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Z.test(k)&&o.insertBefore(b.createTextNode(Z.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bm(k[i]);else bm(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bo=/alpha\([^)]*\)/i,bp=/opacity=([^)]*)/,bq=/-([a-z])/ig,br=/([A-Z]|^ms)/g,bs=/^-?\d+(?:px)?$/i,bt=/^-?\d/,bu=/^[+\-]=/,bv=/[^+\-\.\de]+/g,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB,bC=function(a,b){return b.toUpperCase()};f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0,widows:!0,orphans:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d;if(h==="number"&&isNaN(d)||d==null)return;h==="string"&&bu.test(d)&&(d=+d.replace(bv,"")+parseFloat(f.css(a,c))),h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bq,bC)}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){a.offsetWidth!==0?e=bD(a,b,d):f.swap(a,bw,function(){e=bD(a,b,d)});if(e<=0){e=bz(a,b,b),e==="0px"&&bB&&(e=bB(a,b,b));if(e!=null)return e===""||e==="auto"?"0px":e}if(e<0||e==null){e=a.style[b];return e===""||e==="auto"?"0px":e}return typeof e=="string"?e:e+"px"}},set:function(a,b){if(!bs.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bp.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bo.test(g)?g.replace(bo,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,c){var d,e,g;c=c.replace(br,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bs.test(d)&&bt.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bE=/%20/g,bF=/\[\]$/,bG=/\r?\n/g,bH=/#.*$/,bI=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bJ=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bK=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bL=/^(?:GET|HEAD)$/,bM=/^\/\//,bN=/\?/,bO=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bP=/^(?:select|textarea)/i,bQ=/\s+/,bR=/([?&])_=[^&]*/,bS=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bT=f.fn.load,bU={},bV={},bW,bX;try{bW=e.href}catch(bY){bW=c.createElement("a"),bW.href="",bW=bW.href}bX=bS.exec(bW.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bT)return bT.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bO,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bP.test(this.nodeName)||bJ.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bG,"\r\n")}}):{name:b.name,value:c.replace(bG,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bW,isLocal:bK.test(bX[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bZ(bU),ajaxTransport:bZ(bV),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?ca(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=cb(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bI.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bH,"").replace(bM,bX[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bQ),d.crossDomain==null&&(r=bS.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bX[1]&&r[2]==bX[2]&&(r[3]||(r[1]==="http:"?80:443))==(bX[3]||(bX[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bU,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bL.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bN.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bR,"$1_="+x);d.url=y+(y===d.url?(bN.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bV,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bE,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq,cr=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],"display");g!=="none"&&!f._data(this[d],"olddisplay")&&f._data(this[d],"olddisplay",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?"each":"queue"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(f.support.inlineBlockNeedsLayout?(j=cv(this.nodeName),j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)):this.style.display="inline-block"))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)k=new f.fx(this,b,i),h=a[i],cm.test(h)?k[h==="toggle"?d?"show":"hide":h]():(l=cn.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?"":"px"),o!=="px"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]==="-="?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,""));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this),f.isFunction(d.old)&&d.old.call(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function h(a){return d.step(a)}var d=this,e=f.fx,g;this.startTime=cq||cs(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,h.elem=this.elem,h()&&f.timers.push(h)&&!co&&(cr?(co=1,g=function(){co&&(cr(g),e.tick())},cr(g)):co=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cq||cs(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement("div"),d,e,g,h,i=parseFloat(f.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){return this[0]?parseFloat(f.css(this[0],d,"padding")):null},f.fn["outer"+c]=function(a){return this[0]?parseFloat(f.css(this[0],d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/data/js/jquery-1.7.1.min.js b/data/js/jquery-1.7.1.min.js new file mode 100644 index 0000000000000000000000000000000000000000..198b3ff07d801dffa2c42fcf3b67eb3295eef85f --- /dev/null +++ b/data/js/jquery-1.7.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/data/js/jquery-ui-1.8.13.custom.min.js b/data/js/jquery-ui-1.8.13.custom.min.js deleted file mode 100644 index 30a4d7588c8cd1e441cad19cd5d23433848f2ad4..0000000000000000000000000000000000000000 --- a/data/js/jquery-ui-1.8.13.custom.min.js +++ /dev/null @@ -1,702 +0,0 @@ -/*! - * jQuery UI 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.13", -keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus(); -b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this, -"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection", -function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth, -outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a,"tabindex"),d=isNaN(b); -return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e= -0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery); -;/*! - * jQuery UI Widget 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Widget - */ -(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h, -a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h; -e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options, -this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")}, -widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this}, -enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery); -;/*! - * jQuery UI Mouse 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Mouse - * - * Depends: - * jquery.ui.widget.js - */ -(function(b){var d=false;b(document).mousedown(function(){d=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+ -this.widgetName)},_mouseDown:function(a){if(!d){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,f=a.which==1,g=typeof this.options.cancel=="string"?b(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!f||g||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted= -this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(e){return c._mouseMove(e)};this._mouseUpDelegate=function(e){return c._mouseUp(e)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return d=true}},_mouseMove:function(a){if(b.browser.msie&& -!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= -false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -;/* - * jQuery UI Position 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Position - */ -(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, -left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= -k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= -m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= -d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= -a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), -g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); -;/* - * jQuery UI Draggable 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== -"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= -this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;this.helper= -this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a); -this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b= -d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop", -a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this== -a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a= -{left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&& -d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a= -this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions= -{width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[(a.containment=="document"?0:d(window).scrollLeft())-this.offset.relative.left-this.offset.parent.left,(a.containment=="document"?0:d(window).scrollTop())-this.offset.relative.top-this.offset.parent.top,(a.containment=="document"?0:d(window).scrollLeft())+ -d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!="hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"), -10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height- -this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&& -d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0], -this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.left<g[0])e=g[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<g[1])h=g[1]+this.offset.click.top; -if(a.pageX-this.offset.click.left>g[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1];h=g?!(h-this.offset.click.top<g[1]||h-this.offset.click.top>g[3])?h:!(h-this.offset.click.top<g[1])?h-b.grid[1]:h+b.grid[1]:h;e=this.originalPageX+Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=g?!(e-this.offset.click.left<g[0]||e-this.offset.click.left>g[2])?e:!(e-this.offset.click.left< -g[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"); -this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.13"}); -d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var h=d.data(this,"sortable");if(h&&!h.options.disabled){c.sortables.push({instance:h,shouldRevert:h.options.revert});h.refreshPositions();h._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver= -0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs= -c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a, -true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver= -0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor= -a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable"); -if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop= -f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed); -else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b, -a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,h=b.offset.left,g=h+c.helperProportions.width,n=b.offset.top, -o=n+c.helperProportions.height,i=c.snapElements.length-1;i>=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e<h&&h<l+e&&k-e<n&&n<m+e||j-e<h&&h<l+e&&k-e<o&&o<m+e||j-e<g&&g<l+e&&k-e<n&&n<m+e||j-e<g&&g<l+e&&k-e<o&&o<m+e){if(f.snapMode!="inner"){var p=Math.abs(k-o)<=e,q=Math.abs(m-n)<=e,r=Math.abs(j-g)<=e,s=Math.abs(l-h)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k-c.helperProportions.height,left:0}).top-c.margins.top; -if(q)b.position.top=c._convertPositionTo("relative",{top:m,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l}).left-c.margins.left}var t=p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(k-n)<=e;q=Math.abs(m-o)<=e;r=Math.abs(j-h)<=e;s=Math.abs(l-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k,left:0}).top-c.margins.top;if(q)b.position.top= -c._convertPositionTo("relative",{top:m-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[i].snapping&&(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=p||q||r||s||t}else{c.snapElements[i].snapping&& -c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}}); -d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery); -;/* - * jQuery UI Droppable 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Droppables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.mouse.js - * jquery.ui.draggable.js - */ -(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this); -a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&& -this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass); -this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g= -d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop", -a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.13"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height; -switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>= -i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!= -"none";if(c[f].visible){e=="mousedown"&&c[f]._activate.call(c[f],b);c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight}}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem|| -a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e= -d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery); -;/* - * jQuery UI Resizable 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Resizables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element, -_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), -top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= -this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", -nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor== -String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection(); -this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){if(!a.disabled){e(this).removeClass("ui-resizable-autohide");b._handles.show()}},function(){if(!a.disabled)if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy(); -var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a= -false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"}); -this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff= -{width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis]; -if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing= -false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height); -c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size, -d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width= -a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b= -this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)|| -c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left- -c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this, -arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement, -element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.13"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})}; -if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"), -p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options, -c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName), -g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"), -10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0, -top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h; -g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left: -0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position")); -if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&& -!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost== -"string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid; -var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b, -10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery); -;/* - * jQuery UI Selectable 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"), -selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX, -c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting", -c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d= -this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting"); -a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&& -!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d= -e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.13"})})(jQuery); -;/* - * jQuery UI Sortable 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Sortables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable"); -this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a=== -"disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&& -!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top, -left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]}; -this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!= -document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a); -return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top< -b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()- -b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this, -a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0], -e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset(); -c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"): -this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null, -dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")}, -toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers|| -this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection(); -var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)}, -_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith(); -if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), -this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element), -this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&& -this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b= -this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f= -d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")|| -0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out", -a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h- -f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b= -this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width== -""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top= -this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a= -{top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"), -10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"? -document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"), -10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b= -this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&& -this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset(); -var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g- -this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g- -this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0], -this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]= -"";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove", -f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this, -this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop", -a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()}, -_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.13"})})(jQuery); -;/* - * jQuery UI Accordion 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Accordion - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"); -a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); -if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion", -function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a= -this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"); -this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons(); -b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target); -a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+ -c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options; -if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header); -if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(), -e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight|| -e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false", -"aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.13", -animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/); -f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide", -paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery); -;/* - * jQuery UI Autocomplete 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.attr("readonly"))){g= -false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!= -a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)}; -this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&& -a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); -d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&& -b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source= -this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close(); -this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label|| -b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position));this.options.autoFocus&&this.menu.next(new d.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var g=this; -d.each(b,function(c,f){g._renderItem(a,f)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, -"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery); -(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", --1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); -this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b, -this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[d.fn.prop?"prop":"attr"]("scrollHeight")},select:function(e){this._trigger("selected",e,{item:this.active})}})})(jQuery); -;/* - * jQuery UI Button 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Button - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,f=a([]);if(c)f=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return f};a.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button", -i);if(typeof this.options.disabled!=="boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",f="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button", -function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||a(this).removeClass(f)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")}).bind("click.button",function(e){c.disabled&&e.stopImmediatePropagation()});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button", -function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var e=b.element[0];h(e).not(e).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button", -function(){if(c.disabled)return false;a(this).addClass("ui-state-active");g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(e){if(c.disabled)return false;if(e.keyCode==a.ui.keyCode.SPACE||e.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(e){e.keyCode=== -a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type==="radio"){var b=this.element.parents().filter(":last"),c="label[for="+this.element.attr("id")+"]";this.buttonElement=b.find(c);if(!this.buttonElement.length){b=b.length?b.siblings():this.element.siblings();this.buttonElement=b.filter(c); -if(!this.buttonElement.length)this.buttonElement=b.find(c)}this.element.addClass("ui-helper-hidden-accessible");(b=this.element.is(":checked"))&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()); -this.hasTitle||this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed", -true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"), -c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,f=d.primary&&d.secondary,e=[];if(d.primary||d.secondary){if(this.options.text)e.push("ui-button-text-icon"+(f?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){e.push(f?"ui-button-icons-only": -"ui-button-icon-only");this.hasTitle||b.attr("title",c)}}else e.push("ui-button-text-only");b.addClass(e.join(" "))}}});a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end()}, -destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery); -;/* - * jQuery UI Dialog 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, -position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ -b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g), -h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id", -e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); -a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!== -b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+= -1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target=== -f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a, -function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('<button type="button"></button>').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", -handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition, -originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize", -f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "): -[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f); -if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"): -e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a= -this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height- -b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.13",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "), -create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(), -height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight); -b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances, -function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery); -;/* - * jQuery UI Slider 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Slider - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options,c=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f=a.values&&a.values.length||1,e=[];this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+ -this.orientation+" ui-widget ui-widget-content ui-corner-all"+(a.disabled?" ui-slider-disabled ui-disabled":""));this.range=d([]);if(a.range){if(a.range===true){if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}this.range=d("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(a.range==="min"||a.range==="max"?" ui-slider-range-"+a.range:""))}for(var j=c.length;j<f;j+=1)e.push("<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>"); -this.handles=c.add(d(e.join("")).appendTo(b.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle", -g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!b.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");i=b._start(g,l);if(i===false)return}break}m=b.options.step;i=b.options.values&&b.options.values.length? -(h=b.values(l)):(h=b.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=b._valueMin();break;case d.ui.keyCode.END:h=b._valueMax();break;case d.ui.keyCode.PAGE_UP:h=b._trimAlignValue(i+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(i-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===b._valueMax())return;h=b._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===b._valueMin())return;h=b._trimAlignValue(i- -m);break}b._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(g,k);b._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(b){var a=this.options,c,f,e,j,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(a.range===true&&this.values(1)===a.min){g+=1;e=d(this.handles[g])}if(this._start(b,g)===false)return false; -this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();a=e.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-e.width()/2,top:b.pageY-a.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(b){var a= -this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a;if(this.orientation==="horizontal"){a= -this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a); -c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var f;if(this.options.values&&this.options.values.length){f=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>f||a===1&&c<f))c=f;if(c!==this.values(a)){f=this.values();f[a]=c;b=this._trigger("slide",b,{handle:this.handles[a],value:c,values:f});this.values(a?0:1);b!==false&&this.values(a,c,true)}}else if(c!==this.value()){b=this._trigger("slide",b,{handle:this.handles[a],value:c}); -b!==false&&this.value(c)}},_stop:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("stop",b,c)},_change:function(b,a){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("change",b,c)}},value:function(b){if(arguments.length){this.options.value= -this._trimAlignValue(b);this._refreshValue();this._change(null,0)}else return this._value()},values:function(b,a){var c,f,e;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e<c.length;e+=1){c[e]=this._trimAlignValue(f[e]);this._change(null,e)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(b): -this.value();else return this._values()},_setOption:function(b,a){var c,f=0;if(d.isArray(this.options.values))f=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(b){case "disabled":if(a){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation(); -this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<f;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var b=this.options.value;return b=this._trimAlignValue(b)},_values:function(b){var a,c;if(arguments.length){a=this.options.values[b]; -return a=this._trimAlignValue(a)}else{a=this.options.values.slice();for(c=0;c<a.length;c+=1)a[c]=this._trimAlignValue(a[c]);return a}},_trimAlignValue:function(b){if(b<=this._valueMin())return this._valueMin();if(b>=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max}, -_refreshValue:function(){var b=this.options.range,a=this.options,c=this,f=!this._animateOff?a.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},a.animate); -if(h===1)c.range[f?"animate":"css"]({width:e-g+"%"},{queue:false,duration:a.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},a.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:a.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1, -1)[f?"animate":"css"]({width:e+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.13"})})(jQuery); -;/* - * jQuery UI Tabs 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& -e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= -d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| -(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); -this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= -this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); -if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); -this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ -g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", -function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; -this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= --1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; -d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= -d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, -e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); -j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); -if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, -this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, -load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, -"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, -url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.13"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&& -a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery); -;/* - * jQuery UI Progressbar 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); -this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* -this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.13"})})(jQuery); -;/* - * jQuery UI Effects 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/ - */ -jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], -16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, -a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= -a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", -"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, -0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, -211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, -d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easding:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; -f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, -[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.13",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b= -0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}); -c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c, -a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments); -a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%", -"pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d* -((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/= -e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/= -e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/ -h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5* -h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c, -e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery); -;/* - * jQuery UI Effects Blind 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Blind - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","bottom","left","right"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a, -g);b.effects.removeWrapper(a);c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery); -;/* - * jQuery UI Effects Bounce 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Bounce - * - * Depends: - * jquery.effects.core.js - */ -(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","bottom","left","right"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/ -3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a); -b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery); -;/* - * jQuery UI Effects Clip 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Clip - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","bottom","left","right","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position, -c/2)}var h={};h[g.size]=f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Drop 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Drop - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e== -"show"?1:0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Explode 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Explode - * - * Depends: - * jquery.effects.core.js - */ -(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f= -0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ -e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); -;/* - * jQuery UI Effects Fade 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Fold 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], -10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); -;/* - * jQuery UI Effects Highlight 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& -this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Pulsate 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ -(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration, -a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery); -;/* - * jQuery UI Effects Scale 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Scale - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a, -b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity= -1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","bottom","left","right","width","height","overflow","opacity"],g=["position","top","bottom","left","right","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"], -p=c.effects.setMode(a,b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}}; -if(m=="box"||m=="both"){if(d.from.y!=d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a); -a.css("overflow","hidden").css(a.from);if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from); -child.to=c.effects.setTransition(child,f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a, -n?e:g);c.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Shake 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Shake - * - * Depends: - * jquery.effects.core.js - */ -(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","bottom","left","right"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]= -(h=="pos"?"-=":"+=")+e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery); -;/* - * jQuery UI Effects Slide 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Slide - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right"],f=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var g=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var e=d.options.distance||(g=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f=="show")a.css(g,b=="pos"?isNaN(e)?"-"+e:-e:e); -var i={};i[g]=(f=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Transfer 1.8.13 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Transfer - * - * Depends: - * jquery.effects.core.js - */ -(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); -b.dequeue()})})}})(jQuery); -; \ No newline at end of file diff --git a/data/js/jquery-ui-1.8.17.custom.min.js b/data/js/jquery-ui-1.8.17.custom.min.js new file mode 100644 index 0000000000000000000000000000000000000000..70403c813e446af843455f1f88247ca18a2f4ab6 --- /dev/null +++ b/data/js/jquery-ui-1.8.17.custom.min.js @@ -0,0 +1,193 @@ +/*! + * jQuery UI 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */(function(a,b){function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;if(!b.href||!g||f.nodeName.toLowerCase()!=="map")return!1;h=a("img[usemap=#"+g+"]")[0];return!!h&&d(h)}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}a.ui=a.ui||{};a.ui.version||(a.extend(a.ui,{version:"1.8.17",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.each(["Width","Height"],function(c,d){function h(b,c,d,f){a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)});return c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){if(c===b)return g["inner"+d].call(this);return this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){if(typeof b!="number")return g["outer"+d].call(this,b);return this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!!d&&!!a.element[0].parentNode)for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;if(b[d]>0)return!0;b[d]=1,e=b[d]>0,b[d]=0;return e},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}}))})(jQuery);/*! + * jQuery UI Widget 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Widget + */(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}});return d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;e=!f&&g.length?a.extend.apply(null,[!0,e].concat(g)):e;if(f&&e.charAt(0)==="_")return h;f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b){h=f;return!1}}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))});return h}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}this._setOptions(e);return this},_setOptions:function(b){var c=this;a.each(b,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,b){this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b);return this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);this.element.trigger(c,d);return!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||c.isDefaultPrevented())}}})(jQuery);/*! + * jQuery UI Mouse 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Mouse + * + * Depends: + * jquery.ui.widget.js + */(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent")){a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation();return!1}}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(b){if(!c){this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted){b.preventDefault();return!0}}!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0;return!0}},_mouseMove:function(b){if(a.browser.msie&&!(document.documentMode>=9)&&!b.button)return this._mouseUp(b);if(this._mouseStarted){this._mouseDrag(b);return b.preventDefault()}this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b));return!this._mouseStarted},_mouseUp:function(b){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b));return!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);/* + * jQuery UI Position 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Position + */(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1];return this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]!==e){var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0}},top:function(b,c){if(c.at[1]!==e){var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];if(!c||!c.ownerDocument)return null;if(b)return this.each(function(){a.offset.setOffset(this,b)});return h.call(this)}),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&jQuery.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuery);/* + * jQuery UI Draggable 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!!this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy();return this}},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle"))return!1;this.handle=this._getHandle(b);if(!this.handle)return!1;c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")});return!0},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment();if(this._trigger("start",b)===!1){this._clear();return!1}this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.helper.addClass("ui-draggable-dragging"),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b);return!0},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1){this._mouseUp({});return!1}this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";a.ui.ddmanager&&a.ui.ddmanager.drag(this,b);return!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var d=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){d._trigger("stop",b)!==!1&&d._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b);return a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)});return c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute");return d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.left<h[0]&&(f=h[0]+this.offset.click.left),b.pageY-this.offset.click.top<h[1]&&(g=h[1]+this.offset.click.top),b.pageX-this.offset.click.left>h[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.top<h[1]||j-this.offset.click.top>h[3]?j-this.offset.click.top<h[1]?j+c.grid[1]:j-c.grid[1]:j:j;var k=c.grid[0]?this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0]:this.originalPageX;f=h?k-this.offset.click.left<h[0]||k-this.offset.click.left>h[2]?k-this.offset.click.left<h[0]?k+c.grid[0]:k-c.grid[0]:k:k}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(b,c,d){d=d||this._uiHash(),a.ui.plugin.call(this,b,[c,d]),b=="drag"&&(this.positionAbs=this._convertPositionTo("absolute"));return a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(a){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),a.extend(a.ui.draggable,{version:"1.8.17"}),a.ui.plugin.add("draggable","connectToSortable",{start:function(b,c){var d=a(this).data("draggable"),e=d.options,f=a.extend({},c,{item:d.element});d.sortables=[],a(e.connectToSortable).each(function(){var c=a.data(this,"sortable");c&&!c.options.disabled&&(d.sortables.push({instance:c,shouldRevert:c.options.revert}),c.refreshPositions(),c._trigger("activate",b,f))})},stop:function(b,c){var d=a(this).data("draggable"),e=a.extend({},c,{item:d.element});a.each(d.sortables,function(){this.instance.isOver?(this.instance.isOver=0,d.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(b),this.instance.options.helper=this.instance.options._helper,d.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",b,e))})},drag:function(b,c){var d=a(this).data("draggable"),e=this,f=function(b){var c=this.offset.click.top,d=this.offset.click.left,e=this.positionAbs.top,f=this.positionAbs.left,g=b.height,h=b.width,i=b.top,j=b.left;return a.ui.isOver(e+c,f+d,i,j,g,h)};a.each(d.sortables,function(f){this.instance.positionAbs=d.positionAbs,this.instance.helperProportions=d.helperProportions,this.instance.offset.click=d.offset.click,this.instance._intersectsWith(this.instance.containerCache)?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=a(e).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return c.helper[0]},b.target=this.instance.currentItem[0],this.instance._mouseCapture(b,!0),this.instance._mouseStart(b,!0,!0),this.instance.offset.click.top=d.offset.click.top,this.instance.offset.click.left=d.offset.click.left,this.instance.offset.parent.left-=d.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=d.offset.parent.top-this.instance.offset.parent.top,d._trigger("toSortable",b),d.dropped=this.instance.element,d.currentItem=d.element,this.instance.fromOutside=d),this.instance.currentItem&&this.instance._mouseDrag(b)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",b,this.instance._uiHash(this.instance)),this.instance._mouseStop(b,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),d._trigger("fromSortable",b),d.dropped=!1)})}}),a.ui.plugin.add("draggable","cursor",{start:function(b,c){var d=a("body"),e=a(this).data("draggable").options;d.css("cursor")&&(e._cursor=d.css("cursor")),d.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;d._cursor&&a("body").css("cursor",d._cursor)}}),a.ui.plugin.add("draggable","opacity",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("opacity")&&(e._opacity=d.css("opacity")),d.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;d._opacity&&a(c.helper).css("opacity",d._opacity)}}),a.ui.plugin.add("draggable","scroll",{start:function(b,c){var d=a(this).data("draggable");d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"&&(d.overflowOffset=d.scrollParent.offset())},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=!1;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!e.axis||e.axis!="x")d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<e.scrollSensitivity?d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop+e.scrollSpeed:b.pageY-d.overflowOffset.top<e.scrollSensitivity&&(d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop-e.scrollSpeed);if(!e.axis||e.axis!="y")d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<e.scrollSensitivity?d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft+e.scrollSpeed:b.pageX-d.overflowOffset.left<e.scrollSensitivity&&(d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft-e.scrollSpeed)}else{if(!e.axis||e.axis!="x")b.pageY-a(document).scrollTop()<e.scrollSensitivity?f=a(document).scrollTop(a(document).scrollTop()-e.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<e.scrollSensitivity&&(f=a(document).scrollTop(a(document).scrollTop()+e.scrollSpeed));if(!e.axis||e.axis!="y")b.pageX-a(document).scrollLeft()<e.scrollSensitivity?f=a(document).scrollLeft(a(document).scrollLeft()-e.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<e.scrollSensitivity&&(f=a(document).scrollLeft(a(document).scrollLeft()+e.scrollSpeed))}f!==!1&&a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}}),a.ui.plugin.add("draggable","snap",{start:function(b,c){var d=a(this).data("draggable"),e=d.options;d.snapElements=[],a(e.snap.constructor!=String?e.snap.items||":data(draggable)":e.snap).each(function(){var b=a(this),c=b.offset();this!=d.element[0]&&d.snapElements.push({item:this,width:b.outerWidth(),height:b.outerHeight(),top:c.top,left:c.left})})},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=e.snapTolerance,g=c.offset.left,h=g+d.helperProportions.width,i=c.offset.top,j=i+d.helperProportions.height;for(var k=d.snapElements.length-1;k>=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f<g&&g<m+f&&n-f<i&&i<o+f||l-f<g&&g<m+f&&n-f<j&&j<o+f||l-f<h&&h<m+f&&n-f<i&&i<o+f||l-f<h&&h<m+f&&n-f<j&&j<o+f)){d.snapElements[k].snapping&&d.options.snap.release&&d.options.snap.release.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=!1;continue}if(e.snapMode!="inner"){var p=Math.abs(n-j)<=f,q=Math.abs(o-i)<=f,r=Math.abs(l-h)<=f,s=Math.abs(m-g)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n-d.helperProportions.height,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l-d.helperProportions.width}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m}).left-d.margins.left)}var t=p||q||r||s;if(e.snapMode!="outer"){var p=Math.abs(n-i)<=f,q=Math.abs(o-j)<=f,r=Math.abs(l-g)<=f,s=Math.abs(m-h)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o-d.helperProportions.height,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m-d.helperProportions.width}).left-d.margins.left)}!d.snapElements[k].snapping&&(p||q||r||s||t)&&d.options.snap.snap&&d.options.snap.snap.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=p||q||r||s||t}}}),a.ui.plugin.add("draggable","stack",{start:function(b,c){var d=a(this).data("draggable").options,e=a.makeArray(a(d.stack)).sort(function(b,c){return(parseInt(a(b).css("zIndex"),10)||0)-(parseInt(a(c).css("zIndex"),10)||0)});if(!!e.length){var f=parseInt(e[0].style.zIndex)||0;a(e).each(function(a){this.style.zIndex=f+a}),this[0].style.zIndex=f+e.length}}}),a.ui.plugin.add("draggable","zIndex",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("zIndex")&&(e._zIndex=d.css("zIndex")),d.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;d._zIndex&&a(c.helper).css("zIndex",d._zIndex)}})})(jQuery);/* + * jQuery UI Droppable 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Droppables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + * jquery.ui.mouse.js + * jquery.ui.draggable.js + */(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++)b[c]==this&&b.splice(c,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(b,c){b=="accept"&&(this.accept=a.isFunction(c)?c:function(a){return a.is(c)}),a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),c&&this._trigger("activate",b,this.ui(c))},_deactivate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),c&&this._trigger("deactivate",b,this.ui(c))},_over:function(b){var c=a.ui.ddmanager.current;!!c&&(c.currentItem||c.element)[0]!=this.element[0]&&this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",b,this.ui(c)))},_out:function(b){var c=a.ui.ddmanager.current;!!c&&(c.currentItem||c.element)[0]!=this.element[0]&&this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",b,this.ui(c)))},_drop:function(b,c){var d=c||a.ui.ddmanager.current;if(!d||(d.currentItem||d.element)[0]==this.element[0])return!1;var e=!1;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var b=a.data(this,"droppable");if(b.options.greedy&&!b.options.disabled&&b.options.scope==d.options.scope&&b.accept.call(b.element[0],d.currentItem||d.element)&&a.ui.intersect(d,a.extend(b,{offset:b.element.offset()}),b.options.tolerance)){e=!0;return!1}});if(e)return!1;if(this.accept.call(this.element[0],d.currentItem||d.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",b,this.ui(d));return this.element}return!1},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}}),a.extend(a.ui.droppable,{version:"1.8.17"}),a.ui.intersect=function(b,c,d){if(!c.offset)return!1;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,g=(b.positionAbs||b.position.absolute).top,h=g+b.helperProportions.height,i=c.offset.left,j=i+c.proportions.width,k=c.offset.top,l=k+c.proportions.height;switch(d){case"fit":return i<=e&&f<=j&&k<=g&&h<=l;case"intersect":return i<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<j&&k<g+b.helperProportions.height/2&&h-b.helperProportions.height/2<l;case"pointer":var m=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left,n=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top,o=a.ui.isOver(n,m,k,i,c.proportions.height,c.proportions.width);return o;case"touch":return(g>=k&&g<=l||h>=k&&h<=l||g<k&&h>l)&&(e>=i&&e<=j||f>=i&&f<=j||e<i&&f>j);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();droppablesLoop:for(var g=0;g<d.length;g++){if(d[g].options.disabled||b&&!d[g].accept.call(d[g].element[0],b.currentItem||b.element))continue;for(var h=0;h<f.length;h++)if(f[h]==d[g].element[0]){d[g].proportions.height=0;continue droppablesLoop}d[g].visible=d[g].element.css("display")!="none";if(!d[g].visible)continue;e=="mousedown"&&d[g]._activate.call(d[g],c),d[g].offset=d[g].element.offset(),d[g].proportions={width:d[g].element[0].offsetWidth,height:d[g].element[0].offsetHeight}}},drop:function(b,c){var d=!1;a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){!this.options||(!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)&&(d=this._drop.call(this,c)||d),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],b.currentItem||b.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,c)))});return d},dragStart:function(b,c){b.element.parents(":not(body,html)").bind("scroll.droppable",function(){b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)})},drag:function(b,c){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,c),a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var d=a.ui.intersect(b,this,this.options.tolerance),e=!d&&this.isover==1?"isout":d&&this.isover==0?"isover":null;if(!e)return;var f;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");g.length&&(f=a.data(g[0],"droppable"),f.greedyChild=e=="isover"?1:0)}f&&e=="isover"&&(f.isover=0,f.isout=1,f._out.call(f,c)),this[e]=1,this[e=="isout"?"isover":"isout"]=0,this[e=="isover"?"_over":"_out"].call(this,c),f&&e=="isout"&&(f.isout=0,f.isover=1,f._over.call(f,c))}})},dragStop:function(b,c){b.element.parents(":not(body,html)").unbind("scroll.droppable"),b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)}}})(jQuery);/* + * jQuery UI Resizable 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(/relative/.test(this.element.css("position"))&&a.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"}),this.element.wrap(a('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e<d.length;e++){var f=a.trim(d[e]),g="ui-resizable-"+f,h=a('<div class="ui-resizable-handle '+g+'"></div>');/sw|se|ne|nw/.test(f)&&h.css({zIndex:++c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){c.disabled||(a(this).removeClass("ui-resizable-autohide"),b._handles.show())},function(){c.disabled||b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement);return this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),a.browser.opera&&/relative/.test(f.css("position"))&&f.css({position:"relative",top:"auto",left:"auto"}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b);return!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui());return!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove();return!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),e<h.maxWidth&&(h.maxWidth=e),g<h.maxHeight&&(h.maxHeight=g);this._vBoundaries=h},_updateCache:function(a){var b=this.options;this.offset=this.helper.offset(),d(a.left)&&(this.position.left=a.left),d(a.top)&&(this.position.top=a.top),d(a.height)&&(this.size.height=a.height),d(a.width)&&(this.size.width=a.width)},_updateRatio:function(a,b){var c=this.options,e=this.position,f=this.size,g=this.axis;d(a.height)?a.width=a.height*this.aspectRatio:d(a.width)&&(a.height=a.width/this.aspectRatio),g=="sw"&&(a.left=e.left+(f.width-a.width),a.top=null),g=="nw"&&(a.top=e.top+(f.height-a.height),a.left=e.left+(f.width-a.width));return a},_respectSize:function(a,b){var c=this.helper,e=this._vBoundaries,f=this._aspectRatio||b.shiftKey,g=this.axis,h=d(a.width)&&e.maxWidth&&e.maxWidth<a.width,i=d(a.height)&&e.maxHeight&&e.maxHeight<a.height,j=d(a.width)&&e.minWidth&&e.minWidth>a.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null);return a},_proportionallyResize:function(){var b=this.options;if(!!this._proportionallyResizeElements.length){var c=this.helper||this.element;for(var d=0;d<this._proportionallyResizeElements.length;d++){var e=this._proportionallyResizeElements[d];if(!this.borderDif){var f=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],g=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];this.borderDif=a.map(f,function(a,b){var c=parseInt(a,10)||0,d=parseInt(g[b],10)||0;return c+d})}if(a.browser.msie&&(!!a(c).is(":hidden")||!!a(c).parents(":hidden").length))continue;e.css({height:c.height()-this.borderDif[0]-this.borderDif[2]||0,width:c.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var b=this.element,c=this.options;this.elementOffset=b.offset();if(this._helper){this.helper=this.helper||a('<div style="overflow:hidden;"></div>');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.17"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10),position:b.css("position")})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,e){a(b).each(function(){var b=a(this),f=a(this).data("resizable-alsoresize"),g={},i=e&&e.length?e:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(i,function(a,b){var c=(f[b]||0)+(h[b]||0);c&&c>=0&&(g[b]=c||null)}),a.browser.opera&&/relative/.test(b.css("position"))&&(d._revertToRelativePosition=!0,b.css({position:"absolute",top:"auto",left:"auto"})),b.css(g)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.css({position:b.data("resizable-alsoresize").position})})};d._revertToRelativePosition&&(d._revertToRelativePosition=!1,typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)),a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!!i){e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/e.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*e.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery);/* + * jQuery UI Selectable 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy();return this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(!this.options.disabled){var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element});return!1}})}},_mouseDrag:function(b){var c=this;this.dragged=!0;if(!this.options.disabled){var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!!i&&i.element!=c.element[0]){var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.right<e||i.top>h||i.bottom<f):d.tolerance=="fit"&&(j=i.left>e&&i.right<g&&i.top>f&&i.bottom<h),j?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,c._trigger("selecting",b,{selecting:i.element}))):(i.selecting&&((b.metaKey||b.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),c._trigger("unselecting",b,{unselecting:i.element}))),i.selected&&!b.metaKey&&!b.ctrlKey&&!i.startselected&&(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,c._trigger("unselecting",b,{unselecting:i.element})))}});return!1}},_mouseStop:function(b){var c=this;this.dragged=!1;var d=this.options;a(".ui-unselecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-unselecting"),d.unselecting=!1,d.startselected=!1,c._trigger("unselected",b,{unselected:d.element})}),a(".ui-selecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected"),d.selecting=!1,d.selected=!0,d.startselected=!0,c._trigger("selected",b,{selected:d.element})}),this._trigger("stop",b),this.helper.remove();return!1}}),a.extend(a.ui.selectable,{version:"1.8.17"})})(jQuery);/* + * jQuery UI Sortable 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Sortables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f){e=a(this);return!1}});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}this.currentItem=e,this._removeCurrentsFromItems();return!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b);return!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity?this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop+c.scrollSpeed:b.pageY-this.overflowOffset.top<c.scrollSensitivity&&(this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop-c.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity?this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft+c.scrollSpeed:b.pageX-this.overflowOffset.left<c.scrollSensitivity&&(this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft-c.scrollSpeed)):(b.pageY-a(document).scrollTop()<c.scrollSensitivity?d=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<c.scrollSensitivity&&(d=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed)),b.pageX-a(document).scrollLeft()<c.scrollSensitivity?d=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity&&(d=a(document).scrollLeft(a(document).scrollLeft()+c.scrollSpeed))),d!==!1&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var e=this.items.length-1;e>=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs;return!1},_mouseStop:function(b,c){if(!!b){a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1}},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem));return this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"=");return d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")});return d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+j<i&&b+k>f&&b+k<g;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?l:f<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<g&&h<d+this.helperProportions.height/2&&e-this.helperProportions.height/2<i},_intersectsWithPointer:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left,b.width),e=c&&d,f=this._getDragVerticalDirection(),g=this._getDragHorizontalDirection();if(!e)return!1;return this.floating?g&&g=="right"||f=="down"?2:1:f&&(f=="down"?2:1)},_intersectsWithSides:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top+b.height/2,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left+b.width/2,b.width),e=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();return this.floating&&f?f=="right"&&d||f=="left"&&!d:e&&(e=="down"&&c||e=="up"&&!c)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a),this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(b){this.items=[],this.containers=[this];var c=this.items,d=this,e=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]],f=this._connectWith();if(f)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i<m;i++){var n=a(l[i]);n.data(this.widgetName+"-item",k),c.push({item:n,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var c=this.items.length-1;c>=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];e||(b.style.visibility="hidden");return b},update:function(a,b){if(!e||!!d.forcePlaceholderSize)b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!!c)if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.items[i][this.containers[d].floating?"left":"top"];Math.abs(j-h)<f&&(f=Math.abs(j-h),g=this.items[i])}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height());return d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.left<this.containment[0]&&(f=this.containment[0]+this.offset.click.left),b.pageY-this.offset.click.top<this.containment[1]&&(g=this.containment[1]+this.offset.click.top),b.pageX-this.offset.click.left>this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.top<this.containment[1]||h-this.offset.click.top>this.containment[3]?h-this.offset.click.top<this.containment[1]?h+c.grid[1]:h-c.grid[1]:h:h;var i=this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0];f=this.containment?i-this.offset.click.left<this.containment[0]||i-this.offset.click.left>this.containment[2]?i-this.offset.click.left<this.containment[0]?i+c.grid[0]:i-c.grid[0]:i:i}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var e=this,f=this.counter;window.setTimeout(function(){f==e.counter&&e.refreshPositions(!d)},0)},_clear:function(b,c){this.reverting=!1;var d=[],e=this;!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var f in this._storedCSS)if(this._storedCSS[f]=="auto"||this._storedCSS[f]=="static")this._storedCSS[f]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!c&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!c&&d.push(function(a){this._trigger("update",a,this._uiHash())});if(!a.ui.contains(this.element[0],this.currentItem[0])){c||d.push(function(a){this._trigger("remove",a,this._uiHash())});for(var f=this.containers.length-1;f>=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return!1}c||this._trigger("beforeStop",b,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!c){for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}this.fromOutside=!1;return!0},_trigger:function(){a.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(b){var c=b||this;return{helper:c.helper,placeholder:c.placeholder||a([]),position:c.position,originalPosition:c.originalPosition,offset:c.positionAbs,item:c.currentItem,sender:b?b.element:null}}}),a.extend(a.ui.sortable,{version:"1.8.17"})})(jQuery);/* + * jQuery UI Accordion 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Accordion + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){c.disabled||a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){c.disabled||a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){c.disabled||a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){c.disabled||a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("<span></span>").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");(b.autoHeight||b.fillHeight)&&c.css("height","");return a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(!(this.options.disabled||b.altKey||b.ctrlKey)){var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}if(f){a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus();return!1}return!0}},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];this._clickHandler({target:b},b);return this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(!d.disabled){if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return}},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!!g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;this.running||(this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data))}}),a.extend(a.ui.accordion,{version:"1.8.17",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size())b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);else{if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})}},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})})(jQuery);/* + * jQuery UI Autocomplete 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + * jquery.ui.position.js + */(function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!b.options.disabled&&!b.element.propAttr("readOnly")){d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._move("previous",c),c.preventDefault();break;case e.DOWN:b._move("next",c),c.preventDefault();break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){b.options.disabled||(b.selectedItem=null,b.previous=b.element.val())}).bind("blur.autocomplete",function(a){b.options.disabled||(clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150))}),this._initSource(),this.response=function(){return b._response.apply(b,arguments)},this.menu=a("<ul></ul>").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,d,e;a.isArray(this.options.source)?(d=this.options.source,this.source=function(b,c){c(a.ui.autocomplete.filter(d,b.term))}):typeof this.options.source=="string"?(e=this.options.source,this.source=function(d,f){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:e,data:d,dataType:"json",autocompleteRequest:++c,success:function(a,b){this.autocompleteRequest===c&&f(a)},error:function(){this.autocompleteRequest===c&&f([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==!1)return this._search(a)},_search:function(a){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.source({term:a},this.response)},_response:function(a){!this.options.disabled&&a&&a.length?(a=this._normalize(a),this._suggest(a),this._trigger("open")):this.close(),this.pending--,this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing),this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.deactivate(),this._trigger("close",a))},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(b){if(b.length&&b[0].label&&b[0].value)return b;return a.map(b,function(b){if(typeof b=="string")return{label:b,value:b};return a.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(b){var c=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(c,b),this.menu.deactivate(),this.menu.refresh(),c.show(),this._resizeMenu(),c.position(a.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next(new a.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(b,c){var d=this;a.each(c,function(a,c){d._renderItem(b,c)})},_renderItem:function(b,c){return a("<li></li>").data("item.autocomplete",c).append(a("<a></a>").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible"))this.search(null,b);else{if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)}},widget:function(){return this.menu.element}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})})(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){!a(c.target).closest(".ui-menu-item a").length||(c.preventDefault(),b.select(c))}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){!this.active||(this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null)},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active)this.activate(c,this.element.children(b));else{var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))}},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10}),result.length||(result=this.element.children(".ui-menu-item:first")),this.activate(b,result)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[a.fn.prop?"prop":"attr"]("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})}(jQuery);/* + * jQuery UI Button 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Button + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */(function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form}));return e};a.widget("ui.button",{options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",j),typeof this.options.disabled!="boolean"&&(this.options.disabled=this.element.propAttr("disabled")),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var b=this,h=this.options,i=this.type==="checkbox"||this.type==="radio",l="ui-state-hover"+(i?"":" ui-state-active"),m="ui-state-focus";h.label===null&&(h.label=this.buttonElement.html()),this.element.is(":disabled")&&(h.disabled=!0),this.buttonElement.addClass(g).attr("role","button").bind("mouseenter.button",function(){h.disabled||(a(this).addClass("ui-state-hover"),this===c&&a(this).addClass("ui-state-active"))}).bind("mouseleave.button",function(){h.disabled||a(this).removeClass(l)}).bind("click.button",function(a){h.disabled&&(a.preventDefault(),a.stopImmediatePropagation())}),this.element.bind("focus.button",function(){b.buttonElement.addClass(m)}).bind("blur.button",function(){b.buttonElement.removeClass(m)}),i&&(this.element.bind("change.button",function(){f||b.refresh()}),this.buttonElement.bind("mousedown.button",function(a){h.disabled||(f=!1,d=a.pageX,e=a.pageY)}).bind("mouseup.button",function(a){!h.disabled&&(d!==a.pageX||e!==a.pageY)&&(f=!0)})),this.type==="checkbox"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).toggleClass("ui-state-active"),b.buttonElement.attr("aria-pressed",b.element[0].checked)}):this.type==="radio"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).addClass("ui-state-active"),b.buttonElement.attr("aria-pressed","true");var c=b.element[0];k(c).not(c).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown.button",function(){if(h.disabled)return!1;a(this).addClass("ui-state-active"),c=this,a(document).one("mouseup",function(){c=null})}).bind("mouseup.button",function(){if(h.disabled)return!1;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(b){if(h.disabled)return!1;(b.keyCode==a.ui.keyCode.SPACE||b.keyCode==a.ui.keyCode.ENTER)&&a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(b){b.keyCode===a.ui.keyCode.SPACE&&a(this).click()})),this._setOption("disabled",h.disabled),this._resetButton()},_determineButtonType:function(){this.element.is(":checkbox")?this.type="checkbox":this.element.is(":radio")?this.type="radio":this.element.is("input")?this.type="input":this.type="button";if(this.type==="checkbox"||this.type==="radio"){var a=this.element.parents().filter(":last"),b="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(b),this.buttonElement.length||(a=a.length?a.siblings():this.element.siblings(),this.buttonElement=a.filter(b),this.buttonElement.length||(this.buttonElement=a.find(b))),this.element.addClass("ui-helper-hidden-accessible");var c=this.element.is(":checked");c&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.attr("aria-pressed",c)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(g+" "+h+" "+i).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title"),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);b==="disabled"?c?this.element.propAttr("disabled",!0):this.element.propAttr("disabled",!1):this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b),this.type==="radio"?k(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):this.type==="checkbox"&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass(i),c=a("<span></span>",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>"),d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>"),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})})(jQuery);/* + * jQuery UI Dialog 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + * jquery.ui.button.js + * jquery.ui.draggable.js + * jquery.ui.mouse.js + * jquery.ui.position.js + * jquery.ui.resizable.js + */(function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},f=a.attrFn||{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0,click:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||" ",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("<div></div>")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){b.close(a);return!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("<span></span>")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("<span></span>").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1!==c._trigger("beforeClose",b)){c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d);return c}},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;if(e.modal&&!b||!e.stack&&!e.modal)return d._trigger("focus",c);e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c);return d},open:function(){if(!this._isOpen){var b=this,c=b.options,d=b.uiDialog;b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode===a.ui.keyCode.TAB){var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey){d.focus(1);return!1}if(b.target===d[0]&&b.shiftKey){e.focus(1);return!1}}}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open");return b}},_createButtons:function(b){var c=this,d=!1,e=a("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=a("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('<button type="button"></button>').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(g);a.each(d,function(a,b){a!=="click"&&(a in f?e[a](b):e.attr(a,b))}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||" "))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.17",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");b||(this.uuid+=1,b=this.uuid);return"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()<a.ui.dialog.overlay.maxZ)return!1})},1),a(document).bind("keydown.dialog-overlay",function(c){b.options.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}),a(window).bind("resize.dialog-overlay",a.ui.dialog.overlay.resize));var c=(this.oldInstances.pop()||a("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});a.fn.bgiframe&&c.bgiframe(),this.instances.push(c);return c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;if(a.browser.msie&&a.browser.version<7){b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return b<c?a(window).height()+"px":b+"px"}return a(document).height()+"px"},width:function(){var b,c;if(a.browser.msie){b=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),c=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return b<c?a(window).width()+"px":b+"px"}return a(document).width()+"px"},resize:function(){var b=a([]);a.each(a.ui.dialog.overlay.instances,function(){b=b.add(this)}),b.css({width:0,height:0}).css({width:a.ui.dialog.overlay.width(),height:a.ui.dialog.overlay.height()})}}),a.extend(a.ui.dialog.overlay.prototype,{destroy:function(){a.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);/* + * jQuery UI Slider 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=!0,f=a(this).data("index.ui-slider-handle"),g,h,i,j;if(!b.options.disabled){switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:e=!1;if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),g=b._start(d,f);if(g===!1)return}}j=b.options.step,b.options.values&&b.options.values.length?h=i=b.values(f):h=i=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:i=b._valueMin();break;case a.ui.keyCode.END:i=b._valueMax();break;case a.ui.keyCode.PAGE_UP:i=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:i=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(h===b._valueMax())return;i=b._trimAlignValue(h+j);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(h===b._valueMin())return;i=b._trimAlignValue(h-j)}b._slide(d,f,i);return e}}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy();return this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;if(c.disabled)return!1;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i);if(j===!1)return!1;this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0;return!0},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);this._slide(a,this._handleIndex,c);return!1},_mouseStop:function(a){this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1;return!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e;return this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values());return this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length)this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);else return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1)this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);else{if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()}},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;a=this._trimAlignValue(a);return a},_values:function(a){var b,c,d;if(arguments.length){b=this.options.values[a],b=this._trimAlignValue(b);return b}c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;Math.abs(c)*2>=b&&(d+=c>0?b:-b);return parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.17"})})(jQuery);/* + * jQuery UI Tabs 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */(function(a,b){function f(){return++d}function e(){return++c}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash){e.selected=a;return!1}}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1){this.blur();return!1}e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected")){e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur();return!1}if(!f.length){e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur();return!1}}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$="+a+"]")));return a},destroy:function(){var b=this.options;this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie);return this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e]));return this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1<this.anchors.length?1:-1)),c.disabled=a.map(a.grep(c.disabled,function(a,c){return a!=b}),function(a,c){return a>=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0]));return this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a])));return this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;this.anchors.eq(a).trigger(this.options.event+".tabs");return this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup();return this},url:function(a,b){this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b);return this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.17"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a<c.anchors.length?a:0)},a),b&&b.stopPropagation()}),f=c._unrotate||(c._unrotate=b?function(a){t=d.selected,e()}:function(a){a.clientX&&c.rotate(null)});a?(this.element.bind("tabsshow",e),this.anchors.bind(d.event+".tabs",f),e()):(clearTimeout(c.rotation),this.element.unbind("tabsshow",e),this.anchors.unbind(d.event+".tabs",f),delete this._rotate,delete this._unrotate);return this}})})(jQuery);/* + * jQuery UI Progressbar 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===b)return this._value();this._setOption("value",a);return this},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;typeof a!="number"&&(a=0);return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.17"})})(jQuery); \ No newline at end of file diff --git a/data/js/jquery.cookie.js b/data/js/jquery.cookie.js index 79317f743963cac9d4d82dd3574d32e6d994995c..dc031611f2c0c3c9b70b7cfa9e317f5f17ccacd7 100644 --- a/data/js/jquery.cookie.js +++ b/data/js/jquery.cookie.js @@ -1,96 +1,47 @@ /** - * Cookie plugin + * jQuery Cookie plugin * - * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Copyright (c) 2010 Klaus Hartl (stilbuero.de) * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * */ +(function($) { + $.cookie = function(key, value, options) { -/** - * Create a cookie with the given name and value and other optional parameters. - * - * @example $.cookie('the_cookie', 'the_value'); - * @desc Set the value of a cookie. - * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); - * @desc Create a cookie with all available options. - * @example $.cookie('the_cookie', 'the_value'); - * @desc Create a session cookie. - * @example $.cookie('the_cookie', null); - * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain - * used when the cookie was set. - * - * @param String name The name of the cookie. - * @param String value The value of the cookie. - * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. - * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. - * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. - * If set to null or omitted, the cookie will be a session cookie and will not be retained - * when the the browser exits. - * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). - * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). - * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will - * require a secure protocol (like HTTPS). - * @type undefined - * - * @name $.cookie - * @cat Plugins/Cookie - * @author Klaus Hartl/klaus.hartl@stilbuero.de - */ + // key and at least value given, set cookie... + if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) { + options = $.extend({}, options); -/** - * Get the value of a cookie with the given name. - * - * @example $.cookie('the_cookie'); - * @desc Get the value of a cookie. - * - * @param String name The name of the cookie. - * @return The value of the cookie. - * @type String - * - * @name $.cookie - * @cat Plugins/Cookie - * @author Klaus Hartl/klaus.hartl@stilbuero.de - */ -jQuery.cookie = function(name, value, options) { - if (typeof value != 'undefined') { // name and value given, set cookie - options = options || {}; - if (value === null) { - value = ''; - options.expires = -1; - } - var expires = ''; - if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { - var date; - if (typeof options.expires == 'number') { - date = new Date(); - date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); - } else { - date = options.expires; + if (value === null || value === undefined) { + options.expires = -1; } - expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE - } - // CAUTION: Needed to parenthesize options.path and options.domain - // in the following expressions, otherwise they evaluate to undefined - // in the packed version for some reason... - var path = options.path ? '; path=' + (options.path) : ''; - var domain = options.domain ? '; domain=' + (options.domain) : ''; - var secure = options.secure ? '; secure' : ''; - document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); - } else { // only name given, get cookie - var cookieValue = null; - if (document.cookie && document.cookie != '') { - var cookies = document.cookie.split(';'); - for (var i = 0; i < cookies.length; i++) { - var cookie = jQuery.trim(cookies[i]); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) == (name + '=')) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); } + + value = String(value); + + return (document.cookie = [ + encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // key and possibly options given, get cookie... + options = value || {}; + var decode = options.raw ? function(s) { return s; } : decodeURIComponent; + + var pairs = document.cookie.split('; '); + for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) { + if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined } - return cookieValue; - } -}; + return null; + }; +})(jQuery); diff --git a/data/js/jquery.form-2.69.js b/data/js/jquery.form-2.92.js similarity index 69% rename from data/js/jquery.form-2.69.js rename to data/js/jquery.form-2.92.js index 3ad71f891d3338cd39ba4b69b23d0c3d43bb3992..6425e412f89203773f253b55adf137572e44ae7d 100644 --- a/data/js/jquery.form-2.69.js +++ b/data/js/jquery.form-2.92.js @@ -1,12 +1,12 @@ /*! * jQuery Form Plugin - * version: 2.69 (06-APR-2011) + * version: 2.92 (22-NOV-2011) * @requires jQuery v1.3.2 or later * * Examples and documentation at: http://malsup.com/jquery/form/ * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html */ ;(function($) { @@ -49,23 +49,26 @@ $.fn.ajaxSubmit = function(options) { log('ajaxSubmit: skipping submit process - no element selected'); return this; } + + var method, action, url, $form = this; if (typeof options == 'function') { options = { success: options }; } - var action = this.attr('action'); - var url = (typeof action === 'string') ? $.trim(action) : ''; + method = this.attr('method'); + action = this.attr('action'); + url = (typeof action === 'string') ? $.trim(action) : ''; + url = url || window.location.href || ''; if (url) { // clean url (don't include hash vaue) url = (url.match(/^([^#]+)/)||[])[1]; } - url = url || window.location.href || ''; options = $.extend(true, { url: url, success: $.ajaxSettings.success, - type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57) + type: method || 'GET', iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' }, options); @@ -84,21 +87,15 @@ $.fn.ajaxSubmit = function(options) { return this; } - var n,v,a = this.formToArray(options.semantic); + var traditional = options.traditional; + if ( traditional === undefined ) { + traditional = $.ajaxSettings.traditional; + } + + var qx,n,v,a = this.formToArray(options.semantic); if (options.data) { options.extraData = options.data; - for (n in options.data) { - if(options.data[n] instanceof Array) { - for (var k in options.data[n]) { - a.push( { name: n, value: options.data[n][k] } ); - } - } - else { - v = options.data[n]; - v = $.isFunction(v) ? v() : v; // if value is fn, invoke it - a.push( { name: n, value: v } ); - } - } + qx = $.param(options.data, traditional); } // give pre-submit callback an opportunity to abort the submit @@ -114,8 +111,10 @@ $.fn.ajaxSubmit = function(options) { return this; } - var q = $.param(a); - + var q = $.param(a, traditional); + if (qx) { + q = ( q ? (q + '&' + qx) : qx ); + } if (options.type.toUpperCase() == 'GET') { options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; options.data = null; // data is null for 'get' @@ -124,12 +123,12 @@ $.fn.ajaxSubmit = function(options) { options.data = q; // data is the query string for 'post' } - var $form = this, callbacks = []; + var callbacks = []; if (options.resetForm) { callbacks.push(function() { $form.resetForm(); }); } if (options.clearForm) { - callbacks.push(function() { $form.clearForm(); }); + callbacks.push(function() { $form.clearForm(options.includeHidden); }); } // perform a load on the target only if dataType is not provided @@ -145,41 +144,100 @@ $.fn.ajaxSubmit = function(options) { } options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg - var context = options.context || options; // jQuery 1.4+ supports scope context + var context = options.context || options; // jQuery 1.4+ supports scope context for (var i=0, max=callbacks.length; i < max; i++) { callbacks[i].apply(context, [data, status, xhr || $form, $form]); } }; // are there files to upload? - var fileInputs = $('input:file', this).length > 0; + var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113) + var hasFileInputs = fileInputs.length > 0; var mp = 'multipart/form-data'; var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); + var fileAPI = !!(hasFileInputs && fileInputs.get(0).files && window.FormData); + log("fileAPI :" + fileAPI); + var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; + // options.iframe allows user to force iframe mode // 06-NOV-09: now defaulting to iframe mode if file input is detected - if (options.iframe !== false && (fileInputs || options.iframe || multipart)) { - // hack to fix Safari hang (thanks to Tim Molendijk for this) - // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d - if (options.closeKeepAlive) { - $.get(options.closeKeepAlive, fileUpload); - } - else { - fileUpload(); + if (options.iframe !== false && (options.iframe || shouldUseFrame)) { + // hack to fix Safari hang (thanks to Tim Molendijk for this) + // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d + if (options.closeKeepAlive) { + $.get(options.closeKeepAlive, function() { + fileUploadIframe(a); + }); } - } - else { + else { + fileUploadIframe(a); + } + } + else if ((hasFileInputs || multipart) && fileAPI) { + options.progress = options.progress || $.noop; + fileUploadXhr(a); + } + else { $.ajax(options); - } + } + + // fire 'notify' event + this.trigger('form-submit-notify', [this, options]); + return this; + + // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) + function fileUploadXhr(a) { + var formdata = new FormData(); + + for (var i=0; i < a.length; i++) { + if (a[i].type == 'file') + continue; + formdata.append(a[i].name, a[i].value); + } - // fire 'notify' event - this.trigger('form-submit-notify', [this, options]); - return this; + $form.find('input:file:enabled').each(function(){ + var name = $(this).attr('name'), files = this.files; + if (name) { + for (var i=0; i < files.length; i++) + formdata.append(name, files[i]); + } + }); + options.data = null; + var _beforeSend = options.beforeSend; + options.beforeSend = function(xhr, options) { + options.data = formdata; + if (xhr.upload) { // unfortunately, jQuery doesn't expose this prop (http://bugs.jquery.com/ticket/10190) + xhr.upload.onprogress = function(event) { + options.progress(event.position, event.total); + } + } + if (_beforeSend) + _beforeSend.call(options, xhr, options); + } + $.ajax(options); + } // private function for handling file uploads (hat tip to YAHOO!) - function fileUpload() { - var form = $form[0]; + function fileUploadIframe(a) { + var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; + var useProp = !!$.fn.prop; + + if (a) { + if ( useProp ) { + // ensure that every serialized input is still enabled + for (i=0; i < a.length; i++) { + el = $(form[a[i].name]); + el.prop('disabled', false); + } + } else { + for (i=0; i < a.length; i++) { + el = $(form[a[i].name]); + el.removeAttr('disabled'); + } + }; + } if ($(':input[name=submit],:input[id=submit]', form).length) { // if there is an input with a name or id of 'submit' then we won't be @@ -188,15 +246,25 @@ $.fn.ajaxSubmit = function(options) { return; } - var s = $.extend(true, {}, $.ajaxSettings, options); + s = $.extend(true, {}, $.ajaxSettings, options); s.context = s.context || s; - var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id; - var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />'); - var io = $io[0]; + id = 'jqFormIO' + (new Date().getTime()); + if (s.iframeTarget) { + $io = $(s.iframeTarget); + n = $io.attr('name'); + if (n == null) + $io.attr('name', id); + else + id = n; + } + else { + $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); + $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); + } + io = $io[0]; - $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); - var xhr = { // mock object + xhr = { // mock object aborted: 0, responseText: null, responseXML: null, @@ -205,19 +273,19 @@ $.fn.ajaxSubmit = function(options) { getAllResponseHeaders: function() {}, getResponseHeader: function() {}, setRequestHeader: function() {}, - abort: function() { - log('aborting upload...'); - var e = 'aborted'; + abort: function(status) { + var e = (status === 'timeout' ? 'timeout' : 'aborted'); + log('aborting upload... ' + e); this.aborted = 1; $io.attr('src', s.iframeSrc); // abort op in progress xhr.error = e; - s.error && s.error.call(s.context, xhr, 'error', e); + s.error && s.error.call(s.context, xhr, e, status); g && $.event.trigger("ajaxError", [xhr, s, e]); - s.complete && s.complete.call(s.context, xhr, 'error'); + s.complete && s.complete.call(s.context, xhr, e); } }; - var g = s.global; + g = s.global; // trigger ajax global events so that activity/block indicators work like normal if (g && ! $.active++) { $.event.trigger("ajaxStart"); @@ -227,7 +295,7 @@ $.fn.ajaxSubmit = function(options) { } if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { - if (s.global) { + if (s.global) { $.active--; } return; @@ -236,12 +304,10 @@ $.fn.ajaxSubmit = function(options) { return; } - var timedOut = 0; - // add submitting element to data if we know it - var sub = form.clk; + sub = form.clk; if (sub) { - var n = sub.name; + n = sub.name; if (n && !sub.disabled) { s.extraData = s.extraData || {}; s.extraData[n] = sub.value; @@ -251,6 +317,22 @@ $.fn.ajaxSubmit = function(options) { } } } + + var CLIENT_TIMEOUT_ABORT = 1; + var SERVER_ABORT = 2; + + function getDoc(frame) { + var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document; + return doc; + } + + // Rails CSRF hack (thanks to Yvan BARTH�LEMY) + var csrf_token = $('meta[name=csrf-token]').attr('content'); + var csrf_param = $('meta[name=csrf-param]').attr('content'); + if (csrf_param && csrf_token) { + s.extraData = s.extraData || {}; + s.extraData[csrf_param] = csrf_token; + } // take a breath so that pending repaints get some cpu time before the upload starts function doSubmit() { @@ -259,15 +341,15 @@ $.fn.ajaxSubmit = function(options) { // update form attrs in IE friendly way form.setAttribute('target',id); - if (form.getAttribute('method') != 'POST') { + if (!method) { form.setAttribute('method', 'POST'); } - if (form.getAttribute('action') != s.url) { + if (a != s.url) { form.setAttribute('action', s.url); } // ie borks in some cases when setting encoding - if (! s.skipEncodingOverride) { + if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { $form.attr({ encoding: 'multipart/form-data', enctype: 'multipart/form-data' @@ -276,7 +358,23 @@ $.fn.ajaxSubmit = function(options) { // support timout if (s.timeout) { - setTimeout(function() { timedOut = true; cb(); }, s.timeout); + timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); + } + + // look for server aborts + function checkState() { + try { + var state = getDoc(io).readyState; + log('state = ' + state); + if (state.toLowerCase() == 'uninitialized') + setTimeout(checkState,50); + } + catch(e) { + log('Server abort: ' , e, ' (', e.name, ')'); + cb(SERVER_ABORT); + timeoutHandle && clearTimeout(timeoutHandle); + timeoutHandle = undefined; + } } // add "extra" data to form if provided in options @@ -285,14 +383,17 @@ $.fn.ajaxSubmit = function(options) { if (s.extraData) { for (var n in s.extraData) { extraInputs.push( - $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />') + $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n]) .appendTo(form)[0]); } } - // add iframe to doc and submit the form - $io.appendTo('body'); - io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false); + if (!s.iframeTarget) { + // add iframe to doc and submit the form + $io.appendTo('body'); + io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false); + } + setTimeout(checkState,15); form.submit(); } finally { @@ -313,23 +414,37 @@ $.fn.ajaxSubmit = function(options) { else { setTimeout(doSubmit, 10); // this lets dom updates render } - - var data, doc, domCheckCount = 50; - function cb() { - if (xhr.aborted) { + var data, doc, domCheckCount = 50, callbackProcessed; + + function cb(e) { + if (xhr.aborted || callbackProcessed) { return; } - - var doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document; + try { + doc = getDoc(io); + } + catch(ex) { + log('cannot access response document: ', ex); + e = SERVER_ABORT; + } + if (e === CLIENT_TIMEOUT_ABORT && xhr) { + xhr.abort('timeout'); + return; + } + else if (e == SERVER_ABORT && xhr) { + xhr.abort('server abort'); + return; + } + if (!doc || doc.location.href == s.iframeSrc) { // response not received yet if (!timedOut) return; } - io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false); + io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false); - var ok = true; + var status = 'success', errMsg; try { if (timedOut) { throw 'timeout'; @@ -351,69 +466,99 @@ $.fn.ajaxSubmit = function(options) { } //log('response detected'); - xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null; + var docRoot = doc.body ? doc.body : doc.documentElement; + xhr.responseText = docRoot ? docRoot.innerHTML : null; xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; + if (isXml) + s.dataType = 'xml'; xhr.getResponseHeader = function(header){ var headers = {'content-type': s.dataType}; return headers[header]; }; + // support for XHR 'status' & 'statusText' emulation : + if (docRoot) { + xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; + xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; + } - var scr = /(json|script)/.test(s.dataType); + var dt = (s.dataType || '').toLowerCase(); + var scr = /(json|script|text)/.test(dt); if (scr || s.textarea) { // see if user embedded response in textarea var ta = doc.getElementsByTagName('textarea')[0]; if (ta) { xhr.responseText = ta.value; + // support for XHR 'status' & 'statusText' emulation : + xhr.status = Number( ta.getAttribute('status') ) || xhr.status; + xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; } else if (scr) { // account for browsers injecting pre around json response var pre = doc.getElementsByTagName('pre')[0]; var b = doc.getElementsByTagName('body')[0]; if (pre) { - xhr.responseText = pre.textContent; + xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; } else if (b) { - xhr.responseText = b.innerHTML; + xhr.responseText = b.textContent ? b.textContent : b.innerText; } - } + } } - else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) { + else if (dt == 'xml' && !xhr.responseXML && xhr.responseText != null) { xhr.responseXML = toXml(xhr.responseText); } - - data = httpData(xhr, s.dataType, s); + + try { + data = httpData(xhr, dt, s); + } + catch (e) { + status = 'parsererror'; + xhr.error = errMsg = (e || status); + } } - catch(e){ - log('error caught:',e); - ok = false; - xhr.error = e; - s.error && s.error.call(s.context, xhr, 'error', e); - g && $.event.trigger("ajaxError", [xhr, s, e]); + catch (e) { + log('error caught: ',e); + status = 'error'; + xhr.error = errMsg = (e || status); } - + if (xhr.aborted) { log('upload aborted'); - ok = false; + status = null; + } + + if (xhr.status) { // we've set xhr.status + status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; } // ordering of these callbacks/triggers is odd, but that's how $.ajax does it - if (ok) { + if (status === 'success') { s.success && s.success.call(s.context, data, 'success', xhr); g && $.event.trigger("ajaxSuccess", [xhr, s]); } - + else if (status) { + if (errMsg == undefined) + errMsg = xhr.statusText; + s.error && s.error.call(s.context, xhr, status, errMsg); + g && $.event.trigger("ajaxError", [xhr, s, errMsg]); + } + g && $.event.trigger("ajaxComplete", [xhr, s]); if (g && ! --$.active) { $.event.trigger("ajaxStop"); } - - s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error'); + + s.complete && s.complete.call(s.context, xhr, status); + + callbackProcessed = true; + if (s.timeout) + clearTimeout(timeoutHandle); // clean up setTimeout(function() { - $io.removeData('form-plugin-onload'); - $io.remove(); + if (!s.iframeTarget) + $io.remove(); xhr.responseXML = null; }, 100); } @@ -432,8 +577,9 @@ $.fn.ajaxSubmit = function(options) { var parseJSON = $.parseJSON || function(s) { return window['eval']('(' + s + ')'); }; - + var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 + var ct = xhr.getResponseHeader('content-type') || '', xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, data = xml ? xhr.responseXML : xhr.responseText; @@ -486,7 +632,7 @@ $.fn.ajaxForm = function(options) { log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); return this; } - + return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) { if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed e.preventDefault(); @@ -550,7 +696,7 @@ $.fn.formToArray = function(semantic) { if (!els) { return a; } - + var i,j,n,v,el,max,jmax; for(i=0, max=els.length; i < max; i++) { el = els[i]; @@ -562,7 +708,7 @@ $.fn.formToArray = function(semantic) { if (semantic && form.clk && el.type == "image") { // handle image inputs on the fly when semantic == true if(!el.disabled && form.clk == el) { - a.push({name: n, value: $(el).val()}); + a.push({name: n, value: $(el).val(), type: el.type }); a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); } continue; @@ -575,7 +721,7 @@ $.fn.formToArray = function(semantic) { } } else if (v !== null && typeof v != 'undefined') { - a.push({name: n, value: v}); + a.push({name: n, value: v, type: el.type}); } } @@ -661,7 +807,7 @@ $.fn.fieldSerialize = function(successful) { * for each element is returned. * * Note: This method *always* returns an array. If no valid value can be determined the - * array will be empty, otherwise it will contain one or more values. + * array will be empty, otherwise it will contain one or more values. */ $.fn.fieldValue = function(successful) { for (var val=[], i=0, max=this.length; i < max; i++) { @@ -725,19 +871,20 @@ $.fieldValue = function(el, successful) { * - inputs of type submit, button, reset, and hidden will *not* be effected * - button elements will *not* be effected */ -$.fn.clearForm = function() { +$.fn.clearForm = function(includeHidden) { return this.each(function() { - $('input,select,textarea', this).clearFields(); + $('input,select,textarea', this).clearFields(includeHidden); }); }; /** * Clears the selected form elements. */ -$.fn.clearFields = $.fn.clearInputs = function() { +$.fn.clearFields = $.fn.clearInputs = function(includeHidden) { + var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list return this.each(function() { var t = this.type, tag = this.tagName.toLowerCase(); - if (t == 'text' || t == 'password' || tag == 'textarea') { + if (re.test(t) || tag == 'textarea' || (includeHidden && /hidden/.test(t)) ) { this.value = ''; } else if (t == 'checkbox' || t == 'radio') { @@ -798,17 +945,19 @@ $.fn.selected = function(select) { }); }; +// expose debug var +$.fn.ajaxSubmit.debug = false; + // helper fn for console logging -// set $.fn.ajaxSubmit.debug to true to enable debug logging function log() { - if ($.fn.ajaxSubmit.debug) { - var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); - if (window.console && window.console.log) { - window.console.log(msg); - } - else if (window.opera && window.opera.postError) { - window.opera.postError(msg); - } + if (!$.fn.ajaxSubmit.debug) + return; + var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); + if (window.console && window.console.log) { + window.console.log(msg); + } + else if (window.opera && window.opera.postError) { + window.opera.postError(msg); } }; diff --git a/data/js/jquery.pnotify-1.0.1.min.js b/data/js/jquery.pnotify-1.0.1.min.js deleted file mode 100644 index d41eb4ba6d57f79f1f240ba564cd5ad15a538e8b..0000000000000000000000000000000000000000 --- a/data/js/jquery.pnotify-1.0.1.min.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * jQuery Pines Notify (pnotify) Plugin 1.0.1 - * - * Copyright (c) 2009 Hunter Perrin - * - * Licensed (along with all of Pines) under the GNU Affero GPL: - * http://www.gnu.org/licenses/agpl.html - */ -(function(e){var q,m,k,n;e.extend({pnotify_remove_all:function(){var g=k.data("pnotify");g&&g.length&&e.each(g,function(){this.pnotify_remove&&this.pnotify_remove()})},pnotify_position_all:function(){m&&clearTimeout(m);m=null;var g=k.data("pnotify");if(g&&g.length){e.each(g,function(){var c=this.opts.pnotify_stack;if(c){if(!c.nextpos1)c.nextpos1=c.firstpos1;if(!c.nextpos2)c.nextpos2=c.firstpos2;if(!c.addpos2)c.addpos2=0;if(this.css("display")!="none"){var a,j,i={},b;switch(c.dir1){case "down":b="top"; -break;case "up":b="bottom";break;case "left":b="right";break;case "right":b="left";break}a=parseInt(this.css(b));if(isNaN(a))a=0;if(typeof c.firstpos1=="undefined"){c.firstpos1=a;c.nextpos1=c.firstpos1}var h;switch(c.dir2){case "down":h="top";break;case "up":h="bottom";break;case "left":h="right";break;case "right":h="left";break}j=parseInt(this.css(h));if(isNaN(j))j=0;if(typeof c.firstpos2=="undefined"){c.firstpos2=j;c.nextpos2=c.firstpos2}if(c.dir1=="down"&&c.nextpos1+this.height()>n.height()|| -c.dir1=="up"&&c.nextpos1+this.height()>n.height()||c.dir1=="left"&&c.nextpos1+this.width()>n.width()||c.dir1=="right"&&c.nextpos1+this.width()>n.width()){c.nextpos1=c.firstpos1;c.nextpos2+=c.addpos2+10;c.addpos2=0}if(c.animation&&c.nextpos2<j)switch(c.dir2){case "down":i.top=c.nextpos2+"px";break;case "up":i.bottom=c.nextpos2+"px";break;case "left":i.right=c.nextpos2+"px";break;case "right":i.left=c.nextpos2+"px";break}else this.css(h,c.nextpos2+"px");switch(c.dir2){case "down":case "up":if(this.outerHeight(true)> -c.addpos2)c.addpos2=this.height();break;case "left":case "right":if(this.outerWidth(true)>c.addpos2)c.addpos2=this.width();break}if(c.nextpos1)if(c.animation&&(a>c.nextpos1||i.top||i.bottom||i.right||i.left))switch(c.dir1){case "down":i.top=c.nextpos1+"px";break;case "up":i.bottom=c.nextpos1+"px";break;case "left":i.right=c.nextpos1+"px";break;case "right":i.left=c.nextpos1+"px";break}else this.css(b,c.nextpos1+"px");if(i.top||i.bottom||i.right||i.left)this.animate(i,{duration:500,queue:false});switch(c.dir1){case "down":case "up":c.nextpos1+= -this.height()+10;break;case "left":case "right":c.nextpos1+=this.width()+10;break}}}});e.each(g,function(){var c=this.opts.pnotify_stack;if(c){c.nextpos1=c.firstpos1;c.nextpos2=c.firstpos2;c.addpos2=0;c.animation=true}})}},pnotify:function(g){k||(k=e("body"));n||(n=e(window));var c,a;if(typeof g!="object"){a=e.extend({},e.pnotify.defaults);a.pnotify_text=g}else a=e.extend({},e.pnotify.defaults,g);if(a.pnotify_before_init)if(a.pnotify_before_init(a)===false)return null;var j,i=function(d,f){b.css("display", -"none");var o=document.elementFromPoint(d.clientX,d.clientY);b.css("display","block");var r=e(o),s=r.css("cursor");b.css("cursor",s!="auto"?s:"default");if(!j||j.get(0)!=o){if(j){p.call(j.get(0),"mouseleave",d.originalEvent);p.call(j.get(0),"mouseout",d.originalEvent)}p.call(o,"mouseenter",d.originalEvent);p.call(o,"mouseover",d.originalEvent)}p.call(o,f,d.originalEvent);j=r},b=e("<div />",{"class":"ui-pnotify "+a.pnotify_addclass,css:{display:"none"},mouseenter:function(d){a.pnotify_nonblock&&d.stopPropagation(); -if(a.pnotify_mouse_reset&&c=="out"){b.stop(true);c="in";b.css("height","auto").animate({width:a.pnotify_width,opacity:a.pnotify_nonblock?a.pnotify_nonblock_opacity:a.pnotify_opacity},"fast")}a.pnotify_nonblock&&b.animate({opacity:a.pnotify_nonblock_opacity},"fast");a.pnotify_hide&&a.pnotify_mouse_reset&&b.pnotify_cancel_remove();a.pnotify_closer&&!a.pnotify_nonblock&&b.closer.show()},mouseleave:function(d){a.pnotify_nonblock&&d.stopPropagation();j=null;b.css("cursor","auto");a.pnotify_nonblock&&c!= -"out"&&b.animate({opacity:a.pnotify_opacity},"fast");a.pnotify_hide&&a.pnotify_mouse_reset&&b.pnotify_queue_remove();b.closer.hide();e.pnotify_position_all()},mouseover:function(d){a.pnotify_nonblock&&d.stopPropagation()},mouseout:function(d){a.pnotify_nonblock&&d.stopPropagation()},mousemove:function(d){if(a.pnotify_nonblock){d.stopPropagation();i(d,"onmousemove")}},mousedown:function(d){if(a.pnotify_nonblock){d.stopPropagation();d.preventDefault();i(d,"onmousedown")}},mouseup:function(d){if(a.pnotify_nonblock){d.stopPropagation(); -d.preventDefault();i(d,"onmouseup")}},click:function(d){if(a.pnotify_nonblock){d.stopPropagation();i(d,"onclick")}},dblclick:function(d){if(a.pnotify_nonblock){d.stopPropagation();i(d,"ondblclick")}}});b.opts=a;if(a.pnotify_shadow&&!e.browser.msie)b.shadow_container=e("<div />",{"class":"ui-widget-shadow ui-corner-all ui-pnotify-shadow"}).prependTo(b);b.container=e("<div />",{"class":"ui-widget ui-widget-content ui-corner-all ui-pnotify-container "+(a.pnotify_type=="error"?"ui-state-error":"ui-state-highlight")}).appendTo(b); -b.pnotify_version="1.0.1";b.pnotify=function(d){var f=a;if(typeof d=="string")a.pnotify_text=d;else a=e.extend({},a,d);b.opts=a;if(a.pnotify_shadow!=f.pnotify_shadow)if(a.pnotify_shadow&&!e.browser.msie)b.shadow_container=e("<div />",{"class":"ui-widget-shadow ui-pnotify-shadow"}).prependTo(b);else b.children(".ui-pnotify-shadow").remove();if(a.pnotify_addclass===false)b.removeClass(f.pnotify_addclass);else a.pnotify_addclass!==f.pnotify_addclass&&b.removeClass(f.pnotify_addclass).addClass(a.pnotify_addclass); -if(a.pnotify_title===false)b.title_container.hide("fast");else a.pnotify_title!==f.pnotify_title&&b.title_container.html(a.pnotify_title).show(200);if(a.pnotify_text===false)b.text_container.hide("fast");else if(a.pnotify_text!==f.pnotify_text){if(a.pnotify_insert_brs)a.pnotify_text=a.pnotify_text.replace(/\n/g,"<br />");b.text_container.html(a.pnotify_text).show(200)}b.pnotify_history=a.pnotify_history;a.pnotify_type!=f.pnotify_type&&b.container.toggleClass("ui-state-error ui-state-highlight");if(a.pnotify_notice_icon!= -f.pnotify_notice_icon&&a.pnotify_type=="notice"||a.pnotify_error_icon!=f.pnotify_error_icon&&a.pnotify_type=="error"||a.pnotify_type!=f.pnotify_type){b.container.find("div.ui-pnotify-icon").remove();if(a.pnotify_error_icon&&a.pnotify_type=="error"||a.pnotify_notice_icon)e("<div />",{"class":"ui-pnotify-icon"}).append(e("<span />",{"class":a.pnotify_type=="error"?a.pnotify_error_icon:a.pnotify_notice_icon})).prependTo(b.container)}a.pnotify_width!==f.pnotify_width&&b.animate({width:a.pnotify_width}); -a.pnotify_min_height!==f.pnotify_min_height&&b.container.animate({minHeight:a.pnotify_min_height});a.pnotify_opacity!==f.pnotify_opacity&&b.fadeTo(a.pnotify_animate_speed,a.pnotify_opacity);if(a.pnotify_hide)f.pnotify_hide||b.pnotify_queue_remove();else b.pnotify_cancel_remove();b.pnotify_queue_position();return b};b.pnotify_queue_position=function(){m&&clearTimeout(m);m=setTimeout(e.pnotify_position_all,10)};b.pnotify_display=function(){b.parent().length||b.appendTo(k);if(a.pnotify_before_open)if(a.pnotify_before_open(b)=== -false)return;b.pnotify_queue_position();if(a.pnotify_animation=="fade"||a.pnotify_animation.effect_in=="fade")b.show().fadeTo(0,0).hide();else a.pnotify_opacity!=1&&b.show().fadeTo(0,a.pnotify_opacity).hide();b.animate_in(function(){a.pnotify_after_open&&a.pnotify_after_open(b);b.pnotify_queue_position();a.pnotify_hide&&b.pnotify_queue_remove()})};b.pnotify_remove=function(){if(b.timer){window.clearTimeout(b.timer);b.timer=null}if(a.pnotify_before_close)if(a.pnotify_before_close(b)===false)return; -b.animate_out(function(){if(a.pnotify_after_close)if(a.pnotify_after_close(b)===false)return;b.pnotify_queue_position();a.pnotify_remove&&b.detach()})};b.animate_in=function(d){c="in";var f;f=typeof a.pnotify_animation.effect_in!="undefined"?a.pnotify_animation.effect_in:a.pnotify_animation;if(f=="none"){b.show();d()}else if(f=="show")b.show(a.pnotify_animate_speed,d);else if(f=="fade")b.show().fadeTo(a.pnotify_animate_speed,a.pnotify_opacity,d);else if(f=="slide")b.slideDown(a.pnotify_animate_speed, -d);else if(typeof f=="function")f("in",d,b);else b.effect&&b.effect(f,{},a.pnotify_animate_speed,d)};b.animate_out=function(d){c="out";var f;f=typeof a.pnotify_animation.effect_out!="undefined"?a.pnotify_animation.effect_out:a.pnotify_animation;if(f=="none"){b.hide();d()}else if(f=="show")b.hide(a.pnotify_animate_speed,d);else if(f=="fade")b.fadeOut(a.pnotify_animate_speed,d);else if(f=="slide")b.slideUp(a.pnotify_animate_speed,d);else if(typeof f=="function")f("out",d,b);else b.effect&&b.effect(f, -{},a.pnotify_animate_speed,d)};b.pnotify_cancel_remove=function(){b.timer&&window.clearTimeout(b.timer)};b.pnotify_queue_remove=function(){b.pnotify_cancel_remove();b.timer=window.setTimeout(function(){b.pnotify_remove()},isNaN(a.pnotify_delay)?0:a.pnotify_delay)};b.closer=e("<div />",{"class":"ui-pnotify-closer",css:{cursor:"pointer",display:"none"},click:function(){b.pnotify_remove();b.closer.hide()}}).append(e("<span />",{"class":"ui-icon ui-icon-circle-close"})).appendTo(b.container);if(a.pnotify_error_icon&& -a.pnotify_type=="error"||a.pnotify_notice_icon)e("<div />",{"class":"ui-pnotify-icon"}).append(e("<span />",{"class":a.pnotify_type=="error"?a.pnotify_error_icon:a.pnotify_notice_icon})).appendTo(b.container);b.title_container=e("<div />",{"class":"ui-pnotify-title",html:a.pnotify_title}).appendTo(b.container);a.pnotify_title===false&&b.title_container.hide();if(a.pnotify_insert_brs&&typeof a.pnotify_text=="string")a.pnotify_text=a.pnotify_text.replace(/\n/g,"<br />");b.text_container=e("<div />", -{"class":"ui-pnotify-text",html:a.pnotify_text}).appendTo(b.container);a.pnotify_text===false&&b.text_container.hide();typeof a.pnotify_width=="string"&&b.css("width",a.pnotify_width);typeof a.pnotify_min_height=="string"&&b.container.css("min-height",a.pnotify_min_height);b.pnotify_history=a.pnotify_history;var h=k.data("pnotify");if(h==null||typeof h!="object")h=[];h=a.pnotify_stack.push=="top"?e.merge([b],h):e.merge(h,[b]);k.data("pnotify",h);a.pnotify_after_init&&a.pnotify_after_init(b);if(a.pnotify_history){var l= -k.data("pnotify_history");if(typeof l=="undefined"){l=e("<div />",{"class":"ui-pnotify-history-container ui-state-default ui-corner-bottom",mouseleave:function(){l.animate({top:"-"+q+"px"},{duration:100,queue:false})}}).append(e("<div />",{"class":"ui-pnotify-history-header",text:"Redisplay"})).append(e("<button />",{"class":"ui-pnotify-history-all ui-state-default ui-corner-all",text:"All",mouseenter:function(){e(this).addClass("ui-state-hover")},mouseleave:function(){e(this).removeClass("ui-state-hover")}, -click:function(){e.each(h,function(){this.pnotify_history&&this.pnotify_display&&this.pnotify_display()});return false}})).append(e("<button />",{"class":"ui-pnotify-history-last ui-state-default ui-corner-all",text:"Last",mouseenter:function(){e(this).addClass("ui-state-hover")},mouseleave:function(){e(this).removeClass("ui-state-hover")},click:function(){for(var d=1;!h[h.length-d]||!h[h.length-d].pnotify_history||h[h.length-d].is(":visible");){if(h.length-d===0)return false;d++}d=h[h.length-d]; -d.pnotify_display&&d.pnotify_display();return false}})).appendTo(k);q=e("<span />",{"class":"ui-pnotify-history-pulldown ui-icon ui-icon-grip-dotted-horizontal",mouseenter:function(){l.animate({top:"0"},{duration:100,queue:false})}}).appendTo(l).offset().top+2;l.css({top:"-"+q+"px"});k.data("pnotify_history",l)}}a.pnotify_stack.animation=false;b.pnotify_display();return b}});var t=/^on/,u=/^(dbl)?click$|^mouse(move|down|up|over|out|enter|leave)$|^contextmenu$/,v=/^(focus|blur|select|change|reset)$|^key(press|down|up)$/, -w=/^(scroll|resize|(un)?load|abort|error)$/,p=function(g,c){var a;g=g.toLowerCase();if(document.createEvent&&this.dispatchEvent){g=g.replace(t,"");if(g.match(u)){e(this).offset();a=document.createEvent("MouseEvents");a.initMouseEvent(g,c.bubbles,c.cancelable,c.view,c.detail,c.screenX,c.screenY,c.clientX,c.clientY,c.ctrlKey,c.altKey,c.shiftKey,c.metaKey,c.button,c.relatedTarget)}else if(g.match(v)){a=document.createEvent("UIEvents");a.initUIEvent(g,c.bubbles,c.cancelable,c.view,c.detail)}else if(g.match(w)){a= -document.createEvent("HTMLEvents");a.initEvent(g,c.bubbles,c.cancelable)}a&&this.dispatchEvent(a)}else{g.match(t)||(g="on"+g);a=document.createEventObject(c);this.fireEvent(g,a)}};e.pnotify.defaults={pnotify_title:false,pnotify_text:false,pnotify_addclass:"",pnotify_nonblock:false,pnotify_nonblock_opacity:0.2,pnotify_history:true,pnotify_width:"300px",pnotify_min_height:"16px",pnotify_type:"notice",pnotify_notice_icon:"ui-icon ui-icon-info",pnotify_error_icon:"ui-icon ui-icon-alert",pnotify_animation:"fade", -pnotify_animate_speed:"slow",pnotify_opacity:1,pnotify_shadow:false,pnotify_closer:true,pnotify_hide:true,pnotify_delay:8E3,pnotify_mouse_reset:true,pnotify_remove:true,pnotify_insert_brs:true,pnotify_stack:{dir1:"down",dir2:"left",push:"bottom"}}})(jQuery); diff --git a/data/js/jquery.pnotify-1.0.2.min.js b/data/js/jquery.pnotify-1.0.2.min.js new file mode 100644 index 0000000000000000000000000000000000000000..99bcfdc97cadb144ad58248bb4c3c888ff35695e --- /dev/null +++ b/data/js/jquery.pnotify-1.0.2.min.js @@ -0,0 +1,34 @@ +/* + * jQuery Pines Notify (pnotify) Plugin 1.0.2 + * + * Copyright (c) 2009-2011 Hunter Perrin + * + * Triple license under the GPL, LGPL, and MPL: + * http://www.gnu.org/licenses/gpl.html + * http://www.gnu.org/licenses/lgpl.html + * http://www.mozilla.org/MPL/MPL-1.1.html + */ +(function(e){var n,j,g,k;e.extend({pnotify_remove_all:function(){var d=g.data("pnotify");d&&d.length&&e.each(d,function(){this.pnotify_remove&&this.pnotify_remove()})},pnotify_position_all:function(){j&&clearTimeout(j);j=null;var d=g.data("pnotify");d&&d.length&&(e.each(d,function(){var c=this.opts.pnotify_stack;if(c){if(!c.nextpos1)c.nextpos1=c.firstpos1;if(!c.nextpos2)c.nextpos2=c.firstpos2;if(!c.addpos2)c.addpos2=0;if(this.css("display")!="none"){var a,e,d={},b;switch(c.dir1){case "down":b="top"; +break;case "up":b="bottom";break;case "left":b="right";break;case "right":b="left"}a=parseInt(this.css(b));isNaN(a)&&(a=0);if(typeof c.firstpos1=="undefined")c.firstpos1=a,c.nextpos1=c.firstpos1;var f;switch(c.dir2){case "down":f="top";break;case "up":f="bottom";break;case "left":f="right";break;case "right":f="left"}e=parseInt(this.css(f));isNaN(e)&&(e=0);if(typeof c.firstpos2=="undefined")c.firstpos2=e,c.nextpos2=c.firstpos2;if(c.dir1=="down"&&c.nextpos1+this.height()>k.height()||c.dir1=="up"&& +c.nextpos1+this.height()>k.height()||c.dir1=="left"&&c.nextpos1+this.width()>k.width()||c.dir1=="right"&&c.nextpos1+this.width()>k.width())c.nextpos1=c.firstpos1,c.nextpos2+=c.addpos2+10,c.addpos2=0;if(c.animation&&c.nextpos2<e)switch(c.dir2){case "down":d.top=c.nextpos2+"px";break;case "up":d.bottom=c.nextpos2+"px";break;case "left":d.right=c.nextpos2+"px";break;case "right":d.left=c.nextpos2+"px"}else this.css(f,c.nextpos2+"px");switch(c.dir2){case "down":case "up":if(this.outerHeight(!0)>c.addpos2)c.addpos2= +this.height();break;case "left":case "right":if(this.outerWidth(!0)>c.addpos2)c.addpos2=this.width()}if(c.nextpos1)if(c.animation&&(a>c.nextpos1||d.top||d.bottom||d.right||d.left))switch(c.dir1){case "down":d.top=c.nextpos1+"px";break;case "up":d.bottom=c.nextpos1+"px";break;case "left":d.right=c.nextpos1+"px";break;case "right":d.left=c.nextpos1+"px"}else this.css(b,c.nextpos1+"px");(d.top||d.bottom||d.right||d.left)&&this.animate(d,{duration:500,queue:!1});switch(c.dir1){case "down":case "up":c.nextpos1+= +this.height()+10;break;case "left":case "right":c.nextpos1+=this.width()+10}}}}),e.each(d,function(){var c=this.opts.pnotify_stack;if(c)c.nextpos1=c.firstpos1,c.nextpos2=c.firstpos2,c.addpos2=0,c.animation=!0}))},pnotify:function(d){g||(g=e("body"));k||(k=e(window));var c,a;typeof d!="object"?(a=e.extend({},e.pnotify.defaults),a.pnotify_text=d):a=e.extend({},e.pnotify.defaults,d);if(a.pnotify_before_init&&a.pnotify_before_init(a)===!1)return null;var h,l=function(a,c){b.css("display","none");var d= +document.elementFromPoint(a.clientX,a.clientY);b.css("display","block");var f=e(d),g=f.css("cursor");b.css("cursor",g!="auto"?g:"default");if(!h||h.get(0)!=d)h&&(m.call(h.get(0),"mouseleave",a.originalEvent),m.call(h.get(0),"mouseout",a.originalEvent)),m.call(d,"mouseenter",a.originalEvent),m.call(d,"mouseover",a.originalEvent);m.call(d,c,a.originalEvent);h=f},b=e("<div />",{"class":"ui-pnotify "+a.pnotify_addclass,css:{display:"none"},mouseenter:function(o){a.pnotify_nonblock&&o.stopPropagation(); +a.pnotify_mouse_reset&&c=="out"&&(b.stop(!0),c="in",b.css("height","auto").animate({width:a.pnotify_width,opacity:a.pnotify_nonblock?a.pnotify_nonblock_opacity:a.pnotify_opacity},"fast"));a.pnotify_nonblock&&b.animate({opacity:a.pnotify_nonblock_opacity},"fast");a.pnotify_hide&&a.pnotify_mouse_reset&&b.pnotify_cancel_remove();a.pnotify_closer&&!a.pnotify_nonblock&&b.closer.show()},mouseleave:function(o){a.pnotify_nonblock&&o.stopPropagation();h=null;b.css("cursor","auto");a.pnotify_nonblock&&c!="out"&& +b.animate({opacity:a.pnotify_opacity},"fast");a.pnotify_hide&&a.pnotify_mouse_reset&&b.pnotify_queue_remove();b.closer.hide();e.pnotify_position_all()},mouseover:function(b){a.pnotify_nonblock&&b.stopPropagation()},mouseout:function(b){a.pnotify_nonblock&&b.stopPropagation()},mousemove:function(b){a.pnotify_nonblock&&(b.stopPropagation(),l(b,"onmousemove"))},mousedown:function(b){a.pnotify_nonblock&&(b.stopPropagation(),b.preventDefault(),l(b,"onmousedown"))},mouseup:function(b){a.pnotify_nonblock&& +(b.stopPropagation(),b.preventDefault(),l(b,"onmouseup"))},click:function(b){a.pnotify_nonblock&&(b.stopPropagation(),l(b,"onclick"))},dblclick:function(b){a.pnotify_nonblock&&(b.stopPropagation(),l(b,"ondblclick"))}});b.opts=a;if(a.pnotify_shadow&&!e.browser.msie)b.shadow_container=e("<div />",{"class":"ui-widget-shadow ui-corner-all ui-pnotify-shadow"}).prependTo(b);b.container=e("<div />",{"class":"ui-widget ui-widget-content ui-corner-all ui-pnotify-container "+(a.pnotify_type=="error"?"ui-state-error": +"ui-state-highlight")}).appendTo(b);b.pnotify_version="1.0.2";b.pnotify=function(c){var d=a;typeof c=="string"?a.pnotify_text=c:a=e.extend({},a,c);b.opts=a;if(a.pnotify_shadow!=d.pnotify_shadow)a.pnotify_shadow&&!e.browser.msie?b.shadow_container=e("<div />",{"class":"ui-widget-shadow ui-pnotify-shadow"}).prependTo(b):b.children(".ui-pnotify-shadow").remove();a.pnotify_addclass===!1?b.removeClass(d.pnotify_addclass):a.pnotify_addclass!==d.pnotify_addclass&&b.removeClass(d.pnotify_addclass).addClass(a.pnotify_addclass); +a.pnotify_title===!1?b.title_container.hide("fast"):a.pnotify_title!==d.pnotify_title&&b.title_container.html(a.pnotify_title).show(200);if(a.pnotify_text===!1)b.text_container.hide("fast");else if(a.pnotify_text!==d.pnotify_text){if(a.pnotify_insert_brs)a.pnotify_text=a.pnotify_text.replace(/\n/g,"<br />");b.text_container.html(a.pnotify_text).show(200)}b.pnotify_history=a.pnotify_history;a.pnotify_type!=d.pnotify_type&&b.container.toggleClass("ui-state-error ui-state-highlight");if(a.pnotify_notice_icon!= +d.pnotify_notice_icon&&a.pnotify_type=="notice"||a.pnotify_error_icon!=d.pnotify_error_icon&&a.pnotify_type=="error"||a.pnotify_type!=d.pnotify_type)if(b.container.find("div.ui-pnotify-icon").remove(),a.pnotify_error_icon&&a.pnotify_type=="error"||a.pnotify_notice_icon)e("<div />",{"class":"ui-pnotify-icon"}).append(e("<span />",{"class":a.pnotify_type=="error"?a.pnotify_error_icon:a.pnotify_notice_icon})).prependTo(b.container);a.pnotify_width!==d.pnotify_width&&b.animate({width:a.pnotify_width}); +a.pnotify_min_height!==d.pnotify_min_height&&b.container.animate({minHeight:a.pnotify_min_height});a.pnotify_opacity!==d.pnotify_opacity&&b.fadeTo(a.pnotify_animate_speed,a.pnotify_opacity);a.pnotify_hide?d.pnotify_hide||b.pnotify_queue_remove():b.pnotify_cancel_remove();b.pnotify_queue_position();return b};b.pnotify_queue_position=function(){j&&clearTimeout(j);j=setTimeout(e.pnotify_position_all,10)};b.pnotify_display=function(){b.parent().length||b.appendTo(g);a.pnotify_before_open&&a.pnotify_before_open(b)=== +!1||(b.pnotify_queue_position(),a.pnotify_animation=="fade"||a.pnotify_animation.effect_in=="fade"?b.show().fadeTo(0,0).hide():a.pnotify_opacity!=1&&b.show().fadeTo(0,a.pnotify_opacity).hide(),b.animate_in(function(){a.pnotify_after_open&&a.pnotify_after_open(b);b.pnotify_queue_position();a.pnotify_hide&&b.pnotify_queue_remove()}))};b.pnotify_remove=function(){if(b.timer)window.clearTimeout(b.timer),b.timer=null;a.pnotify_before_close&&a.pnotify_before_close(b)===!1||b.animate_out(function(){a.pnotify_after_close&& +a.pnotify_after_close(b)===!1||(b.pnotify_queue_position(),a.pnotify_remove&&b.detach())})};b.animate_in=function(d){c="in";var e;e=typeof a.pnotify_animation.effect_in!="undefined"?a.pnotify_animation.effect_in:a.pnotify_animation;e=="none"?(b.show(),d()):e=="show"?b.show(a.pnotify_animate_speed,d):e=="fade"?b.show().fadeTo(a.pnotify_animate_speed,a.pnotify_opacity,d):e=="slide"?b.slideDown(a.pnotify_animate_speed,d):typeof e=="function"?e("in",d,b):b.effect&&b.effect(e,{},a.pnotify_animate_speed, +d)};b.animate_out=function(d){c="out";var e;e=typeof a.pnotify_animation.effect_out!="undefined"?a.pnotify_animation.effect_out:a.pnotify_animation;e=="none"?(b.hide(),d()):e=="show"?b.hide(a.pnotify_animate_speed,d):e=="fade"?b.fadeOut(a.pnotify_animate_speed,d):e=="slide"?b.slideUp(a.pnotify_animate_speed,d):typeof e=="function"?e("out",d,b):b.effect&&b.effect(e,{},a.pnotify_animate_speed,d)};b.pnotify_cancel_remove=function(){b.timer&&window.clearTimeout(b.timer)};b.pnotify_queue_remove=function(){b.pnotify_cancel_remove(); +b.timer=window.setTimeout(function(){b.pnotify_remove()},isNaN(a.pnotify_delay)?0:a.pnotify_delay)};b.closer=e("<div />",{"class":"ui-pnotify-closer",css:{cursor:"pointer",display:"none"},click:function(){b.pnotify_remove();b.closer.hide()}}).append(e("<span />",{"class":"ui-icon ui-icon-circle-close"})).appendTo(b.container);if(a.pnotify_error_icon&&a.pnotify_type=="error"||a.pnotify_notice_icon)e("<div />",{"class":"ui-pnotify-icon"}).append(e("<span />",{"class":a.pnotify_type=="error"?a.pnotify_error_icon: +a.pnotify_notice_icon})).appendTo(b.container);b.title_container=e("<div />",{"class":"ui-pnotify-title",html:a.pnotify_title}).appendTo(b.container);a.pnotify_title===!1&&b.title_container.hide();if(a.pnotify_insert_brs&&typeof a.pnotify_text=="string")a.pnotify_text=a.pnotify_text.replace(/\n/g,"<br />");b.text_container=e("<div />",{"class":"ui-pnotify-text",html:a.pnotify_text}).appendTo(b.container);a.pnotify_text===!1&&b.text_container.hide();typeof a.pnotify_width=="string"&&b.css("width", +a.pnotify_width);typeof a.pnotify_min_height=="string"&&b.container.css("min-height",a.pnotify_min_height);b.pnotify_history=a.pnotify_history;var f=g.data("pnotify");if(f==null||typeof f!="object")f=[];f=a.pnotify_stack.push=="top"?e.merge([b],f):e.merge(f,[b]);g.data("pnotify",f);a.pnotify_after_init&&a.pnotify_after_init(b);if(a.pnotify_history){var i=g.data("pnotify_history");typeof i=="undefined"&&(i=e("<div />",{"class":"ui-pnotify-history-container ui-state-default ui-corner-bottom",mouseleave:function(){i.animate({top:"-"+ +n+"px"},{duration:100,queue:!1})}}).append(e("<div />",{"class":"ui-pnotify-history-header",text:"Redisplay"})).append(e("<button />",{"class":"ui-pnotify-history-all ui-state-default ui-corner-all",text:"All",mouseenter:function(){e(this).addClass("ui-state-hover")},mouseleave:function(){e(this).removeClass("ui-state-hover")},click:function(){e.each(f,function(){this.pnotify_history&&this.pnotify_display&&this.pnotify_display()});return!1}})).append(e("<button />",{"class":"ui-pnotify-history-last ui-state-default ui-corner-all", +text:"Last",mouseenter:function(){e(this).addClass("ui-state-hover")},mouseleave:function(){e(this).removeClass("ui-state-hover")},click:function(){for(var a=1;!f[f.length-a]||!f[f.length-a].pnotify_history||f[f.length-a].is(":visible");){if(f.length-a===0)return!1;a++}a=f[f.length-a];a.pnotify_display&&a.pnotify_display();return!1}})).appendTo(g),n=e("<span />",{"class":"ui-pnotify-history-pulldown ui-icon ui-icon-grip-dotted-horizontal",mouseenter:function(){i.animate({top:"0"},{duration:100,queue:!1})}}).appendTo(i).offset().top+ +2,i.css({top:"-"+n+"px"}),g.data("pnotify_history",i))}a.pnotify_stack.animation=!1;b.pnotify_display();return b}});var p=/^on/,q=/^(dbl)?click$|^mouse(move|down|up|over|out|enter|leave)$|^contextmenu$/,r=/^(focus|blur|select|change|reset)$|^key(press|down|up)$/,s=/^(scroll|resize|(un)?load|abort|error)$/,m=function(d,c){var a,d=d.toLowerCase();document.createEvent&&this.dispatchEvent?(d=d.replace(p,""),d.match(q)?(e(this).offset(),a=document.createEvent("MouseEvents"),a.initMouseEvent(d,c.bubbles, +c.cancelable,c.view,c.detail,c.screenX,c.screenY,c.clientX,c.clientY,c.ctrlKey,c.altKey,c.shiftKey,c.metaKey,c.button,c.relatedTarget)):d.match(r)?(a=document.createEvent("UIEvents"),a.initUIEvent(d,c.bubbles,c.cancelable,c.view,c.detail)):d.match(s)&&(a=document.createEvent("HTMLEvents"),a.initEvent(d,c.bubbles,c.cancelable)),a&&this.dispatchEvent(a)):(d.match(p)||(d="on"+d),a=document.createEventObject(c),this.fireEvent(d,a))};e.pnotify.defaults={pnotify_title:!1,pnotify_text:!1,pnotify_addclass:"", +pnotify_nonblock:!1,pnotify_nonblock_opacity:0.2,pnotify_history:!0,pnotify_width:"300px",pnotify_min_height:"16px",pnotify_type:"notice",pnotify_notice_icon:"ui-icon ui-icon-info",pnotify_error_icon:"ui-icon ui-icon-alert",pnotify_animation:"fade",pnotify_animate_speed:"slow",pnotify_opacity:1,pnotify_shadow:!1,pnotify_closer:!0,pnotify_hide:!0,pnotify_delay:8E3,pnotify_mouse_reset:!0,pnotify_remove:!0,pnotify_insert_brs:!0,pnotify_stack:{dir1:"down",dir2:"left",push:"bottom"}}})(jQuery); diff --git a/data/js/jquery.qtip-2011-11-14.min.js b/data/js/jquery.qtip-2011-11-14.min.js new file mode 100644 index 0000000000000000000000000000000000000000..4cfcebf2bbf9dd848a072f98f5c0626bc5858bf1 --- /dev/null +++ b/data/js/jquery.qtip-2011-11-14.min.js @@ -0,0 +1,13 @@ +/* +* qTip2 - Pretty powerful tooltips +* http://craigsworks.com/projects/qtip2/ +* +* Version: nightly +* Copyright 2009-2010 Craig Michael Thompson - http://craigsworks.com +* +* Dual licensed under MIT or GPLv2 licenses +* http://en.wikipedia.org/wiki/MIT_License +* http://en.wikipedia.org/wiki/GNU_General_Public_License +* +* Date: Thu Nov 17 12:01:03.0000000000 2011 +*//*jslint browser: true, onevar: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true *//*global window: false, jQuery: false, console: false */(function(a,b,c){function C(b,g){function w(a){var b=a.precedance==="y",c=n[b?"width":"height"],d=n[b?"height":"width"],e=a.string().indexOf("center")>-1,f=c*(e?.5:1),g=Math.pow,h=Math.round,i,j,k,l=Math.sqrt(g(f,2)+g(d,2)),m=[p/f*l,p/d*l];m[2]=Math.sqrt(g(m[0],2)-g(p,2)),m[3]=Math.sqrt(g(m[1],2)-g(p,2)),i=l+m[2]+m[3]+(e?0:m[0]),j=i/l,k=[h(j*d),h(j*c)];return{height:k[b?0:1],width:k[b?1:0]}}function v(b){var c=k.titlebar&&b.y==="top",d=c?k.titlebar:k.content,e=a.browser.mozilla,f=e?"-moz-":a.browser.webkit?"-webkit-":"",g=b.y+(e?"":"-")+b.x,h=f+(e?"border-radius-"+g:"border-"+g+"-radius");return parseInt(d.css(h),10)||parseInt(l.css(h),10)||0}function u(a,b,c){b=b?b:a[a.precedance];var d=l.hasClass(r),e=k.titlebar&&a.y==="top",f=e?k.titlebar:k.content,g="border-"+b+"-width",h;l.addClass(r),h=parseInt(f.css(g),10),h=(c?h||parseInt(l.css(g),10):h)||0,l.toggleClass(r,d);return h}function t(f,g,h,l){if(k.tip){var n=a.extend({},i.corner),o=h.adjusted,p=b.options.position.adjust.method.split(" "),q=p[0],r=p[1]||p[0],s={left:e,top:e,x:0,y:0},t,u={},v;i.corner.fixed!==d&&(q==="shift"&&n.precedance==="x"&&o.left&&n.y!=="center"?n.precedance=n.precedance==="x"?"y":"x":q==="flip"&&o.left&&(n.x=n.x==="center"?o.left>0?"left":"right":n.x==="left"?"right":"left"),r==="shift"&&n.precedance==="y"&&o.top&&n.x!=="center"?n.precedance=n.precedance==="y"?"x":"y":r==="flip"&&o.top&&(n.y=n.y==="center"?o.top>0?"top":"bottom":n.y==="top"?"bottom":"top"),n.string()!==m.corner&&(m.top!==o.top||m.left!==o.left)&&i.update(n,e)),t=i.position(n,o),t.right!==c&&(t.left=-t.right),t.bottom!==c&&(t.top=-t.bottom),t.user=Math.max(0,j.offset);if(s.left=q==="shift"&&!!o.left)n.x==="center"?u["margin-left"]=s.x=t["margin-left"]-o.left:(v=t.right!==c?[o.left,-t.left]:[-o.left,t.left],(s.x=Math.max(v[0],v[1]))>v[0]&&(h.left-=o.left,s.left=e),u[t.right!==c?"right":"left"]=s.x);if(s.top=r==="shift"&&!!o.top)n.y==="center"?u["margin-top"]=s.y=t["margin-top"]-o.top:(v=t.bottom!==c?[o.top,-t.top]:[-o.top,t.top],(s.y=Math.max(v[0],v[1]))>v[0]&&(h.top-=o.top,s.top=e),u[t.bottom!==c?"bottom":"top"]=s.y);k.tip.css(u).toggle(!(s.x&&s.y||n.x==="center"&&s.y||n.y==="center"&&s.x)),h.left-=t.left.charAt?t.user:q!=="shift"||s.top||!s.left&&!s.top?t.left:0,h.top-=t.top.charAt?t.user:r!=="shift"||s.left||!s.left&&!s.top?t.top:0,m.left=o.left,m.top=o.top,m.corner=n.string()}}var i=this,j=b.options.style.tip,k=b.elements,l=k.tooltip,m={top:0,left:0,corner:""},n={width:j.width,height:j.height},o={},p=j.border||0,q=".qtip-tip",s=!!(a("<canvas />")[0]||{}).getContext;i.mimic=i.corner=f,i.border=p,i.offset=j.offset,i.size=n,b.checks.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){i.init()||i.destroy(),b.reposition()},"^style.tip.(height|width)$":function(){n={width:j.width,height:j.height},i.create(),i.update(),b.reposition()},"^content.title.text|style.(classes|widget)$":function(){k.tip&&i.update()}},a.extend(i,{init:function(){var b=i.detectCorner()&&(s||a.browser.msie);b&&(i.create(),i.update(),l.unbind(q).bind("tooltipmove"+q,t));return b},detectCorner:function(){var a=j.corner,c=b.options.position,f=c.at,g=c.my.string?c.my.string():c.my;if(a===e||g===e&&f===e)return e;a===d?i.corner=new h.Corner(g):a.string||(i.corner=new h.Corner(a),i.corner.fixed=d);return i.corner.string()!=="centercenter"},detectColours:function(c){var d,e,f,g=k.tip.css("cssText",""),h=c||i.corner,m=h[h.precedance],p="border-"+m+"-color",q="border"+m.charAt(0)+m.substr(1)+"Color",s=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,t="background-color",u="transparent",v=" !important",w=a(document.body).css("color"),x=b.elements.content.css("color"),y=k.titlebar&&(h.y==="top"||h.y==="center"&&g.position().top+n.height/2+j.offset<k.titlebar.outerHeight(1)),z=y?k.titlebar:k.content;l.addClass(r),o.fill=e=g.css(t),o.border=f=g[0].style[q]||g.css(p)||l.css(p);if(!e||s.test(e))o.fill=z.css(t)||u,s.test(o.fill)&&(o.fill=l.css(t)||e);if(!f||s.test(f)||f===w)o.border=z.css(p)||u,s.test(o.border)&&(o.border=f);a("*",g).add(g).css("cssText",t+":"+u+v+";border:0"+v+";"),l.removeClass(r)},create:function(){var b=n.width,c=n.height,d;k.tip&&k.tip.remove(),k.tip=a("<div />",{"class":"ui-tooltip-tip"}).css({width:b,height:c}).prependTo(l),s?a("<canvas />").appendTo(k.tip)[0].getContext("2d").save():(d='<vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape>',k.tip.html(d+d))},update:function(b,c){var g=k.tip,l=g.children(),m=n.width,q=n.height,r="px solid ",t="px dashed transparent",v=j.mimic,x=Math.round,y,z,A,C,D;b||(b=i.corner),v===e?v=b:(v=new h.Corner(v),v.precedance=b.precedance,v.x==="inherit"?v.x=b.x:v.y==="inherit"?v.y=b.y:v.x===v.y&&(v[b.precedance]=b[b.precedance])),y=v.precedance,i.detectColours(b),o.border!=="transparent"&&o.border!=="#123456"?(p=u(b,f,d),j.border===0&&p>0&&(o.fill=o.border),i.border=p=j.border!==d?j.border:p):i.border=p=0,A=B(v,m,q),i.size=D=w(b),g.css(D),b.precedance==="y"?C=[x(v.x==="left"?p:v.x==="right"?D.width-m-p:(D.width-m)/2),x(v.y==="top"?D.height-q:0)]:C=[x(v.x==="left"?D.width-m:0),x(v.y==="top"?p:v.y==="bottom"?D.height-q-p:(D.height-q)/2)],s?(l.attr(D),z=l[0].getContext("2d"),z.restore(),z.save(),z.clearRect(0,0,3e3,3e3),z.translate(C[0],C[1]),z.beginPath(),z.moveTo(A[0][0],A[0][1]),z.lineTo(A[1][0],A[1][1]),z.lineTo(A[2][0],A[2][1]),z.closePath(),z.fillStyle=o.fill,z.strokeStyle=o.border,z.lineWidth=p*2,z.lineJoin="miter",z.miterLimit=100,p&&z.stroke(),z.fill()):(A="m"+A[0][0]+","+A[0][1]+" l"+A[1][0]+","+A[1][1]+" "+A[2][0]+","+A[2][1]+" xe",C[2]=p&&/^(r|b)/i.test(b.string())?parseFloat(a.browser.version,10)===8?2:1:0,l.css({antialias:""+(v.string().indexOf("center")>-1),left:C[0]-C[2]*Number(y==="x"),top:C[1]-C[2]*Number(y==="y"),width:m+p,height:q+p}).each(function(b){var c=a(this);c[c.prop?"prop":"attr"]({coordsize:m+p+" "+(q+p),path:A,fillcolor:o.fill,filled:!!b,stroked:!b}).css({display:p||b?"block":"none"}),!b&&c.html()===""&&c.html('<vml:stroke weight="'+p*2+'px" color="'+o.border+'" miterlimit="1000" joinstyle="miter" style="behavior:url(#default#VML); display:inline-block;" />')})),c!==e&&i.position(b)},position:function(b){var c=k.tip,f={},g=Math.max(0,j.offset),h,l,m;if(j.corner===e||!c)return e;b=b||i.corner,h=b.precedance,l=w(b),m=[b.x,b.y],h==="x"&&m.reverse(),a.each(m,function(a,c){var e,i;c==="center"?(e=h==="y"?"left":"top",f[e]="50%",f["margin-"+e]=-Math.round(l[h==="y"?"width":"height"]/2)+g):(e=u(b,c,d),i=v(b),f[c]=a?p?u(b,c):0:g+(i>e?i:0))}),f[b[h]]-=l[h==="x"?"width":"height"],c.css({top:"",bottom:"",left:"",right:"",margin:""}).css(f);return f},destroy:function(){k.tip&&k.tip.remove(),l.unbind(q)}}),i.init()}function B(a,b,c){var d=Math.ceil(b/2),e=Math.ceil(c/2),f={bottomright:[[0,0],[b,c],[b,0]],bottomleft:[[0,0],[b,0],[0,c]],topright:[[0,c],[b,0],[b,c]],topleft:[[0,0],[0,c],[b,c]],topcenter:[[0,c],[d,0],[b,c]],bottomcenter:[[0,0],[b,0],[d,c]],rightcenter:[[0,0],[b,e],[0,c]],leftcenter:[[b,0],[b,c],[0,e]]};f.lefttop=f.bottomright,f.righttop=f.bottomleft,f.leftbottom=f.topright,f.rightbottom=f.topleft;return f[a.string()]}function A(b){var c=this,f=b.elements.tooltip,g=b.options.content.ajax,h=".qtip-ajax",i=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,j=d;b.checks.ajax={"^content.ajax":function(a,b,d){b==="ajax"&&(g=d),b==="once"?c.init():g&&g.url?c.load():f.unbind(h)}},a.extend(c,{init:function(){g&&g.url&&f.unbind(h)[g.once?"one":"bind"]("tooltipshow"+h,c.load);return c},load:function(d,f){function p(a,c,d){a.status!==0&&b.set("content.text",c+": "+d)}function o(c){k&&(c=a("<div/>").append(c.replace(i,"")).find(k)),b.set("content.text",c)}function n(){l&&(b.show(d.originalEvent),f=e),a.isFunction(g.complete)&&g.complete.apply(this,arguments)}var h=g.url.indexOf(" "),j=g.url,k,l=g.once&&!g.loading&&f;if(l)try{d.preventDefault()}catch(m){}else if(d&&d.isDefaultPrevented())return c;h>-1&&(k=j.substr(h),j=j.substr(0,h)),a.ajax(a.extend({success:o,error:p,context:b},g,{url:j,complete:n}))}}),c.init()}function z(b,c){var i,j,k,l,m,n=a(this),o=a(document.body),p=this===document?o:n,q=n.metadata?n.metadata(c.metadata):f,r=c.metadata.type==="html5"&&q?q[c.metadata.name]:f,s=n.data(c.metadata.name||"qtipopts");try{s=typeof s==="string"?(new Function("return "+s))():s}catch(t){w("Unable to parse HTML5 attribute data: "+s)}l=a.extend(d,{},g.defaults,c,typeof s==="object"?x(s):f,x(r||q)),j=l.position,l.id=b;if("boolean"===typeof l.content.text){k=n.attr(l.content.attr);if(l.content.attr!==e&&k)l.content.text=k;else{w("Unable to locate content for tooltip! Aborting render of tooltip on element: ",n);return e}}j.container===e&&(j.container=o),j.target===e&&(j.target=p),l.show.target===e&&(l.show.target=p),l.show.solo===d&&(l.show.solo=o),l.hide.target===e&&(l.hide.target=p),l.position.viewport===d&&(l.position.viewport=j.container),j.at=new h.Corner(j.at),j.my=new h.Corner(j.my);if(a.data(this,"qtip"))if(l.overwrite)n.qtip("destroy");else if(l.overwrite===e)return e;l.suppress&&(m=a.attr(this,"title"))&&a(this).removeAttr("title").attr(u,m),i=new y(n,l,b,!!k),a.data(this,"qtip",i),n.bind("remove.qtip-"+b,function(){i.destroy()});return i}function y(s,t,w,y){function R(){var c=[t.show.target[0],t.hide.target[0],z.rendered&&G.tooltip[0],t.position.container[0],t.position.viewport[0],b,document];z.rendered?a([]).pushStack(a.grep(c,function(a){return typeof a==="object"})).unbind(F):t.show.target.unbind(F+"-create")}function Q(){function p(a){E.is(":visible")&&z.reposition(a)}function o(a){if(E.hasClass(m))return e;clearTimeout(z.timers.inactive),z.timers.inactive=setTimeout(function(){z.hide(a)},t.hide.inactive)}function l(b){if(E.hasClass(m)||C||D)return e;var d=a(b.relatedTarget||b.target),g=d.closest(n)[0]===E[0],h=d[0]===f.show[0];clearTimeout(z.timers.show),clearTimeout(z.timers.hide);if(c.target==="mouse"&&g||t.hide.fixed&&(/mouse(out|leave|move)/.test(b.type)&&(g||h)))try{b.preventDefault(),b.stopImmediatePropagation()}catch(i){}else t.hide.delay>0?z.timers.hide=setTimeout(function(){z.hide(b)},t.hide.delay):z.hide(b)}function k(a){if(E.hasClass(m))return e;clearTimeout(z.timers.show),clearTimeout(z.timers.hide);var b=function(){z.toggle(d,a)};t.show.delay>0?z.timers.show=setTimeout(b,t.show.delay):b()}var c=t.position,f={show:t.show.target,hide:t.hide.target,viewport:a(c.viewport),document:a(document),body:a(document.body),window:a(b)},h={show:a.trim(""+t.show.event).split(" "),hide:a.trim(""+t.hide.event).split(" ")},j=a.browser.msie&&parseInt(a.browser.version,10)===6;E.bind("mouseenter"+F+" mouseleave"+F,function(a){var b=a.type==="mouseenter";b&&z.focus(a),E.toggleClass(q,b)}),t.hide.fixed&&(f.hide=f.hide.add(E),E.bind("mouseover"+F,function(){E.hasClass(m)||clearTimeout(z.timers.hide)})),/mouse(out|leave)/i.test(t.hide.event)?t.hide.leave==="window"&&f.window.bind("mouseout"+F,function(a){/select|option/.test(a.target)&&!a.relatedTarget&&z.hide(a)}):/mouse(over|enter)/i.test(t.show.event)&&f.hide.bind("mouseleave"+F,function(a){clearTimeout(z.timers.show)}),(""+t.hide.event).indexOf("unfocus")>-1&&f.body.bind("mousedown"+F,function(b){var c=a(b.target),d=!E.hasClass(m)&&E.is(":visible");c[0]!==E[0]&&c.parents(n).length===0&&c.add(s).length>1&&!c.attr("disabled")&&z.hide(b)}),"number"===typeof t.hide.inactive&&(f.show.bind("qtip-"+w+"-inactive",o),a.each(g.inactiveEvents,function(a,b){f.hide.add(G.tooltip).bind(b+F+"-inactive",o)})),a.each(h.hide,function(b,c){var d=a.inArray(c,h.show),e=a(f.hide);d>-1&&e.add(f.show).length===e.length||c==="unfocus"?(f.show.bind(c+F,function(a){E.is(":visible")?l(a):k(a)}),delete h.show[d]):f.hide.bind(c+F,l)}),a.each(h.show,function(a,b){f.show.bind(b+F,k)}),"number"===typeof t.hide.distance&&f.show.add(E).bind("mousemove"+F,function(a){var b=H.origin||{},c=t.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&z.hide(a)}),c.target==="mouse"&&(f.show.bind("mousemove"+F,function(a){i={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),c.adjust.mouse&&(t.hide.event&&E.bind("mouseleave"+F,function(a){(a.relatedTarget||a.target)!==f.show[0]&&z.hide(a)}),f.document.bind("mousemove"+F,function(a){!E.hasClass(m)&&E.is(":visible")&&z.reposition(a||i)}))),(c.adjust.resize||f.viewport.length)&&(a.event.special.resize?f.viewport:f.window).bind("resize"+F,p),(f.viewport.length||j&&E.css("position")==="fixed")&&f.viewport.bind("scroll"+F,p)}function P(b,d){function g(b){function i(c){c&&(delete h[c.src],clearTimeout(z.timers.img[c.src]),a(c).unbind(F)),a.isEmptyObject(h)&&(z.redraw(),d!==e&&z.reposition(H.event),b())}var g,h={};if((g=f.find("img:not([height]):not([width])")).length===0)return i();g.each(function(b,d){if(h[d.src]===c){var e=0,f=3;(function g(){if(d.height||d.width||e>f)return i(d);e+=1,z.timers.img[d.src]=setTimeout(g,700)})(),a(d).bind("error"+F+" load"+F,function(){i(this)}),h[d.src]=d}})}var f=G.content;if(!z.rendered||!b)return e;a.isFunction(b)&&(b=b.call(s,H.event,z)||""),b.jquery&&b.length>0?f.empty().append(b.css({display:"block"})):f.html(b),z.rendered<0?E.queue("fx",g):(D=0,g(a.noop));return z}function O(b,c){var d=G.title;if(!z.rendered||!b)return e;a.isFunction(b)&&(b=b.call(s,H.event,z));if(b===e)return K(e);b.jquery&&b.length>0?d.empty().append(b.css({display:"block"})):d.html(b),z.redraw(),c!==e&&z.rendered&&E.is(":visible")&&z.reposition(H.event)}function N(a){var b=G.button,c=G.title;if(!z.rendered)return e;a?(c||M(),L()):b.remove()}function M(){var b=B+"-title";G.titlebar&&K(),G.titlebar=a("<div />",{"class":k+"-titlebar "+(t.style.widget?"ui-widget-header":"")}).append(G.title=a("<div />",{id:b,"class":k+"-title","aria-atomic":d})).insertBefore(G.content).delegate(".ui-tooltip-close","mousedown keydown mouseup keyup mouseout",function(b){a(this).toggleClass("ui-state-active ui-state-focus",b.type.substr(-4)==="down")}).delegate(".ui-tooltip-close","mouseover mouseout",function(b){a(this).toggleClass("ui-state-hover",b.type==="mouseover")}),t.content.title.button?L():z.rendered&&z.redraw()}function L(){var b=t.content.title.button,c=typeof b==="string",d=c?b:"Close tooltip";G.button&&G.button.remove(),b.jquery?G.button=b:G.button=a("<a />",{"class":"ui-state-default ui-tooltip-close "+(t.style.widget?"":k+"-icon"),title:d,"aria-label":d}).prepend(a("<span />",{"class":"ui-icon ui-icon-close",html:"×"})),G.button.appendTo(G.titlebar).attr("role","button").click(function(a){E.hasClass(m)||z.hide(a);return e}),z.redraw()}function K(a){G.title&&(G.titlebar.remove(),G.titlebar=G.title=G.button=f,a!==e&&z.reposition())}function J(){var a=t.style.widget;E.toggleClass(l,a).toggleClass(o,!a),G.content.toggleClass(l+"-content",a),G.titlebar&&G.titlebar.toggleClass(l+"-header",a),G.button&&G.button.toggleClass(k+"-icon",!a)}function I(a){var b=0,c,d=t,e=a.split(".");while(d=d[e[b++]])b<e.length&&(c=d);return[c||t,e.pop()]}var z=this,A=document.body,B=k+"-"+w,C=0,D=0,E=a(),F=".qtip-"+w,G,H;z.id=w,z.rendered=e,z.elements=G={target:s},z.timers={img:{}},z.options=t,z.checks={},z.plugins={},z.cache=H={event:{},target:a(),disabled:e,attr:y},z.checks.builtin={"^id$":function(b,c,f){var h=f===d?g.nextid:f,i=k+"-"+h;h!==e&&h.length>0&&!a("#"+i).length&&(E[0].id=i,G.content[0].id=i+"-content",G.title[0].id=i+"-title")},"^content.text$":function(a,b,c){P(c)},"^content.title.text$":function(a,b,c){if(!c)return K();!G.title&&c&&M(),O(c)},"^content.title.button$":function(a,b,c){N(c)},"^position.(my|at)$":function(a,b,c){"string"===typeof c&&(a[b]=new h.Corner(c))},"^position.container$":function(a,b,c){z.rendered&&E.appendTo(c)},"^show.ready$":function(){z.rendered?z.toggle(d):z.render(1)},"^style.classes$":function(a,b,c){E.attr("class",k+" qtip ui-helper-reset "+c)},"^style.widget|content.title":J,"^events.(render|show|move|hide|focus|blur)$":function(b,c,d){E[(a.isFunction(d)?"":"un")+"bind"]("tooltip"+c,d)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){var a=t.position;E.attr("tracking",a.target==="mouse"&&a.adjust.mouse),R(),Q()}},a.extend(z,{render:function(b){if(z.rendered)return z;var c=t.content.text,f=t.content.title.text,g=t.position,i=a.Event("tooltiprender");a.attr(s[0],"aria-describedby",B),E=G.tooltip=a("<div/>",{id:B,"class":k+" qtip ui-helper-reset "+o+" "+t.style.classes+" "+k+"-pos-"+t.position.my.abbreviation(),width:t.style.width||"",height:t.style.height||"",tracking:g.target==="mouse"&&g.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":e,"aria-describedby":B+"-content","aria-hidden":d}).toggleClass(m,H.disabled).data("qtip",z).appendTo(t.position.container).append(G.content=a("<div />",{"class":k+"-content",id:B+"-content","aria-atomic":d})),z.rendered=-1,C=D=1,f&&(M(),a.isFunction(f)||O(f,e)),a.isFunction(c)||P(c,e),z.rendered=d,J(),a.each(t.events,function(b,c){a.isFunction(c)&&E.bind(b==="toggle"?"tooltipshow tooltiphide":"tooltip"+b,c)}),a.each(h,function(){this.initialize==="render"&&this(z)}),Q(),E.queue("fx",function(a){i.originalEvent=H.event,E.trigger(i,[z]),C=D=0,z.redraw(),(t.show.ready||b)&&z.toggle(d,H.event),a()});return z},get:function(a){var b,c;switch(a.toLowerCase()){case"dimensions":b={height:E.outerHeight(),width:E.outerWidth()};break;case"offset":b=h.offset(E,t.position.container);break;default:c=I(a.toLowerCase()),b=c[0][c[1]],b=b.precedance?b.string():b}return b},set:function(b,c){function m(a,b){var c,d,e;for(c in k)for(d in k[c])if(e=(new RegExp(d,"i")).exec(a))b.push(e),k[c][d].apply(z,b)}var g=/^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,h=/^content\.(title|attr)|style/i,i=e,j=e,k=z.checks,l;"string"===typeof b?(l=b,b={},b[l]=c):b=a.extend(d,{},b),a.each(b,function(c,d){var e=I(c.toLowerCase()),f;f=e[0][e[1]],e[0][e[1]]="object"===typeof d&&d.nodeType?a(d):d,b[c]=[e[0],e[1],d,f],i=g.test(c)||i,j=h.test(c)||j}),x(t),C=D=1,a.each(b,m),C=D=0,E.is(":visible")&&z.rendered&&(i&&z.reposition(t.position.target==="mouse"?f:H.event),j&&z.redraw());return z},toggle:function(b,c){function q(){b?(a.browser.msie&&E[0].style.removeAttribute("filter"),E.css("overflow",""),"string"===typeof h.autofocus&&a(h.autofocus,E).focus(),p=a.Event("tooltipvisible"),p.originalEvent=c?H.event:f,E.trigger(p,[z]),h.target.trigger("qtip-"+w+"-inactive")):E.css({display:"",visibility:"",opacity:"",left:"",top:""})}if(!z.rendered)return b?z.render(1):z;var g=b?"show":"hide",h=t[g],j=E.is(":visible"),k=!c||t[g].target.length<2||H.target[0]===c.target,l=t.position,m=t.content,o,p;(typeof b).search("boolean|number")&&(b=!j);if(!E.is(":animated")&&j===b&&k)return z;if(c){if(/over|enter/.test(c.type)&&/out|leave/.test(H.event.type)&&c.target===t.show.target[0]&&E.has(c.relatedTarget).length)return z;H.event=a.extend({},c)}p=a.Event("tooltip"+g),p.originalEvent=c?H.event:f,E.trigger(p,[z,90]);if(p.isDefaultPrevented())return z;a.attr(E[0],"aria-hidden",!b),b?(H.origin=a.extend({},i),z.focus(c),a.isFunction(m.text)&&P(m.text,e),a.isFunction(m.title.text)&&O(m.title.text,e),!v&&l.target==="mouse"&&l.adjust.mouse&&(a(document).bind("mousemove.qtip",function(a){i={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),v=d),z.reposition(c),(p.solo=!!h.solo)&&a(n,h.solo).not(E).qtip("hide",p)):(clearTimeout(z.timers.show),delete H.origin,v&&!a(n+'[tracking="true"]:visible',h.solo).not(E).length&&(a(document).unbind("mousemove.qtip"),v=e),z.blur(c)),k&&E.stop(0,1),h.effect===e?(E[g](),q.call(E)):a.isFunction(h.effect)?(h.effect.call(E,z),E.queue("fx",function(a){q(),a()})):E.fadeTo(90,b?1:0,q),b&&h.target.trigger("qtip-"+w+"-inactive");return z},show:function(a){return z.toggle(d,a)},hide:function(a){return z.toggle(e,a)},focus:function(b){if(!z.rendered)return z;var c=a(n),d=parseInt(E[0].style.zIndex,10),e=g.zindex+c.length,f=a.extend({},b),h,i;E.hasClass(p)||(i=a.Event("tooltipfocus"),i.originalEvent=f,E.trigger(i,[z,e]),i.isDefaultPrevented()||(d!==e&&(c.each(function(){this.style.zIndex>d&&(this.style.zIndex=this.style.zIndex-1)}),c.filter("."+p).qtip("blur",f)),E.addClass(p)[0].style.zIndex=e));return z},blur:function(b){var c=a.extend({},b),d;E.removeClass(p),d=a.Event("tooltipblur"),d.originalEvent=c,E.trigger(d,[z]);return z},reposition:function(c,d){if(!z.rendered||C)return z;C=1;var f=t.position.target,g=t.position,j=g.my,l=g.at,m=g.adjust,n=m.method.split(" "),o=E.outerWidth(),p=E.outerHeight(),q=0,r=0,s=a.Event("tooltipmove"),u=E.css("position")==="fixed",v=g.viewport,w={left:0,top:0},x=g.container,y=e,B=z.plugins.tip,D={horizontal:n[0],vertical:n[1]=n[1]||n[0],enabled:v.jquery&&f[0]!==b&&f[0]!==A&&m.method!=="none",left:function(a){var b=D.horizontal==="shift",c=-x.offset.left+v.offset.left+v.scrollLeft,d=j.x==="left"?o:j.x==="right"?-o:-o/2,e=l.x==="left"?q:l.x==="right"?-q:-q/2,f=B&&B.size?B.size.width||0:0,g=B&&B.corner&&B.corner.precedance==="x"&&!b?f:0,h=c-a+g,i=a+o-v.width-c+g,k=d-(j.precedance==="x"||j.x===j.y?e:0),n=j.x==="center";b?(g=B&&B.corner&&B.corner.precedance==="y"?f:0,k=(j.x==="left"?1:-1)*d-g,w.left+=h>0?h:i>0?-i:0,w.left=Math.max(-x.offset.left+v.offset.left+(g&&B.corner.x==="center"?B.offset:0),a-k,Math.min(Math.max(-x.offset.left+v.offset.left+v.width,a+k),w.left))):(h>0&&(j.x!=="left"||i>0)?w.left-=k:i>0&&(j.x!=="right"||h>0)&&(w.left-=n?-k:k),w.left!==a&&n&&(w.left-=m.x),w.left<c&&-w.left>i&&(w.left=a));return w.left-a},top:function(a){var b=D.vertical==="shift",c=-x.offset.top+v.offset.top+v.scrollTop,d=j.y==="top"?p:j.y==="bottom"?-p:-p/2,e=l.y==="top"?r:l.y==="bottom"?-r:-r/2,f=B&&B.size?B.size.height||0:0,g=B&&B.corner&&B.corner.precedance==="y"&&!b?f:0,h=c-a+g,i=a+p-v.height-c+g,k=d-(j.precedance==="y"||j.x===j.y?e:0),n=j.y==="center";b?(g=B&&B.corner&&B.corner.precedance==="x"?f:0,k=(j.y==="top"?1:-1)*d-g,w.top+=h>0?h:i>0?-i:0,w.top=Math.max(-x.offset.top+v.offset.top+(g&&B.corner.x==="center"?B.offset:0),a-k,Math.min(Math.max(-x.offset.top+v.offset.top+v.height,a+k),w.top))):(h>0&&(j.y!=="top"||i>0)?w.top-=k:i>0&&(j.y!=="bottom"||h>0)&&(w.top-=n?-k:k),w.top!==a&&n&&(w.top-=m.y),w.top<0&&-w.top>i&&(w.top=a));return w.top-a}},F;if(a.isArray(f)&&f.length===2)l={x:"left",y:"top"},w={left:f[0],top:f[1]};else if(f==="mouse"&&(c&&c.pageX||H.event.pageX))l={x:"left",y:"top"},c=(c&&(c.type==="resize"||c.type==="scroll")?H.event:c&&c.pageX&&c.type==="mousemove"?c:i&&i.pageX&&(m.mouse||!c||!c.pageX)?{pageX:i.pageX,pageY:i.pageY}:!m.mouse&&H.origin&&H.origin.pageX?H.origin:c)||c||H.event||i||{},w={top:c.pageY,left:c.pageX};else{f==="event"?c&&c.target&&c.type!=="scroll"&&c.type!=="resize"?f=H.target=a(c.target):f=H.target:H.target=a(f),f=a(f).eq(0);if(f.length===0)return z;f[0]===document||f[0]===b?(q=h.iOS?b.innerWidth:f.width(),r=h.iOS?b.innerHeight:f.height(),f[0]===b&&(w={top:u||h.iOS?(v||f).scrollTop():0,left:u||h.iOS?(v||f).scrollLeft():0})):f.is("area")&&h.imagemap?w=h.imagemap(f,l,D.enabled?n:e):f[0].namespaceURI==="http://www.w3.org/2000/svg"&&h.svg?w=h.svg(f,l):(q=f.outerWidth(),r=f.outerHeight(),w=h.offset(f,x)),w.offset&&(q=w.width,r=w.height,y=w.flipoffset,w=w.offset);if(h.iOS<4.1&&h.iOS>3.1||h.iOS==4.3||!h.iOS&&u)F=a(b),w.left-=F.scrollLeft(),w.top-=F.scrollTop();w.left+=l.x==="right"?q:l.x==="center"?q/2:0,w.top+=l.y==="bottom"?r:l.y==="center"?r/2:0}w.left+=m.x+(j.x==="right"?-o:j.x==="center"?-o/2:0),w.top+=m.y+(j.y==="bottom"?-p:j.y==="center"?-p/2:0),D.enabled?(v={elem:v,height:v[(v[0]===b?"h":"outerH")+"eight"](),width:v[(v[0]===b?"w":"outerW")+"idth"](),scrollLeft:u?0:v.scrollLeft(),scrollTop:u?0:v.scrollTop(),offset:v.offset()||{left:0,top:0}},x={elem:x,scrollLeft:x.scrollLeft(),scrollTop:x.scrollTop(),offset:x.offset()||{left:0,top:0}},w.adjusted={left:D.horizontal!=="none"?D.left(w.left):0,top:D.vertical!=="none"?D.top(w.top):0},w.adjusted.left+w.adjusted.top&&E.attr("class",E[0].className.replace(/ui-tooltip-pos-\w+/i,k+"-pos-"+j.abbreviation())),y&&w.adjusted.left&&(w.left+=y.left),y&&w.adjusted.top&&(w.top+=y.top)):w.adjusted={left:0,top:0},s.originalEvent=a.extend({},c),E.trigger(s,[z,w,v.elem||v]);if(s.isDefaultPrevented())return z;delete w.adjusted,d===e||isNaN(w.left)||isNaN(w.top)||f==="mouse"||!a.isFunction(g.effect)?E.css(w):a.isFunction(g.effect)&&(g.effect.call(E,z,a.extend({},w)),E.queue(function(b){a(this).css({opacity:"",height:""}),a.browser.msie&&this.style.removeAttribute("filter"),b()})),C=0;return z},redraw:function(){if(z.rendered<1||D)return z;var a=t.position.container,b,c,d,e;D=1,t.style.height&&E.css("height",t.style.height),t.style.width?E.css("width",t.style.width):(E.css("width","").addClass(r),c=E.width()+1,d=E.css("max-width")||"",e=E.css("min-width")||"",b=(d+e).indexOf("%")>-1?a.width()/100:0,d=(d.indexOf("%")>-1?b:1)*parseInt(d,10)||c,e=(e.indexOf("%")>-1?b:1)*parseInt(e,10)||0,c=d+e?Math.min(Math.max(c,e),d):c,E.css("width",Math.round(c)).removeClass(r)),D=0;return z},disable:function(b){"boolean"!==typeof b&&(b=!E.hasClass(m)&&!H.disabled),z.rendered?(E.toggleClass(m,b),a.attr(E[0],"aria-disabled",b)):H.disabled=!!b;return z},enable:function(){return z.disable(e)},destroy:function(){var b=s[0],c=a.attr(b,u),d=s.data("qtip");z.rendered&&(E.remove(),a.each(z.plugins,function(){this.destroy&&this.destroy()})),clearTimeout(z.timers.show),clearTimeout(z.timers.hide),R();if(!d||z===d)a.removeData(b,"qtip"),t.suppress&&c&&(a.attr(b,"title",c),s.removeAttr(u)),s.removeAttr("aria-describedby");s.unbind(".qtip-"+w),delete j[z.id];return s}})}function x(b){var c;if(!b||"object"!==typeof b)return e;if(b.metadata===f||"object"!==typeof b.metadata)b.metadata={type:b.metadata};if("content"in b){if(b.content===f||"object"!==typeof b.content||b.content.jquery)b.content={text:b.content};c=b.content.text||e,!a.isFunction(c)&&(!c&&!c.attr||c.length<1||"object"===typeof c&&!c.jquery)&&(b.content.text=e);if("title"in b.content){if(b.content.title===f||"object"!==typeof b.content.title)b.content.title={text:b.content.title};c=b.content.title.text||e,!a.isFunction(c)&&(!c&&!c.attr||c.length<1||"object"===typeof c&&!c.jquery)&&(b.content.title.text=e)}}if("position"in b)if(b.position===f||"object"!==typeof b.position)b.position={my:b.position,at:b.position};if("show"in b)if(b.show===f||"object"!==typeof b.show)b.show.jquery?b.show={target:b.show}:b.show={event:b.show};if("hide"in b)if(b.hide===f||"object"!==typeof b.hide)b.hide.jquery?b.hide={target:b.hide}:b.hide={event:b.hide};if("style"in b)if(b.style===f||"object"!==typeof b.style)b.style={classes:b.style};a.each(h,function(){this.sanitize&&this.sanitize(b)});return b}function w(){w.history=w.history||[],w.history.push(arguments);if("object"===typeof console){var a=console[console.warn?"warn":"log"],b=Array.prototype.slice.call(arguments),c;typeof arguments[0]==="string"&&(b[0]="qTip2: "+b[0]),c=a.apply?a.apply(console,b):a(b)}}"use strict";var d=!0,e=!1,f=null,g,h,i,j={},k="ui-tooltip",l="ui-widget",m="ui-state-disabled",n="div.qtip."+k,o=k+"-default",p=k+"-focus",q=k+"-hover",r=k+"-fluid",s="-31000px",t="_replacedByqTip",u="oldtitle",v;g=a.fn.qtip=function(b,h,i){var j=(""+b).toLowerCase(),k=f,l=a.makeArray(arguments).slice(1),m=l[l.length-1],n=this[0]?a.data(this[0],"qtip"):f;if(!arguments.length&&n||j==="api")return n;if("string"===typeof b){this.each(function(){var b=a.data(this,"qtip");if(!b)return d;m&&m.timeStamp&&(b.cache.event=m);if(j!=="option"&&j!=="options"||!h)b[j]&&b[j].apply(b[j],l);else if(a.isPlainObject(h)||i!==c)b.set(h,i);else{k=b.get(h);return e}});return k!==f?k:this}if("object"===typeof b||!arguments.length){n=x(a.extend(d,{},b));return g.bind.call(this,n,m)}},g.bind=function(b,f){return this.each(function(k){function r(b){function d(){p.render(typeof b==="object"||l.show.ready),m.show.add(m.hide).unbind(o)}if(p.cache.disabled)return e;p.cache.event=a.extend({},b),p.cache.target=b?a(b.target):[c],l.show.delay>0?(clearTimeout(p.timers.show),p.timers.show=setTimeout(d,l.show.delay),n.show!==n.hide&&m.hide.bind(n.hide,function(){clearTimeout(p.timers.show)})):d()}var l,m,n,o,p,q;q=a.isArray(b.id)?b.id[k]:b.id,q=!q||q===e||q.length<1||j[q]?g.nextid++:j[q]=q,o=".qtip-"+q+"-create",p=z.call(this,q,b);if(p===e)return d;l=p.options,a.each(h,function(){this.initialize==="initialize"&&this(p)}),m={show:l.show.target,hide:l.hide.target},n={show:a.trim(""+l.show.event).replace(/ /g,o+" ")+o,hide:a.trim(""+l.hide.event).replace(/ /g,o+" ")+o},/mouse(over|enter)/i.test(n.show)&&!/mouse(out|leave)/i.test(n.hide)&&(n.hide+=" mouseleave"+o),m.show.bind("mousemove"+o,function(a){i={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),m.show.bind(n.show,r),(l.show.ready||l.prerender)&&r(f)})},h=g.plugins={Corner:function(a){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,"center").toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.precedance=a.charAt(0).search(/^(t|b)/)>-1?"y":"x",this.string=function(){return this.precedance==="y"?this.y+this.x:this.x+this.y},this.abbreviation=function(){var a=this.x.substr(0,1),b=this.y.substr(0,1);return a===b?a:a==="c"||a!=="c"&&b!=="c"?b+a:a+b}},offset:function(a,b){function i(a,b){c.left+=b*a.scrollLeft(),c.top+=b*a.scrollTop()}var c=a.offset(),d=b,e=0,f=document.body,g,h;if(d){do{d.css("position")!=="static"&&(g=d[0]===f?{left:parseInt(d.css("left"),10)||0,top:parseInt(d.css("top"),10)||0}:d.position(),c.left-=g.left+(parseInt(d.css("borderLeftWidth"),10)||0)+(parseInt(d.css("marginLeft"),10)||0),c.top-=g.top+(parseInt(d.css("borderTopWidth"),10)||0),h=d.css("overflow"),(h==="scroll"||h==="auto")&&++e);if(d[0]===f)break}while(d=d.offsetParent());b[0]!==f&&e&&i(b,1)}return c},iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,3})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_","."))||e,fn:{attr:function(b,c){if(this.length){var d=this[0],e="title",f=a.data(d,"qtip");if(b===e&&f&&"object"===typeof f&&f.options.suppress){if(arguments.length<2)return a.attr(d,u);f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",c);return this.attr(u,c)}}return a.fn["attr"+t].apply(this,arguments)},clone:function(b){var c=a([]),d="title",e=a.fn["clone"+t].apply(this,arguments);b||e.filter("["+u+"]").attr("title",function(){return a.attr(this,u)}).removeAttr(u);return e},remove:a.ui?f:function(b,c){a.ui||a(this).each(function(){c||(!b||a.filter(b,[this]).length)&&a("*",this).add(this).each(function(){a(this).triggerHandler("remove")})})}}},a.each(h.fn,function(b,c){if(!c||a.fn[b+t])return d;var e=a.fn[b+t]=a.fn[b];a.fn[b]=function(){return c.apply(this,arguments)||e.apply(this,arguments)}}),g.version="nightly",g.nextid=0,g.inactiveEvents="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),g.zindex=15e3,g.defaults={prerender:e,id:e,overwrite:d,suppress:d,content:{text:d,attr:"title",title:{text:e,button:e}},position:{my:"top left",at:"bottom right",target:e,container:e,viewport:e,adjust:{x:0,y:0,mouse:d,resize:d,method:"flip flip"},effect:function(b,c,d){a(this).animate(c,{duration:200,queue:e})}},show:{target:e,event:"mouseenter",effect:d,delay:90,solo:e,ready:e,autofocus:e},hide:{target:e,event:"mouseleave",effect:d,delay:0,fixed:e,inactive:e,leave:"window",distance:e},style:{classes:"",widget:e,width:e,height:e},events:{render:f,move:f,show:f,hide:f,toggle:f,visible:f,focus:f,blur:f}},h.ajax=function(a){var b=a.plugins.ajax;return"object"===typeof b?b:a.plugins.ajax=new A(a)},h.ajax.initialize="render",h.ajax.sanitize=function(a){var b=a.content,c;b&&"ajax"in b&&(c=b.ajax,typeof c!=="object"&&(c=a.content.ajax={url:c}),"boolean"!==typeof c.once&&c.once&&(c.once=!!c.once))},a.extend(d,g.defaults,{content:{ajax:{loading:d,once:d}}}),h.tip=function(a){var b=a.plugins.tip;return"object"===typeof b?b:a.plugins.tip=new C(a)},h.tip.initialize="render",h.tip.sanitize=function(a){var b=a.style,c;b&&"tip"in b&&(c=a.style.tip,typeof c!=="object"&&(a.style.tip={corner:c}),/string|boolean/i.test(typeof c.corner)||(c.corner=d),typeof c.width!=="number"&&delete c.width,typeof c.height!=="number"&&delete c.height,typeof c.border!=="number"&&c.border!==d&&delete c.border,typeof c.offset!=="number"&&delete c.offset)},a.extend(d,g.defaults,{style:{tip:{corner:d,mimic:e,width:6,height:6,border:d,offset:0}}})})(jQuery,window) \ No newline at end of file diff --git a/data/js/jquery.tablesorter-2.0.3.min.js b/data/js/jquery.tablesorter-2.0.3.min.js deleted file mode 100644 index 88ae32e77804b90ab93ce9dd9ffa12aeb8b3a44e..0000000000000000000000000000000000000000 --- a/data/js/jquery.tablesorter-2.0.3.min.js +++ /dev/null @@ -1,2 +0,0 @@ - -(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,cells[i]);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,node){var l=parsers.length;for(var i=1;i<l;i++){if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)){return parsers[i];}}return parsers[0];}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=table.tBodies[0].rows[i],cols=[];cache.row.push($(c));for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));}cols.push(i);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){if(!node)return"";var t="";if(config.textExtraction=="simple"){if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){t=node.childNodes[0].innerHTML;}else{t=node.innerHTML;}}else{if(typeof(config.textExtraction)=="function"){t=config.textExtraction(node);}else{t=$(node).text();}}return t;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){rows.push(r[n[i][checkCell]]);if(!table.config.appender){var o=r[n[i][checkCell]];var l=o.length;for(var j=0;j<l;j++){tableBody[0].appendChild(o[j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false,tableHeadersRows=[];for(var i=0;i<table.tHead.rows.length;i++){tableHeadersRows[i]=0;};$tableHeaders=$("thead th",table);$tableHeaders.each(function(index){this.count=0;this.column=index;this.order=formatSortingOrder(table.config.sortInitialOrder);if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(!this.sortDisabled){$(this).addClass(table.config.cssHeader);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){i=(v.toLowerCase()=="desc")?1:0;}else{i=(v==(0||1))?v:0;}return i;}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(getCachedSortType(table.config.parsers,c)=="text")?((order==0)?"sortText":"sortTextDesc"):((order==0)?"sortNumeric":"sortNumericDesc");var e="e"+i;dynamicExp+="var "+e+" = "+s+"(a["+c+"],b["+c+"]); ";dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function sortText(a,b){return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){var DECIMAL='\\'+config.decimal;var exp='/(^[+]?0('+DECIMAL+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)'+DECIMAL+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*'+DECIMAL+'0+$)/';return RegExp(exp).test($.trim(s));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[A?$a��?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}$("tr:visible",table.tBodies[0]).filter(':even').removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]).end().filter(':odd').removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery); \ No newline at end of file diff --git a/data/js/jquery.tablesorter-2.1.10.min.js b/data/js/jquery.tablesorter-2.1.10.min.js new file mode 100644 index 0000000000000000000000000000000000000000..a2170ba965c639e7c9971e55f5e8088ca3100cf1 --- /dev/null +++ b/data/js/jquery.tablesorter-2.1.10.min.js @@ -0,0 +1,6 @@ +/*! +* TableSorter 2.1.10 - Client-side table sorting with ease! +* Minified using http://dean.edwards.name/packer/ +* Copyright (c) 2007 Christian Bach +*/ +!(function($){$.extend({tablesorter:new function(){this.version="2.1.10";var g=[],widgets=[],tbl;this.defaults={cssHeader:"tablesorter-header",cssAsc:"tablesorter-headerSortUp",cssDesc:"tablesorter-headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:false,sortReset:false,sortRestart:false,textExtraction:"simple",parsers:{},widgets:[],headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"mmddyyyy",usNumberFormat:true,onRenderHeader:null,selectorHeaders:'thead th',selectorRemove:"tr.remove-me",tableClass:'tablesorter',debug:false,widgetOptions:{zebra:["even","odd"]}};function log(s){if(typeof console!=="undefined"&&typeof console.log!=="undefined"){console.log(s)}else{alert(s)}}function benchmark(s,d){log(s+" ("+(new Date().getTime()-d.getTime())+"ms)")}this.benchmark=benchmark;this.hasInitialized=false;function getElementText(a,b,c){var d="",te=a.textExtraction;if(!b){return""}if(!a.supportsTextContent){a.supportsTextContent=b.textContent||false}if(te==="simple"){if(a.supportsTextContent){d=b.textContent}else{if(b.childNodes[0]&&b.childNodes[0].hasChildNodes()){d=b.childNodes[0].innerHTML}else{d=b.innerHTML}}}else{if(typeof(te)==="function"){d=te(b,tbl,c)}else if(typeof(te)==="object"&&te.hasOwnProperty(c)){d=te[c](b,tbl,c)}else{d=$(b).text()}}return d}function getParserById(a){var i,l=g.length;for(i=0;i<l;i++){if(g[i].id.toLowerCase()===(a.toString()).toLowerCase()){return g[i]}}return false}function trimAndGetNodeText(a,b,c){return $.trim(getElementText(a,b,c))}function detectParserForColumn(a,b,c,d){var i,l=g.length,node=false,nodeValue='',keepLooking=true;while(nodeValue===''&&keepLooking){c++;if(b[c]){node=b[c].cells[d];nodeValue=trimAndGetNodeText(a.config,node,d);if(a.config.debug){log('Checking if value was empty on row '+c+', column:'+d+": "+nodeValue)}}else{keepLooking=false}}for(i=1;i<l;i++){if(g[i].is(nodeValue,a,node)){return g[i]}}return g[0]}function buildParserCache(a,b){if(a.tBodies.length===0){return}var c=a.tBodies[0].rows,list,cells,l,h,i,p,parsersDebug="";if(c[0]){list=[];cells=c[0].cells;l=cells.length;for(i=0;i<l;i++){p=false;h=$(b[i]);if($.metadata&&(h.metadata()&&h.metadata().sorter)){p=getParserById(h.metadata().sorter)}else if((a.config.headers[i]&&a.config.headers[i].sorter)){p=getParserById(a.config.headers[i].sorter)}else if(h.attr('class')&&h.attr('class').match('sorter-')){p=getParserById(h.attr('class').match(/sorter-(\w+)/)[1]||'')}if(!p){p=detectParserForColumn(a,c,-1,i)}if(a.config.debug){parsersDebug+="column:"+i+"; parser:"+p.id+"\n"}list.push(p)}}if(a.config.debug){log(parsersDebug)}return list}function buildCache(a){var b=a.tBodies[0],totalRows=(b&&b.rows.length)||0,totalCells=(b.rows[0]&&b.rows[0].cells.length)||0,g=a.config.parsers,cache={row:[],normalized:[]},t,i,j,c,cols,cacheTime;if(a.config.debug){cacheTime=new Date()}for(i=0;i<totalRows;++i){c=$(b.rows[i]);cols=[];if(c.hasClass(a.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue}cache.row.push(c);for(j=0;j<totalCells;++j){t=trimAndGetNodeText(a.config,c[0].cells[j],j);cols.push(g[j].format(t,a,c[0].cells[j],j))}cols.push(cache.normalized.length);cache.normalized.push(cols)}if(a.config.debug){benchmark("Building cache for "+totalRows+" rows",cacheTime)}a.config.cache=cache;return cache}function getWidgetById(a){var i,w,l=widgets.length;for(i=0;i<l;i++){w=widgets[i];if(w&&w.hasOwnProperty('id')&&w.id.toLowerCase()===a.toLowerCase()){return w}}}function applyWidget(a,b){var c=a.config.widgets,i,w,l=c.length;for(i=0;i<l;i++){w=getWidgetById(c[i]);if(w){if(b&&w.hasOwnProperty('init')){w.init(a,widgets,w)}else if(!b&&w.hasOwnProperty('format')){w.format(a)}}}}function appendToTable(a,b){var c=a.config,r=b.row,n=b.normalized,totalRows=n.length,checkCell=totalRows?(n[0].length-1):0,rows=[],i,j,l,pos,appendTime;if(c.debug){appendTime=new Date()}for(i=0;i<totalRows;i++){pos=n[i][checkCell];rows.push(r[pos]);if(!c.appender||!c.removeRows){l=r[pos].length;for(j=0;j<l;j++){a.tBodies[0].appendChild(r[pos][j])}}}if(c.appender){c.appender(a,rows)}if(c.debug){benchmark("Rebuilt table",appendTime)}applyWidget(a);$(a).trigger("sortEnd",a)}function computeTableHeaderCellIndexes(t){var a=[],lookup={},thead=t.getElementsByTagName('THEAD')[0],trs=thead.getElementsByTagName('TR'),i,j,k,l,c,cells,rowIndex,cellId,rowSpan,colSpan,firstAvailCol,matrixrow;for(i=0;i<trs.length;i++){cells=trs[i].cells;for(j=0;j<cells.length;j++){c=cells[j];rowIndex=c.parentNode.rowIndex;cellId=rowIndex+"-"+c.cellIndex;rowSpan=c.rowSpan||1;colSpan=c.colSpan||1;if(typeof(a[rowIndex])==="undefined"){a[rowIndex]=[]}for(k=0;k<a[rowIndex].length+1;k++){if(typeof(a[rowIndex][k])==="undefined"){firstAvailCol=k;break}}lookup[cellId]=firstAvailCol;for(k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(a[k])==="undefined"){a[k]=[]}matrixrow=a[k];for(l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x"}}}}return lookup}function formatSortingOrder(v){return(/^d/i.test(v)||v===1)}function checkHeaderMetadata(a){return(($.metadata)&&($(a).metadata().sorter===false))}function checkHeaderOptions(a,i){return((a.config.headers[i])&&(a.config.headers[i].sorter===false))}function checkHeaderLocked(a,i){if((a.config.headers[i])&&(a.config.headers[i].lockedOrder!==null)){return a.config.headers[i].lockedOrder}return false}function checkHeaderOrder(a,i){if((a.config.headers[i])&&(a.config.headers[i].sortInitialOrder)){return a.config.headers[i].sortInitialOrder}return a.config.sortInitialOrder}function buildHeaders(b){var d=($.metadata)?true:false,header_index=computeTableHeaderCellIndexes(b),$th,lock,time,$tableHeaders,c=b.config;c.headerList=[];if(c.debug){time=new Date()}$tableHeaders=$(c.selectorHeaders,b).wrapInner("<div class='tablesorter-header-inner' />").each(function(a){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(checkHeaderOrder(b,a))?[1,0,2]:[0,1,2];this.count=-1;if(checkHeaderMetadata(this)||checkHeaderOptions(b,a)||$(this).hasClass('sorter-false')){this.sortDisabled=true}this.lockedOrder=false;lock=checkHeaderLocked(b,a);if(typeof(lock)!=='undefined'&&lock!==false){this.order=this.lockedOrder=formatSortingOrder(lock)?[1,1,1]:[0,0,0]}if(!this.sortDisabled){$th=$(this).addClass(c.cssHeader);if(c.onRenderHeader){c.onRenderHeader.apply($th,[a])}}c.headerList[a]=this;$(this).parent().addClass(c.cssHeader)});if(c.debug){benchmark("Built headers",time);log($tableHeaders)}return $tableHeaders}function checkCellColSpan(a,b,d){var i,cell,arr=[],r=a.tHead.rows,c=r[d].cells;for(i=0;i<c.length;i++){cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(a,b,d++))}else{if(a.tHead.length===1||(cell.rowSpan>1||!r[d+1])){arr.push(cell)}}}return arr}function isValueInArray(v,a){var i,l=a.length;for(i=0;i<l;i++){if(a[i][0]===v){return true}}return false}function setHeadersCss(b,c,d){var h=[],i,l,css=[b.config.cssDesc,b.config.cssAsc];c.removeClass(css[0]).removeClass(css[1]);c.each(function(a){if(!this.sortDisabled){h[this.column]=$(this)}});l=d.length;for(i=0;i<l;i++){if(d[i][1]===2){continue}h[d[i][0]].addClass(css[d[i][1]])}}function fixColumnWidth(a,b){if(a.config.widthFixed){var c=$('<colgroup>');$("tr:first td",a.tBodies[0]).each(function(){c.append($('<col>').css('width',$(this).width()))});$(a).prepend(c)}}function updateHeaderSortCount(a,b){var i,s,o,c=a.config,l=b.length;for(i=0;i<l;i++){s=b[i];o=c.headerList[s[0]];o.count=s[1]%(c.sortReset?3:2)}}function getCachedSortType(a,i){return(a)?a[i].type:''}function multisort(a,b,d){var f="var sortWrapper = function(a,b) {",col,mx=0,dir=0,tc=a.config,lc=d.normalized.length,l=b.length,sortTime,i,j,c,s,e,order,orgOrderCol;if(tc.debug){sortTime=new Date()}for(i=0;i<l;i++){c=b[i][0];order=b[i][1];s=(getCachedSortType(tc.parsers,c)==="text")?((order===0)?"sortText":"sortTextDesc"):((order===0)?"sortNumeric":"sortNumericDesc");e="e"+i;if(/Numeric/.test(s)&&tc.headers[c]&&tc.headers[c].string){for(j=0;j<lc;j++){col=Math.abs(parseFloat(d.normalized[j][c]));mx=Math.max(mx,isNaN(col)?0:col)}dir=(tc.headers[c])?tc.string[tc.headers[c].string]||0:0}f+="var "+e+" = "+s+"(a["+c+"],b["+c+"],"+mx+","+dir+"); ";f+="if ("+e+") { return "+e+"; } ";f+="else { "}orgOrderCol=(d.normalized&&d.normalized[0])?d.normalized[0].length-1:0;f+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(i=0;i<l;i++){f+="}; "}f+="return 0; ";f+="}; ";eval(f);d.normalized.sort(sortWrapper);if(tc.debug){benchmark("Sorting on "+b.toString()+" and dir "+order+" time",sortTime)}return d}function sortText(a,b){if(a===b){return 0}if(a===''){return 1}if(b===''){return-1}if($.data(tbl[0],"tablesorter").sortLocaleCompare){return a.localeCompare(b)}try{var c=0,ax,t,x=/^(\.)?\d/,L=Math.min(a.length,b.length)+1;while(c<L&&a.charAt(c)===b.charAt(c)&&x.test(b.substring(c))===false&&x.test(a.substring(c))===false){c++}a=a.substring(c);b=b.substring(c);if(x.test(a)||x.test(b)){if(x.test(a)===false){return(a)?1:-1}else if(x.test(b)===false){return(b)?-1:1}else{t=parseFloat(a)-parseFloat(b);if(t!==0){return t}else{t=a.search(/[^\.\d]/)}if(t===-1){t=b.search(/[^\.\d]/)}a=a.substring(t);b=b.substring(t)}}return(a>b)?1:-1}catch(er){return 0}}function sortTextDesc(a,b){if(a===b){return 0}if(a===''){return 1}if(b===''){return-1}if($.data(tbl[0],"tablesorter").sortLocaleCompare){return b.localeCompare(a)}return-sortText(a,b)}function getTextValue(a,b,d){if(b){var i,l=a.length,n=b+d;for(i=0;i<l;i++){n+=a.charCodeAt(i)}return d*n}return 0}function sortNumeric(a,b,c,d){if(a===b){return 0}if(a===''){return 1}if(b===''){return-1}if(isNaN(a)){a=getTextValue(a,c,d)}if(isNaN(b)){b=getTextValue(b,c,d)}return a-b}function sortNumericDesc(a,b,c,d){if(a===b){return 0}if(a===''){return 1}if(b===''){return-1}if(isNaN(a)){a=getTextValue(a,c,d)}if(isNaN(b)){b=getTextValue(b,c,d)}return b-a}this.construct=function(f){return this.each(function(){if(!this.tHead||this.tBodies.length===0){return}var d,$document,$headers,cache,config,shiftDown=0,sortOrder,totalRows,$cell,c,i,j,k,a,s,o;this.config={};c=config=$.extend(true,this.config,$.tablesorter.defaults,f);tbl=d=$(this).addClass(this.config.tableClass);$.data(this,"tablesorter",c);$headers=buildHeaders(this);c.parsers=buildParserCache(this,$headers);c.string={max:1,'max+':1,'max-':-1,none:0};cache=buildCache(this);fixColumnWidth(this);$headers.click(function(e){totalRows=(d[0].tBodies[0]&&d[0].tBodies[0].rows.length)||0;if(!this.sortDisabled){d.trigger("sortStart",tbl[0]);$cell=$(this);k=!e[c.sortMultiSortKey];this.count=(this.count+1)%(c.sortReset?3:2);if(c.sortRestart){i=this;$headers.each(function(){if(this!==i&&(k||!$(this).is('.'+c.cssDesc+',.'+c.cssAsc))){this.count=-1}})}i=this.column;if(k){c.sortList=[];if(c.sortForce!==null){a=c.sortForce;for(j=0;j<a.length;j++){if(a[j][0]!==i){c.sortList.push(a[j])}}}if(this.order[this.count]<2){c.sortList.push([i,this.order[this.count]])}}else{if(isValueInArray(i,c.sortList)){for(j=0;j<c.sortList.length;j++){s=c.sortList[j];o=c.headerList[s[0]];if(s[0]===i){s[1]=o.order[o.count];if(s[1]===2){c.sortList.splice(j,1);o.count=-1}}}}else{if(this.order[this.count]<2){c.sortList.push([i,this.order[this.count]])}}}if(c.sortAppend!==null){a=c.sortAppend;for(j=0;j<a.length;j++){if(a[j][0]!==i){c.sortList.push(a[j])}}}d.trigger("sortBegin",tbl[0]);setHeadersCss(d[0],$headers,c.sortList);appendToTable(d[0],multisort(d[0],c.sortList,cache));return false}}).mousedown(function(){if(c.cancelSelection){this.onselectstart=function(){return false};return false}});d.bind("update",function(){var t=this,c=t.config;$(c.selectorRemove,t.tBodies[0]).remove();t.config.parsers=buildParserCache(t,$headers);cache=buildCache(t);d.trigger("sorton",[t.config.sortList])}).bind("updateCell",function(e,a){var b=[(a.parentNode.rowIndex-1),a.cellIndex];cache.normalized[b[0]][b[1]]=c.parsers[b[1]].format(getElementText(c,a,b[1]),d,a,b[1]);c.cache=cache;d.trigger("sorton",[c.sortList])}).bind("addRows",function(e,a){var i,rows=a.filter('tr').length,dat=[],l=a[0].cells.length;for(i=0;i<rows;i++){for(j=0;j<l;j++){dat[j]=c.parsers[j].format(getElementText(c,a[i].cells[j],j),d,a[i].cells[j],j)}dat.push(cache.row.length);cache.row.push([a[i]]);cache.normalized.push(dat);dat=[]}c.cache=cache;d.trigger("sorton",[c.sortList])}).bind("sorton",function(e,a){$(this).trigger("sortStart",tbl[0]);c.sortList=a;var b=c.sortList;updateHeaderSortCount(this,b);setHeadersCss(this,$headers,b);appendToTable(this,multisort(this,b,cache))}).bind("appendCache",function(){appendToTable(this,cache)}).bind("applyWidgetId",function(e,a){getWidgetById(a).format(this)}).bind("applyWidgets",function(){applyWidget(this)});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){c.sortList=$(this).metadata().sortlist}applyWidget(this,true);if(c.sortList.length>0){d.trigger("sorton",[c.sortList])}else{applyWidget(this)}this.hasInitialized=true})};this.addParser=function(b){var i,l=g.length,a=true;for(i=0;i<l;i++){if(g[i].id.toLowerCase()===b.id.toLowerCase()){a=false}}if(a){g.push(b)}};this.addWidget=function(a){widgets.push(a)};this.formatFloat=function(s){if(typeof(s)!=='string'){return s}if(tbl[0].config.usNumberFormat){s=s.replace(/,/g,'')}else{s=s.replace(/[\s|\.]/g,'').replace(/,/g,'.')}var i=parseFloat(s);return isNaN(i)?$.trim(s):i};this.isDigit=function(s){return(/^[\-+]?\d*$/).test($.trim(s.replace(/[,.'\s]/g,'')))};this.clearTableBody=function(a){$(a.tBodies[0]).empty()}}})();$.fn.extend({tablesorter:$.tablesorter.construct});var m=$.tablesorter;m.addParser({id:"text",is:function(s){return true},format:function(s){return $.trim(s.toLocaleLowerCase())},type:"text"});m.addParser({id:"digit",is:function(s){return $.tablesorter.isDigit(s)},format:function(s){return $.tablesorter.formatFloat(s)},type:"numeric"});m.addParser({id:"currency",is:function(s){return(/^[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]/).test(s)},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9,. \-]/g),""))},type:"numeric"});m.addParser({id:"ipAddress",is:function(s){return(/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/).test(s)},format:function(s){var i,item,a=s.split("."),r="",l=a.length;for(i=0;i<l;i++){item=a[i];if(item.length===2){r+="0"+item}else{r+=item}}return $.tablesorter.formatFloat(r)},type:"numeric"});m.addParser({id:"url",is:function(s){return(/^(https?|ftp|file):\/\/$/).test(s)},format:function(s){return $.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''))},type:"text"});m.addParser({id:"isoDate",is:function(s){return(/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/).test(s)},format:function(s){return $.tablesorter.formatFloat((s!=="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"")},type:"numeric"});m.addParser({id:"percent",is:function(s){return(/\%$/).test($.trim(s))},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""))},type:"numeric"});m.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/))},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime())},type:"numeric"});m.addParser({id:"shortDate",is:function(s){return(/\d{1,4}[\/\-\,\.\s+]\d{1,4}[\/\-\.\,\s+]\d{1,4}/).test(s)},format:function(s,a,b,d){var c=a.config,format=(c.headers&&c.headers[d])?c.headers[d].dateFormat||c.dateFormat:c.dateFormat;s=s.replace(/\s+/g," ").replace(/[\-|\.|\,|\s]/g,"/");if(format==="mmddyyyy"){s=s.replace(/(\d{1,2})\/(\d{1,2})\/(\d{4})/,"$3/$1/$2")}else if(format==="ddmmyyyy"){s=s.replace(/(\d{1,2})\/(\d{1,2})\/(\d{4})/,"$3/$2/$1")}else if(format==="yyyymmdd"){s=s.replace(/(\d{4})\/(\d{1,2})\/(\d{1,2})/,"$1/$2/$3")}return $.tablesorter.formatFloat(new Date(s).getTime())},type:"numeric"});m.addParser({id:"time",is:function(s){return(/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/).test(s)},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime())},type:"numeric"});m.addParser({id:"metadata",is:function(s){return false},format:function(s,a,b){var c=a.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(b).metadata()[p]},type:"numeric"});m.addWidget({id:"zebra",format:function(a){var b,row=0,even,time,c=a.config,child=c.cssChildRow,css=["even","odd"];css=c.widgetZebra&&c.hasOwnProperty('css')?c.widgetZebra.css:(c.widgetOptions&&c.widgetOptions.hasOwnProperty('zebra'))?c.widgetOptions.zebra:css;if(a.config.debug){time=new Date()}$("tr:visible",a.tBodies[0]).each(function(i){b=$(this);if(!b.hasClass(child)){row++}even=(row%2===0);b.removeClass(css[even?1:0]).addClass(css[even?0:1])});if(a.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time)}}})})(jQuery); diff --git a/data/js/jquery.tablesorter.widgets.min.js b/data/js/jquery.tablesorter.widgets.min.js new file mode 100644 index 0000000000000000000000000000000000000000..672aa37e0e908ee4edaa4a93aba5be0d007460c1 --- /dev/null +++ b/data/js/jquery.tablesorter.widgets.min.js @@ -0,0 +1,10 @@ +/*! tableSorter 2.1 widgets - updated 4/2/2012 */ +(function(b){ +b.tablesorter.storage=function(a,e,d){var c,g=!1;c={};var i=a.id||b(".tablesorter").index(b(a)),f=window.location.pathname;try{g=!!localStorage.getItem}catch(j){}b.parseJSON&&(g?c=b.parseJSON(localStorage[e])||{}:(c=document.cookie.split(/[;\s|=]/),a=b.inArray(e,c)+1,c=0!==a?b.parseJSON(c[a])||{}:{}));if(d&&JSON&&JSON.hasOwnProperty("stringify")){if(!c[f]||!c[f][i])c[f]||(c[f]={});c[f][i]=d;g?localStorage[e]=JSON.stringify(c):(a=new Date,a.setTime(a.getTime()+31536E6),document.cookie= e+"="+JSON.stringify(c).replace(/\"/g,'"')+"; expires="+a.toGMTString()+"; path=/")}else return c&&c.hasOwnProperty(f)&&c[f].hasOwnProperty(i)?c[f][i]:{}}; +b.tablesorter.addWidget({id:"uitheme",format:function(a){var e,d,c,g,i,f=b(a),j=a.config,h=j.widgetOptions,k=["ui-icon-arrowthick-2-n-s","ui-icon-arrowthick-1-s","ui-icon-arrowthick-1-n"],k=j.widgetUitheme&&j.widgetUitheme.hasOwnProperty("css")?j.widgetUitheme.css||k:h&&h.hasOwnProperty("uitheme")?h.uitheme:k;c=k.join(" ");j.debug&&(e=new Date); f.hasClass("ui-theme")||(f.addClass("ui-widget ui-widget-content ui-corner-all ui-theme"),b.each(j.headerList,function(){b(this).addClass("ui-widget-header ui-corner-all ui-state-default").append('<span class="ui-icon"/>').wrapInner('<div class="tablesorter-inner"/>').hover(function(){b(this).addClass("ui-state-hover")},function(){b(this).removeClass("ui-state-hover")})}));b.each(j.headerList,function(a){g=b(this);if(this.sortDisabled)g.find("span.ui-icon").removeClass(c+" ui-icon");else{d=g.hasClass(j.cssAsc)? k[1]:g.hasClass(j.cssDesc)?k[2]:g.hasClass(j.cssHeader)?k[0]:"";i=f.hasClass("hasStickyHeaders")?f.find("tr."+(h.stickyHeaders||"tablesorter-stickyHeader")).find("th").eq(a).add(g):g;i[d===k[0]?"removeClass":"addClass"]("ui-state-active").find("span.ui-icon").removeClass(c).addClass(d)}});j.debug&&b.tablesorter.benchmark("Applying uitheme widget",e)}}); +b.tablesorter.addWidget({id:"columns",format:function(a){var e,d,c,g,i=a.config,f=i.sortList,j=f.length,h=["primary","secondary","tertiary"],h=i.widgetColumns&& i.widgetColumns.hasOwnProperty("css")?i.widgetColumns.css||h:i.widgetOptions&&i.widgetOptions.hasOwnProperty("columns")?i.widgetOptions.columns||h:h;c=h.length-1;g=h.join(" ");i.debug&&(d=new Date);f&&f[0]?b("tr:visible",a.tBodies[0]).each(function(a){e=b(this).children().removeClass(g);e.eq(f[0][0]).addClass(h[0]);if(1<j)for(a=1;a<j;a++)e.eq(f[a][0]).addClass(h[a]||h[c])}):b("td",a.tBodies[0]).removeClass(g);i.debug&&b.tablesorter.benchmark("Applying Columns widget",d)}}); +b.tablesorter.addWidget({id:"filter", format:function(a){if(!b(a).hasClass("hasFilters")){var e,d,c,g,i,f,j,h=a.config,k=h.widgetOptions,l=k.filter_cssFilter||"tablesorter-filter",n=h.headerList.length,m=b(a).addClass("hasFilters"),a='<tr class="'+l+'">',o;h.debug&&(o=new Date);for(e=0;e<n;e++)a+='<td><input type="search" data-col="'+e+'" class="'+l,a+=h.headers[e]&&h.headers[e].hasOwnProperty("filter")&&!1===h.headers[e].filter||b(h.headerList[e]).is(".filter-false")?' disabled" disabled':'"',a+="></td>";m.find("thead").append(a+="</tr>").find("input."+ l).bind("keyup search",function(){d=m.find("thead").find("input."+l).map(function(){return(b(this).val()||"").toLowerCase()}).get();""===d.join("")?m.find("tr").show():m.find("tbody").find("tr:not(."+h.cssChildRow+")").each(function(){c=!0;f=b(this).nextUntil("tr:not(."+h.cssChildRow+")");g=f.length&&(k&&k.hasOwnProperty("filter_childRows")&&"undefined"!==typeof k.filter_childRows?k.filter_childRows:1)?f.text():"";j=b(this).find("td");for(e=0;e<n;e++)i=(j.eq(e).text()+g).toLowerCase().indexOf(d[e]), ""!==d[e]&&(!k.filter_startsWith&&0<=i||k.filter_startsWith&&0===i)?c=c?!0:!1:""!==d[e]&&(c=!1);b(this)[c?"show":"hide"]();if(f.length)f[c?"show":"hide"]()});m.trigger("applyWidgets")});h.debug&&b.tablesorter.benchmark("Applying Filter widget",o)}}}); +b.tablesorter.addWidget({id:"stickyHeaders",format:function(a){if(!b(a).hasClass("hasStickyHeaders")){var e=b(a).addClass("hasStickyHeaders"),d=a.config.widgetOptions,c=b(window),g=b(a).find("thead"),i=g.find("tr").children(),f=d.stickyHeaders||"tablesorter-stickyHeader", j=i.eq(0),h=g.find("tr.tablesorter-header").clone().removeClass("tablesorter-header").addClass(f).css({width:g.outerWidth(!0),position:"fixed",left:j.offset().left,margin:0,top:0,visibility:"hidden",zIndex:10}),k=h.children(),l="";e.bind("sortEnd",function(a,c){var d=b(c).find("thead tr"),e=d.filter("."+f).children();d.filter(":not(."+f+")").children().each(function(a){e.eq(a).attr("class",b(this).attr("class"))})}).bind("pagerComplete",function(){c.resize()});i.each(function(a){var c=b(this);k.eq(a).bind("click", function(a){c.trigger(a)}).bind("mousedown",function(){this.onselectstart=function(){return!1};return!1}).find(".tablesorter-header-inner").width(c.find(".tablesorter-header-inner").width())});g.prepend(h);c.scroll(function(){var a=j.offset(),b=c.scrollTop(),b=b>a.top&&b<a.top+e.find("tbody").height()?"visible":"hidden";h.css({left:a.left-c.scrollLeft(),visibility:b});b!==l&&(c.resize(),l=b)}).resize(function(){h.css({left:j.offset().left-c.scrollLeft(),width:g.outerWidth()});k.find(".tablesorter-header-inner").each(function(a){b(this).width(i.eq(a).find(".tablesorter-header-inner").width())})})}}}); +b.tablesorter.addWidget({id:"resizable",format:function(a){if(!b(a).hasClass("hasResizable")){b(a).addClass("hasResizable");var e,d,c=a.config,g=b(c.headerList).filter(":gt(0)"),i=0,f=null,j=null,h=function(){i=0;f=j=null;b(window).trigger("resize")};if(d=b.tablesorter.storage?b.tablesorter.storage(a,"tablesorter-resizable"):"")for(e in d)!isNaN(e)&&e<c.headerList.length&&b(c.headerList[e]).width(d[e]);g.each(function(){b(this).append('<div class="tablesorter-resizer" style="cursor:w-resize;position:absolute;height:100%;width:20px;left:-20px;top:0;z-index:1;"></div>').wrapInner('<div style="position:relative;height:100%;width:100%"></div>')}).bind("mousemove", function(a){if(0!==i&&f){var b=a.pageX-i;f.width()<-b||j&&j.width()<=b||(j.width(j.width()+b),i=a.pageX)}}).bind("mouseup",function(){d&&b.tablesorter.storage&&f&&(d[j.index()]=j.width(),b.tablesorter.storage(a,"tablesorter-resizable",d));h();return!1}).find(".tablesorter-resizer").bind("mousedown",function(a){f=b(a.target).closest("th");j=f.prev();i=a.pageX});b(a).find("thead").bind("mouseup mouseleave",function(){h()})}}}); +b.tablesorter.addWidget({id:"saveSort",init:function(a,b,d){d.format(a,!0)}, format:function(a,e){var d,c,g=a.config;d={sortList:g.sortList};g.debug&&(c=new Date);b(a).hasClass("hasSaveSort")?a.hasInitialized&&b.tablesorter.storage&&(b.tablesorter.storage(a,"tablesorter-savesort",d),g.debug&&b.tablesorter.benchmark("saveSort widget: Saving last sort: "+g.sortList,c)):(b(a).addClass("hasSaveSort"),d="",b.tablesorter.storage&&(d=(d=b.tablesorter.storage(a,"tablesorter-savesort"))&&d.hasOwnProperty("sortList")&&b.isArray(d.sortList)?d.sortList:"",g.debug&&b.tablesorter.benchmark("saveSort: Last sort loaded: "+ d,c)),e&&d&&0<d.length?g.sortList=d:a.hasInitialized&&d&&0<d.length&&b(a).trigger("sorton",[d]))}}) +})(jQuery); \ No newline at end of file diff --git a/data/js/massUpdate.js b/data/js/massUpdate.js index 4fa241d00587311fdbba9b8e7fc6a4612b515896..e7524d3f954b2cca5f144925f0ecf1cd784e0276 100644 --- a/data/js/massUpdate.js +++ b/data/js/massUpdate.js @@ -75,5 +75,35 @@ $(document).ready(function(){ this.checked = !this.checked }); }); + + ['.editCheck', '.updateCheck', '.refreshCheck', '.renameCheck', '.deleteCheck'].forEach(function(name) { + var lastCheck = null; + + $(name).click(function(event) { + + if(!lastCheck || !event.shiftKey) { + lastCheck = this; + return; + } + + var check = this; + var found = 0; + + $(name).each(function() { + switch (found) { + case 2: return false; + case 1: + if (!this.disabled) + this.checked = lastCheck.checked; + } + + if (this == check || this == lastCheck) + found++; + }); + + lastClick = this; + }); + + }); }); diff --git a/data/js/newShow.js b/data/js/newShow.js index 7ba6cf7f59d5b79eb4fe8f81f55261f56eaae116..1f5dd8db9f8f4a0fdec3930da886ffee1c3fad3d 100644 --- a/data/js/newShow.js +++ b/data/js/newShow.js @@ -54,8 +54,15 @@ $(document).ready(function(){ else resultStr += '<a href="http://thetvdb.com/?tab=series&id=' + obj[0] + '" onclick=\"window.open(this.href, \'_blank\'); return false;\" ><b>' + obj[1] + '</b></a>'; - if (obj[2] != null) - resultStr += ' (started on ' + obj[2] + ')'; + if (obj[2] != null) { + var startDate = new Date(obj[2]); + var today = new Date(); + if (startDate>today) + resultStr += ' (will debut on ' + obj[2] + ')'; + else + resultStr += ' (started on ' + obj[2] + ')'; + } + resultStr += '<br />'; }); resultStr += '</ul>'; diff --git a/data/js/plotTooltip.js b/data/js/plotTooltip.js index a2e5296cdfe3487ba596e7b1d2d12c5cebb2f7c4..f65725fd5545402c135aed5febefcd86d2a8a6a2 100644 --- a/data/js/plotTooltip.js +++ b/data/js/plotTooltip.js @@ -1,19 +1,40 @@ -$(function(){ - $('body').append('<div id="tooltip" />'); - $('.plotInfo').tooltip( - { - position: 'bottom right', - offset: [0, 5], - delay: 100, - effect: 'fade', - tip: '#tooltip', - onBeforeShow: function(e) { - match = this.getTrigger().attr("id").match(/^plot_info_(\d+)_(\d+)_(\d+)$/); - $('#tooltip').html($.ajax({ - async: false, - data: { show: match[1], episode: match[3], season: match[2] }, - url: $("#sbRoot").val()+'/home/plotDetails' - }).responseText); +$(function () { + $('.plotInfo').each(function () { + match = $(this).attr("id").match(/^plot_info_(\d+)_(\d+)_(\d+)$/); + $(this).qtip({ + content: { + text: 'Loading...', + ajax: { + url: $("#sbRoot").val() + '/home/plotDetails', + type: 'GET', + data: { + show: match[1], + episode: match[3], + season: match[2] + }, + success: function (data, status) { + this.set('content.text', data); + } } - }) -}) + }, + show: { + solo: true + }, + position: { + viewport: $(window), + my: 'left center', + adjust: { + y: -6, + x: 3 + } + }, + style: { + tip: { + corner: true, + method: 'polygon' + }, + classes: 'ui-tooltip-rounded ui-tooltip-shadow ui-tooltip-sb' + } + }); + }); +}); diff --git a/data/js/restart.js b/data/js/restart.js index 86160c9482b6fdc6bfa61ba2e0bc0895323f0130..715065f857716ad50986fc53266bece93fd0568d 100644 --- a/data/js/restart.js +++ b/data/js/restart.js @@ -1,3 +1,9 @@ +if (sbHttpsEnabled != "False" && sbHttpsEnabled != 0) + var sb_base_url = 'https://'+sbHost+':'+sbHttpPort+sbRoot; +else + var sb_base_url = 'http://'+sbHost+':'+sbHttpPort+sbRoot; + +var base_url = window.location.protocol+'//'+window.location.host+sbRoot; var is_alive_url = sbRoot+'/home/is_alive'; var timeout_id; var current_pid = ''; @@ -8,26 +14,26 @@ function is_alive() { $.get(is_alive_url, function(data) { // if it's still initalizing then just wait and try again - if (data == 'nope') { + if (data.msg == 'nope') { $('#shut_down_loading').hide(); $('#shut_down_success').show(); $('#restart_message').show(); setTimeout('is_alive()', 1000); } else { // if this is before we've even shut down then just try again later - if (current_pid == '' || data == current_pid) { - current_pid = data; + if (current_pid == '' || data.msg == current_pid) { + current_pid = data.msg; setTimeout(is_alive, 1000); - // if we're ready to go then refresh the page which'll forward to /home + // if we're ready to go then redirect to new url } else { $('#restart_loading').hide(); $('#restart_success').show(); $('#refresh_message').show(); - location.reload(); + window.location = sb_base_url+'/home'; } } - }); + }, 'jsonp'); } $(document).ready(function() @@ -36,13 +42,26 @@ $(document).ready(function() is_alive(); $('#shut_down_message').ajaxError(function(e, jqxhr, settings, exception) { - if (settings.url != is_alive_url) - return; num_restart_waits += 1; $('#shut_down_loading').hide(); $('#shut_down_success').show(); $('#restart_message').show(); + is_alive_url = sb_base_url+'/home/is_alive'; + + // if https is enabled or you are currently on https and the port or protocol changed just wait 5 seconds then redirect. + // This is because the ajax will fail if the cert is untrusted or the the http ajax requst from https will fail because of mixed content error. + if ((sbHttpsEnabled != "False" && sbHttpsEnabled != 0) || window.location.protocol == "https:") { + if (base_url != sb_base_url) { + timeout_id = 1; + setTimeout(function(){ + $('#restart_loading').hide(); + $('#restart_success').show(); + $('#refresh_message').show(); + }, 3000); + setTimeout("window.location = sb_base_url+'/home'", 5000); + } + } // if it is taking forever just give up if (num_restart_waits > 90) { diff --git a/data/js/tools.tooltip-1.2.5.min.js b/data/js/tools.tooltip-1.2.5.min.js deleted file mode 100644 index 370a39ebac43b589eda3d7e453b5da35a09e38e5..0000000000000000000000000000000000000000 --- a/data/js/tools.tooltip-1.2.5.min.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - - jQuery Tools 1.2.5 Tooltip - UI essentials - - NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. - - http://flowplayer.org/tools/tooltip/ - - Since: November 2008 - Date: Wed Sep 22 06:02:10 2010 +0000 -*/ -(function(f){function p(a,b,c){var h=c.relative?a.position().top:a.offset().top,d=c.relative?a.position().left:a.offset().left,i=c.position[0];h-=b.outerHeight()-c.offset[0];d+=a.outerWidth()+c.offset[1];if(/iPad/i.test(navigator.userAgent))h-=f(window).scrollTop();var j=b.outerHeight()+a.outerHeight();if(i=="center")h+=j/2;if(i=="bottom")h+=j;i=c.position[1];a=b.outerWidth()+a.outerWidth();if(i=="center")d-=a/2;if(i=="left")d-=a;return{top:h,left:d}}function u(a,b){var c=this,h=a.add(c),d,i=0,j= -0,m=a.attr("title"),q=a.attr("data-tooltip"),r=o[b.effect],l,s=a.is(":input"),v=s&&a.is(":checkbox, :radio, select, :button, :submit"),t=a.attr("type"),k=b.events[t]||b.events[s?v?"widget":"input":"def"];if(!r)throw'Nonexistent effect "'+b.effect+'"';k=k.split(/,\s*/);if(k.length!=2)throw"Tooltip: bad events configuration for "+t;a.bind(k[0],function(e){clearTimeout(i);if(b.predelay)j=setTimeout(function(){c.show(e)},b.predelay);else c.show(e)}).bind(k[1],function(e){clearTimeout(j);if(b.delay)i= -setTimeout(function(){c.hide(e)},b.delay);else c.hide(e)});if(m&&b.cancelDefault){a.removeAttr("title");a.data("title",m)}f.extend(c,{show:function(e){if(!d){if(q)d=f(q);else if(b.tip)d=f(b.tip).eq(0);else if(m)d=f(b.layout).addClass(b.tipClass).appendTo(document.body).hide().append(m);else{d=a.next();d.length||(d=a.parent().next())}if(!d.length)throw"Cannot find tooltip for "+a;}if(c.isShown())return c;d.stop(true,true);var g=p(a,d,b);b.tip&&d.html(a.data("title"));e=e||f.Event();e.type="onBeforeShow"; -h.trigger(e,[g]);if(e.isDefaultPrevented())return c;g=p(a,d,b);d.css({position:"absolute",top:g.top,left:g.left});l=true;r[0].call(c,function(){e.type="onShow";l="full";h.trigger(e)});g=b.events.tooltip.split(/,\s*/);if(!d.data("__set")){d.bind(g[0],function(){clearTimeout(i);clearTimeout(j)});g[1]&&!a.is("input:not(:checkbox, :radio), textarea")&&d.bind(g[1],function(n){n.relatedTarget!=a[0]&&a.trigger(k[1].split(" ")[0])});d.data("__set",true)}return c},hide:function(e){if(!d||!c.isShown())return c; -e=e||f.Event();e.type="onBeforeHide";h.trigger(e);if(!e.isDefaultPrevented()){l=false;o[b.effect][1].call(c,function(){e.type="onHide";h.trigger(e)});return c}},isShown:function(e){return e?l=="full":l},getConf:function(){return b},getTip:function(){return d},getTrigger:function(){return a}});f.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","),function(e,g){f.isFunction(b[g])&&f(c).bind(g,b[g]);c[g]=function(n){n&&f(c).bind(g,n);return c}})}f.tools=f.tools||{version:"1.2.5"};f.tools.tooltip= -{conf:{effect:"toggle",fadeOutSpeed:"fast",predelay:0,delay:30,opacity:1,tip:0,position:["top","center"],offset:[0,0],relative:false,cancelDefault:true,events:{def:"mouseenter,mouseleave",input:"focus,blur",widget:"focus mouseenter,blur mouseleave",tooltip:"mouseenter,mouseleave"},layout:"<div/>",tipClass:"tooltip"},addEffect:function(a,b,c){o[a]=[b,c]}};var o={toggle:[function(a){var b=this.getConf(),c=this.getTip();b=b.opacity;b<1&&c.css({opacity:b});c.show();a.call()},function(a){this.getTip().hide(); -a.call()}],fade:[function(a){var b=this.getConf();this.getTip().fadeTo(b.fadeInSpeed,b.opacity,a)},function(a){this.getTip().fadeOut(this.getConf().fadeOutSpeed,a)}]};f.fn.tooltip=function(a){var b=this.data("tooltip");if(b)return b;a=f.extend(true,{},f.tools.tooltip.conf,a);if(typeof a.position=="string")a.position=a.position.split(/,?\s/);this.each(function(){b=new u(f(this),a);f(this).data("tooltip",b)});return a.api?b:this}})(jQuery); diff --git a/init.fedora b/init.fedora index d763c373f58c58f7e2f37612d49448e60c6f170b..190b2f9428d86206e9a8bac212196ec663923930 100755 --- a/init.fedora +++ b/init.fedora @@ -1,5 +1,7 @@ +#!/bin/sh +# ### BEGIN INIT INFO -# Provides: Sick Beard application instance +# Provides: sickbeard # Required-Start: $all # Required-Stop: $all # Default-Start: 2 3 4 5 @@ -23,17 +25,23 @@ lockfile=/var/lock/subsys/$prog ## the defaults username=${SB_USER-sickbeard} homedir=${SB_HOME-/opt/sickbeard} +datadir=${SB_DATA-/opt/sickbeard} pidfile=${SB_PIDFILE-/var/run/sickbeard/sickbeard.pid} nice=${SB_NICE-} ## pidpath=`dirname ${pidfile}` -options=" --daemon --pidfile=${pidfile}" +options=" --daemon --nolaunch --pidfile=${pidfile} --datadir=${datadir}" # create PID directory if not exist and ensure the SickBeard user can write to it if [ ! -d $pidpath ]; then - mkdir -p $pidpath - chown $username $pidpath + mkdir -p $pidpath + chown $username $pidpath +fi + +if [ ! -d $datadir ]; then + mkdir -p $datadir + chown $username $datadir fi start() { @@ -83,4 +91,3 @@ case "$1" in echo $"Usage: $0 {start|stop|status|restart|try-restart|force-reload}" exit 2 esac - diff --git a/init.freebsd b/init.freebsd new file mode 100755 index 0000000000000000000000000000000000000000..8d9ba4b787c4b4187da02f158793db8e183417e1 --- /dev/null +++ b/init.freebsd @@ -0,0 +1,84 @@ +#!/bin/sh +# +# PROVIDE: sickbeard +# REQUIRE: DAEMON sabnzbd +# KEYWORD: shutdown +# +# Add the following lines to /etc/rc.conf.local or /etc/rc.conf +# to enable this service: +# +# sickbeard_enable (bool): Set to NO by default. +# Set it to YES to enable it. +# sickbeard_user: The user account Sick Beard daemon runs as what +# you want it to be. It uses '_sabnzbd' user by +# default. Do not sets it as empty or it will run +# as root. +# sickbeard_dir: Directory where Sick Beard lives. +# Default: /usr/local/sickbeard +# sickbeard_chdir: Change to this directory before running Sick Beard. +# Default is same as sickbeard_dir. +# sickbeard_pid: The name of the pidfile to create. +# Default is sickbeard.pid in sickbeard_dir. +PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin" + +. /etc/rc.subr + +name="sickbeard" +rcvar=${name}_enable + +load_rc_config ${name} + +: ${sickbeard_enable:="NO"} +: ${sickbeard_user:="_sabnzbd"} +: ${sickbeard_dir:="/usr/local/sickbeard"} +: ${sickbeard_chdir:="${sickbeard_dir}"} +: ${sickbeard_pid:="${sickbeard_dir}/sickbeard.pid"} + +WGET="/usr/local/bin/wget" # You need wget for this script to safely shutdown Sick Beard. +HOST="127.0.0.1" # Set Sick Beard address here. +PORT="8081" # Set Sick Beard port here. +SBUSR="" # Set Sick Beard username (if you use one) here. +SBPWD="" # Set Sick Beard password (if you use one) here. + +status_cmd="${name}_status" +stop_cmd="${name}_stop" + +command="/usr/sbin/daemon" +command_args="-f -p ${sickbeard_pid} python ${sickbeard_dir}/SickBeard.py ${sickbeard_flags} --quiet --nolaunch" + +# Check for wget and refuse to start without it. +if [ ! -x "${WGET}" ]; then + warn "Sickbeard not started: You need wget to safely shut down Sick Beard." + exit 1 +fi + +# Ensure user is root when running this script. +if [ `id -u` != "0" ]; then + echo "Oops, you should be root before running this!" + exit 1 +fi + +verify_sickbeard_pid() { + # Make sure the pid corresponds to the Sick Beard process. + pid=`cat ${sickbeard_pid} 2>/dev/null` + ps -p ${pid} | grep -q "python ${sickbeard_dir}/SickBeard.py" + return $? +} + +# Try to stop Sick Beard cleanly by calling shutdown over http. +sickbeard_stop() { + echo "Stopping $name" + verify_sickbeard_pid + ${WGET} -O - -q --user=${SBUSR} --password=${SBPWD} "http://${HOST}:${PORT}/home/shutdown/" >/dev/null + if [ -n "${pid}" ]; then + wait_for_pids ${pid} + echo "Stopped" + fi +} + +sickbeard_status() { + verify_sickbeard_pid && echo "$name is running as ${pid}" || echo "$name is not running" +} + +run_rc_command "$1" + diff --git a/init.ubuntu b/init.ubuntu index 6509898c04075f82b3f45777978ece232ec26398..9515fdefba5bde0a02adb5d10195974684e267cf 100755 --- a/init.ubuntu +++ b/init.ubuntu @@ -1,9 +1,11 @@ #! /bin/sh ### BEGIN INIT INFO -# Provides: Sick Beard application instance -# Required-Start: $all -# Required-Stop: $all +# Provides: sickbeard +# Required-Start: $local_fs $network $remote_fs +# Required-Stop: $local_fs $network $remote_fs +# Should-Start: $NetworkManager +# Should-Stop: $NetworkManager # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts instance of Sick Beard @@ -21,9 +23,6 @@ DAEMON=/usr/bin/python PID_FILE=/var/run/sickbeard/sickbeard.pid PID_PATH=`dirname $PID_FILE` -# startup args -DAEMON_OPTS=" SickBeard.py -q --daemon --pidfile=${PID_FILE}" - # script name NAME=sickbeard @@ -33,6 +32,12 @@ DESC=SickBeard # user RUN_AS=SICKBEARD_USER +# data directory +DATA_DIR=~/.sickbeard + +# startup args +DAEMON_OPTS=" SickBeard.py -q --daemon --pidfile=${PID_FILE} --datadir=${DATA_DIR}" + ############### END EDIT ME ################## test -x $DAEMON || exit 0 @@ -40,8 +45,21 @@ test -x $DAEMON || exit 0 set -e if [ ! -d $PID_PATH ]; then - mkdir -p $PID_PATH - chown $RUN_AS $PID_PATH + mkdir -p $PID_PATH + chown $RUN_AS $PID_PATH +fi + +if [ ! -d $DATA_DIR ]; then + mkdir -p $DATA_DIR + chown $RUN_AS $DATA_DIR +fi + +if [ -e $PID_FILE ]; then + PID=`cat $PID_FILE` + if ! kill -0 $PID > /dev/null 2>&1; then + echo "Removing stale $PID_FILE" + rm $PID_FILE + fi fi case "$1" in @@ -51,13 +69,12 @@ case "$1" in ;; stop) echo "Stopping $DESC" - start-stop-daemon --stop --pidfile $PID_FILE + start-stop-daemon --stop --pidfile $PID_FILE --retry 15 ;; restart|force-reload) echo "Restarting $DESC" - start-stop-daemon --stop --pidfile $PID_FILE - sleep 15 + start-stop-daemon --stop --pidfile $PID_FILE --retry 15 start-stop-daemon -d $APP_PATH -c $RUN_AS --start --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS ;; *) diff --git a/lib/certgen.py b/lib/certgen.py new file mode 100644 index 0000000000000000000000000000000000000000..1b941161bdb70d549ee86fd7ede62f4f6a7e93c8 --- /dev/null +++ b/lib/certgen.py @@ -0,0 +1,82 @@ +# -*- coding: latin-1 -*- +# +# Copyright (C) Martin Sj�gren and AB Strakt 2001, All rights reserved +# Copyright (C) Jean-Paul Calderone 2008, All rights reserved +# This file is licenced under the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1 or later (aka LGPL v2.1) +# Please see LGPL2.1.txt for more information +""" +Certificate generation module. +""" + +from OpenSSL import crypto +import time + +TYPE_RSA = crypto.TYPE_RSA +TYPE_DSA = crypto.TYPE_DSA + +serial = int(time.time()) + + +def createKeyPair(type, bits): + """ + Create a public/private key pair. + + Arguments: type - Key type, must be one of TYPE_RSA and TYPE_DSA + bits - Number of bits to use in the key + Returns: The public/private key pair in a PKey object + """ + pkey = crypto.PKey() + pkey.generate_key(type, bits) + return pkey + +def createCertRequest(pkey, digest="md5", **name): + """ + Create a certificate request. + + Arguments: pkey - The key to associate with the request + digest - Digestion method to use for signing, default is md5 + **name - The name of the subject of the request, possible + arguments are: + C - Country name + ST - State or province name + L - Locality name + O - Organization name + OU - Organizational unit name + CN - Common name + emailAddress - E-mail address + Returns: The certificate request in an X509Req object + """ + req = crypto.X509Req() + subj = req.get_subject() + + for (key,value) in name.items(): + setattr(subj, key, value) + + req.set_pubkey(pkey) + req.sign(pkey, digest) + return req + +def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter), digest="md5"): + """ + Generate a certificate given a certificate request. + + Arguments: req - Certificate reqeust to use + issuerCert - The certificate of the issuer + issuerKey - The private key of the issuer + serial - Serial number for the certificate + notBefore - Timestamp (relative to now) when the certificate + starts being valid + notAfter - Timestamp (relative to now) when the certificate + stops being valid + digest - Digest method to use for signing, default is md5 + Returns: The signed certificate in an X509 object + """ + cert = crypto.X509() + cert.set_serial_number(serial) + cert.gmtime_adj_notBefore(notBefore) + cert.gmtime_adj_notAfter(notAfter) + cert.set_issuer(issuerCert.get_subject()) + cert.set_subject(req.get_subject()) + cert.set_pubkey(req.get_pubkey()) + cert.sign(issuerKey, digest) + return cert diff --git a/lib/dateutil/__init__.py b/lib/dateutil/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..290814cf9ca518f66bc23d1219c63772e22dbd40 --- /dev/null +++ b/lib/dateutil/__init__.py @@ -0,0 +1,9 @@ +""" +Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net> + +This module offers extensions to the standard python 2.3+ +datetime module. +""" +__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" +__license__ = "PSF License" +__version__ = "1.5" diff --git a/lib/dateutil/easter.py b/lib/dateutil/easter.py new file mode 100644 index 0000000000000000000000000000000000000000..d7944104beb186bceda1584c98d431a7e2624371 --- /dev/null +++ b/lib/dateutil/easter.py @@ -0,0 +1,92 @@ +""" +Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net> + +This module offers extensions to the standard python 2.3+ +datetime module. +""" +__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" +__license__ = "PSF License" + +import datetime + +__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"] + +EASTER_JULIAN = 1 +EASTER_ORTHODOX = 2 +EASTER_WESTERN = 3 + +def easter(year, method=EASTER_WESTERN): + """ + This method was ported from the work done by GM Arts, + on top of the algorithm by Claus Tondering, which was + based in part on the algorithm of Ouding (1940), as + quoted in "Explanatory Supplement to the Astronomical + Almanac", P. Kenneth Seidelmann, editor. + + This algorithm implements three different easter + calculation methods: + + 1 - Original calculation in Julian calendar, valid in + dates after 326 AD + 2 - Original method, with date converted to Gregorian + calendar, valid in years 1583 to 4099 + 3 - Revised method, in Gregorian calendar, valid in + years 1583 to 4099 as well + + These methods are represented by the constants: + + EASTER_JULIAN = 1 + EASTER_ORTHODOX = 2 + EASTER_WESTERN = 3 + + The default method is method 3. + + More about the algorithm may be found at: + + http://users.chariot.net.au/~gmarts/eastalg.htm + + and + + http://www.tondering.dk/claus/calendar.html + + """ + + if not (1 <= method <= 3): + raise ValueError, "invalid method" + + # g - Golden year - 1 + # c - Century + # h - (23 - Epact) mod 30 + # i - Number of days from March 21 to Paschal Full Moon + # j - Weekday for PFM (0=Sunday, etc) + # p - Number of days from March 21 to Sunday on or before PFM + # (-6 to 28 methods 1 & 3, to 56 for method 2) + # e - Extra days to add for method 2 (converting Julian + # date to Gregorian date) + + y = year + g = y % 19 + e = 0 + if method < 3: + # Old method + i = (19*g+15)%30 + j = (y+y//4+i)%7 + if method == 2: + # Extra dates to convert Julian to Gregorian date + e = 10 + if y > 1600: + e = e+y//100-16-(y//100-16)//4 + else: + # New method + c = y//100 + h = (c-c//4-(8*c+13)//25+19*g+15)%30 + i = h-(h//28)*(1-(h//28)*(29//(h+1))*((21-g)//11)) + j = (y+y//4+i+2-c+c//4)%7 + + # p can be from -6 to 56 corresponding to dates 22 March to 23 May + # (later dates apply to method 2, although 23 May never actually occurs) + p = i-j+e + d = 1+(p+27+(p+6)//40)%31 + m = 3+(p+26)//30 + return datetime.date(int(y),int(m),int(d)) + diff --git a/lib/dateutil/parser.py b/lib/dateutil/parser.py new file mode 100644 index 0000000000000000000000000000000000000000..5d824e411f32949c95de0a512bfa061a12c68bc1 --- /dev/null +++ b/lib/dateutil/parser.py @@ -0,0 +1,886 @@ +# -*- coding:iso-8859-1 -*- +""" +Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net> + +This module offers extensions to the standard python 2.3+ +datetime module. +""" +__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" +__license__ = "PSF License" + +import datetime +import string +import time +import sys +import os + +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + +import relativedelta +import tz + + +__all__ = ["parse", "parserinfo"] + + +# Some pointers: +# +# http://www.cl.cam.ac.uk/~mgk25/iso-time.html +# http://www.iso.ch/iso/en/prods-services/popstds/datesandtime.html +# http://www.w3.org/TR/NOTE-datetime +# http://ringmaster.arc.nasa.gov/tools/time_formats.html +# http://search.cpan.org/author/MUIR/Time-modules-2003.0211/lib/Time/ParseDate.pm +# http://stein.cshl.org/jade/distrib/docs/java.text.SimpleDateFormat.html + + +class _timelex(object): + + def __init__(self, instream): + if isinstance(instream, basestring): + instream = StringIO(instream) + self.instream = instream + self.wordchars = ('abcdfeghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_' + '��������������������������������' + '������������������������������') + self.numchars = '0123456789' + self.whitespace = ' \t\r\n' + self.charstack = [] + self.tokenstack = [] + self.eof = False + + def get_token(self): + if self.tokenstack: + return self.tokenstack.pop(0) + seenletters = False + token = None + state = None + wordchars = self.wordchars + numchars = self.numchars + whitespace = self.whitespace + while not self.eof: + if self.charstack: + nextchar = self.charstack.pop(0) + else: + nextchar = self.instream.read(1) + while nextchar == '\x00': + nextchar = self.instream.read(1) + if not nextchar: + self.eof = True + break + elif not state: + token = nextchar + if nextchar in wordchars: + state = 'a' + elif nextchar in numchars: + state = '0' + elif nextchar in whitespace: + token = ' ' + break # emit token + else: + break # emit token + elif state == 'a': + seenletters = True + if nextchar in wordchars: + token += nextchar + elif nextchar == '.': + token += nextchar + state = 'a.' + else: + self.charstack.append(nextchar) + break # emit token + elif state == '0': + if nextchar in numchars: + token += nextchar + elif nextchar == '.': + token += nextchar + state = '0.' + else: + self.charstack.append(nextchar) + break # emit token + elif state == 'a.': + seenletters = True + if nextchar == '.' or nextchar in wordchars: + token += nextchar + elif nextchar in numchars and token[-1] == '.': + token += nextchar + state = '0.' + else: + self.charstack.append(nextchar) + break # emit token + elif state == '0.': + if nextchar == '.' or nextchar in numchars: + token += nextchar + elif nextchar in wordchars and token[-1] == '.': + token += nextchar + state = 'a.' + else: + self.charstack.append(nextchar) + break # emit token + if (state in ('a.', '0.') and + (seenletters or token.count('.') > 1 or token[-1] == '.')): + l = token.split('.') + token = l[0] + for tok in l[1:]: + self.tokenstack.append('.') + if tok: + self.tokenstack.append(tok) + return token + + def __iter__(self): + return self + + def next(self): + token = self.get_token() + if token is None: + raise StopIteration + return token + + def split(cls, s): + return list(cls(s)) + split = classmethod(split) + + +class _resultbase(object): + + def __init__(self): + for attr in self.__slots__: + setattr(self, attr, None) + + def _repr(self, classname): + l = [] + for attr in self.__slots__: + value = getattr(self, attr) + if value is not None: + l.append("%s=%s" % (attr, `value`)) + return "%s(%s)" % (classname, ", ".join(l)) + + def __repr__(self): + return self._repr(self.__class__.__name__) + + +class parserinfo(object): + + # m from a.m/p.m, t from ISO T separator + JUMP = [" ", ".", ",", ";", "-", "/", "'", + "at", "on", "and", "ad", "m", "t", "of", + "st", "nd", "rd", "th"] + + WEEKDAYS = [("Mon", "Monday"), + ("Tue", "Tuesday"), + ("Wed", "Wednesday"), + ("Thu", "Thursday"), + ("Fri", "Friday"), + ("Sat", "Saturday"), + ("Sun", "Sunday")] + MONTHS = [("Jan", "January"), + ("Feb", "February"), + ("Mar", "March"), + ("Apr", "April"), + ("May", "May"), + ("Jun", "June"), + ("Jul", "July"), + ("Aug", "August"), + ("Sep", "September"), + ("Oct", "October"), + ("Nov", "November"), + ("Dec", "December")] + HMS = [("h", "hour", "hours"), + ("m", "minute", "minutes"), + ("s", "second", "seconds")] + AMPM = [("am", "a"), + ("pm", "p")] + UTCZONE = ["UTC", "GMT", "Z"] + PERTAIN = ["of"] + TZOFFSET = {} + + def __init__(self, dayfirst=False, yearfirst=False): + self._jump = self._convert(self.JUMP) + self._weekdays = self._convert(self.WEEKDAYS) + self._months = self._convert(self.MONTHS) + self._hms = self._convert(self.HMS) + self._ampm = self._convert(self.AMPM) + self._utczone = self._convert(self.UTCZONE) + self._pertain = self._convert(self.PERTAIN) + + self.dayfirst = dayfirst + self.yearfirst = yearfirst + + self._year = time.localtime().tm_year + self._century = self._year//100*100 + + def _convert(self, lst): + dct = {} + for i in range(len(lst)): + v = lst[i] + if isinstance(v, tuple): + for v in v: + dct[v.lower()] = i + else: + dct[v.lower()] = i + return dct + + def jump(self, name): + return name.lower() in self._jump + + def weekday(self, name): + if len(name) >= 3: + try: + return self._weekdays[name.lower()] + except KeyError: + pass + return None + + def month(self, name): + if len(name) >= 3: + try: + return self._months[name.lower()]+1 + except KeyError: + pass + return None + + def hms(self, name): + try: + return self._hms[name.lower()] + except KeyError: + return None + + def ampm(self, name): + try: + return self._ampm[name.lower()] + except KeyError: + return None + + def pertain(self, name): + return name.lower() in self._pertain + + def utczone(self, name): + return name.lower() in self._utczone + + def tzoffset(self, name): + if name in self._utczone: + return 0 + return self.TZOFFSET.get(name) + + def convertyear(self, year): + if year < 100: + year += self._century + if abs(year-self._year) >= 50: + if year < self._year: + year += 100 + else: + year -= 100 + return year + + def validate(self, res): + # move to info + if res.year is not None: + res.year = self.convertyear(res.year) + if res.tzoffset == 0 and not res.tzname or res.tzname == 'Z': + res.tzname = "UTC" + res.tzoffset = 0 + elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname): + res.tzoffset = 0 + return True + + +class parser(object): + + def __init__(self, info=None): + self.info = info or parserinfo() + + def parse(self, timestr, default=None, + ignoretz=False, tzinfos=None, + **kwargs): + if not default: + default = datetime.datetime.now().replace(hour=0, minute=0, + second=0, microsecond=0) + res = self._parse(timestr, **kwargs) + if res is None: + raise ValueError, "unknown string format" + repl = {} + for attr in ["year", "month", "day", "hour", + "minute", "second", "microsecond"]: + value = getattr(res, attr) + if value is not None: + repl[attr] = value + ret = default.replace(**repl) + if res.weekday is not None and not res.day: + ret = ret+relativedelta.relativedelta(weekday=res.weekday) + if not ignoretz: + if callable(tzinfos) or tzinfos and res.tzname in tzinfos: + if callable(tzinfos): + tzdata = tzinfos(res.tzname, res.tzoffset) + else: + tzdata = tzinfos.get(res.tzname) + if isinstance(tzdata, datetime.tzinfo): + tzinfo = tzdata + elif isinstance(tzdata, basestring): + tzinfo = tz.tzstr(tzdata) + elif isinstance(tzdata, int): + tzinfo = tz.tzoffset(res.tzname, tzdata) + else: + raise ValueError, "offset must be tzinfo subclass, " \ + "tz string, or int offset" + ret = ret.replace(tzinfo=tzinfo) + elif res.tzname and res.tzname in time.tzname: + ret = ret.replace(tzinfo=tz.tzlocal()) + elif res.tzoffset == 0: + ret = ret.replace(tzinfo=tz.tzutc()) + elif res.tzoffset: + ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset)) + return ret + + class _result(_resultbase): + __slots__ = ["year", "month", "day", "weekday", + "hour", "minute", "second", "microsecond", + "tzname", "tzoffset"] + + def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False): + info = self.info + if dayfirst is None: + dayfirst = info.dayfirst + if yearfirst is None: + yearfirst = info.yearfirst + res = self._result() + l = _timelex.split(timestr) + try: + + # year/month/day list + ymd = [] + + # Index of the month string in ymd + mstridx = -1 + + len_l = len(l) + i = 0 + while i < len_l: + + # Check if it's a number + try: + value_repr = l[i] + value = float(value_repr) + except ValueError: + value = None + + if value is not None: + # Token is a number + len_li = len(l[i]) + i += 1 + if (len(ymd) == 3 and len_li in (2, 4) + and (i >= len_l or (l[i] != ':' and + info.hms(l[i]) is None))): + # 19990101T23[59] + s = l[i-1] + res.hour = int(s[:2]) + if len_li == 4: + res.minute = int(s[2:]) + elif len_li == 6 or (len_li > 6 and l[i-1].find('.') == 6): + # YYMMDD or HHMMSS[.ss] + s = l[i-1] + if not ymd and l[i-1].find('.') == -1: + ymd.append(info.convertyear(int(s[:2]))) + ymd.append(int(s[2:4])) + ymd.append(int(s[4:])) + else: + # 19990101T235959[.59] + res.hour = int(s[:2]) + res.minute = int(s[2:4]) + res.second, res.microsecond = _parsems(s[4:]) + elif len_li == 8: + # YYYYMMDD + s = l[i-1] + ymd.append(int(s[:4])) + ymd.append(int(s[4:6])) + ymd.append(int(s[6:])) + elif len_li in (12, 14): + # YYYYMMDDhhmm[ss] + s = l[i-1] + ymd.append(int(s[:4])) + ymd.append(int(s[4:6])) + ymd.append(int(s[6:8])) + res.hour = int(s[8:10]) + res.minute = int(s[10:12]) + if len_li == 14: + res.second = int(s[12:]) + elif ((i < len_l and info.hms(l[i]) is not None) or + (i+1 < len_l and l[i] == ' ' and + info.hms(l[i+1]) is not None)): + # HH[ ]h or MM[ ]m or SS[.ss][ ]s + if l[i] == ' ': + i += 1 + idx = info.hms(l[i]) + while True: + if idx == 0: + res.hour = int(value) + if value%1: + res.minute = int(60*(value%1)) + elif idx == 1: + res.minute = int(value) + if value%1: + res.second = int(60*(value%1)) + elif idx == 2: + res.second, res.microsecond = \ + _parsems(value_repr) + i += 1 + if i >= len_l or idx == 2: + break + # 12h00 + try: + value_repr = l[i] + value = float(value_repr) + except ValueError: + break + else: + i += 1 + idx += 1 + if i < len_l: + newidx = info.hms(l[i]) + if newidx is not None: + idx = newidx + elif i+1 < len_l and l[i] == ':': + # HH:MM[:SS[.ss]] + res.hour = int(value) + i += 1 + value = float(l[i]) + res.minute = int(value) + if value%1: + res.second = int(60*(value%1)) + i += 1 + if i < len_l and l[i] == ':': + res.second, res.microsecond = _parsems(l[i+1]) + i += 2 + elif i < len_l and l[i] in ('-', '/', '.'): + sep = l[i] + ymd.append(int(value)) + i += 1 + if i < len_l and not info.jump(l[i]): + try: + # 01-01[-01] + ymd.append(int(l[i])) + except ValueError: + # 01-Jan[-01] + value = info.month(l[i]) + if value is not None: + ymd.append(value) + assert mstridx == -1 + mstridx = len(ymd)-1 + else: + return None + i += 1 + if i < len_l and l[i] == sep: + # We have three members + i += 1 + value = info.month(l[i]) + if value is not None: + ymd.append(value) + mstridx = len(ymd)-1 + assert mstridx == -1 + else: + ymd.append(int(l[i])) + i += 1 + elif i >= len_l or info.jump(l[i]): + if i+1 < len_l and info.ampm(l[i+1]) is not None: + # 12 am + res.hour = int(value) + if res.hour < 12 and info.ampm(l[i+1]) == 1: + res.hour += 12 + elif res.hour == 12 and info.ampm(l[i+1]) == 0: + res.hour = 0 + i += 1 + else: + # Year, month or day + ymd.append(int(value)) + i += 1 + elif info.ampm(l[i]) is not None: + # 12am + res.hour = int(value) + if res.hour < 12 and info.ampm(l[i]) == 1: + res.hour += 12 + elif res.hour == 12 and info.ampm(l[i]) == 0: + res.hour = 0 + i += 1 + elif not fuzzy: + return None + else: + i += 1 + continue + + # Check weekday + value = info.weekday(l[i]) + if value is not None: + res.weekday = value + i += 1 + continue + + # Check month name + value = info.month(l[i]) + if value is not None: + ymd.append(value) + assert mstridx == -1 + mstridx = len(ymd)-1 + i += 1 + if i < len_l: + if l[i] in ('-', '/'): + # Jan-01[-99] + sep = l[i] + i += 1 + ymd.append(int(l[i])) + i += 1 + if i < len_l and l[i] == sep: + # Jan-01-99 + i += 1 + ymd.append(int(l[i])) + i += 1 + elif (i+3 < len_l and l[i] == l[i+2] == ' ' + and info.pertain(l[i+1])): + # Jan of 01 + # In this case, 01 is clearly year + try: + value = int(l[i+3]) + except ValueError: + # Wrong guess + pass + else: + # Convert it here to become unambiguous + ymd.append(info.convertyear(value)) + i += 4 + continue + + # Check am/pm + value = info.ampm(l[i]) + if value is not None: + if value == 1 and res.hour < 12: + res.hour += 12 + elif value == 0 and res.hour == 12: + res.hour = 0 + i += 1 + continue + + # Check for a timezone name + if (res.hour is not None and len(l[i]) <= 5 and + res.tzname is None and res.tzoffset is None and + not [x for x in l[i] if x not in string.ascii_uppercase]): + res.tzname = l[i] + res.tzoffset = info.tzoffset(res.tzname) + i += 1 + + # Check for something like GMT+3, or BRST+3. Notice + # that it doesn't mean "I am 3 hours after GMT", but + # "my time +3 is GMT". If found, we reverse the + # logic so that timezone parsing code will get it + # right. + if i < len_l and l[i] in ('+', '-'): + l[i] = ('+', '-')[l[i] == '+'] + res.tzoffset = None + if info.utczone(res.tzname): + # With something like GMT+3, the timezone + # is *not* GMT. + res.tzname = None + + continue + + # Check for a numbered timezone + if res.hour is not None and l[i] in ('+', '-'): + signal = (-1,1)[l[i] == '+'] + i += 1 + len_li = len(l[i]) + if len_li == 4: + # -0300 + res.tzoffset = int(l[i][:2])*3600+int(l[i][2:])*60 + elif i+1 < len_l and l[i+1] == ':': + # -03:00 + res.tzoffset = int(l[i])*3600+int(l[i+2])*60 + i += 2 + elif len_li <= 2: + # -[0]3 + res.tzoffset = int(l[i][:2])*3600 + else: + return None + i += 1 + res.tzoffset *= signal + + # Look for a timezone name between parenthesis + if (i+3 < len_l and + info.jump(l[i]) and l[i+1] == '(' and l[i+3] == ')' and + 3 <= len(l[i+2]) <= 5 and + not [x for x in l[i+2] + if x not in string.ascii_uppercase]): + # -0300 (BRST) + res.tzname = l[i+2] + i += 4 + continue + + # Check jumps + if not (info.jump(l[i]) or fuzzy): + return None + + i += 1 + + # Process year/month/day + len_ymd = len(ymd) + if len_ymd > 3: + # More than three members!? + return None + elif len_ymd == 1 or (mstridx != -1 and len_ymd == 2): + # One member, or two members with a month string + if mstridx != -1: + res.month = ymd[mstridx] + del ymd[mstridx] + if len_ymd > 1 or mstridx == -1: + if ymd[0] > 31: + res.year = ymd[0] + else: + res.day = ymd[0] + elif len_ymd == 2: + # Two members with numbers + if ymd[0] > 31: + # 99-01 + res.year, res.month = ymd + elif ymd[1] > 31: + # 01-99 + res.month, res.year = ymd + elif dayfirst and ymd[1] <= 12: + # 13-01 + res.day, res.month = ymd + else: + # 01-13 + res.month, res.day = ymd + if len_ymd == 3: + # Three members + if mstridx == 0: + res.month, res.day, res.year = ymd + elif mstridx == 1: + if ymd[0] > 31 or (yearfirst and ymd[2] <= 31): + # 99-Jan-01 + res.year, res.month, res.day = ymd + else: + # 01-Jan-01 + # Give precendence to day-first, since + # two-digit years is usually hand-written. + res.day, res.month, res.year = ymd + elif mstridx == 2: + # WTF!? + if ymd[1] > 31: + # 01-99-Jan + res.day, res.year, res.month = ymd + else: + # 99-01-Jan + res.year, res.day, res.month = ymd + else: + if ymd[0] > 31 or \ + (yearfirst and ymd[1] <= 12 and ymd[2] <= 31): + # 99-01-01 + res.year, res.month, res.day = ymd + elif ymd[0] > 12 or (dayfirst and ymd[1] <= 12): + # 13-01-01 + res.day, res.month, res.year = ymd + else: + # 01-13-01 + res.month, res.day, res.year = ymd + + except (IndexError, ValueError, AssertionError): + return None + + if not info.validate(res): + return None + return res + +DEFAULTPARSER = parser() +def parse(timestr, parserinfo=None, **kwargs): + if parserinfo: + return parser(parserinfo).parse(timestr, **kwargs) + else: + return DEFAULTPARSER.parse(timestr, **kwargs) + + +class _tzparser(object): + + class _result(_resultbase): + + __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset", + "start", "end"] + + class _attr(_resultbase): + __slots__ = ["month", "week", "weekday", + "yday", "jyday", "day", "time"] + + def __repr__(self): + return self._repr("") + + def __init__(self): + _resultbase.__init__(self) + self.start = self._attr() + self.end = self._attr() + + def parse(self, tzstr): + res = self._result() + l = _timelex.split(tzstr) + try: + + len_l = len(l) + + i = 0 + while i < len_l: + # BRST+3[BRDT[+2]] + j = i + while j < len_l and not [x for x in l[j] + if x in "0123456789:,-+"]: + j += 1 + if j != i: + if not res.stdabbr: + offattr = "stdoffset" + res.stdabbr = "".join(l[i:j]) + else: + offattr = "dstoffset" + res.dstabbr = "".join(l[i:j]) + i = j + if (i < len_l and + (l[i] in ('+', '-') or l[i][0] in "0123456789")): + if l[i] in ('+', '-'): + # Yes, that's right. See the TZ variable + # documentation. + signal = (1,-1)[l[i] == '+'] + i += 1 + else: + signal = -1 + len_li = len(l[i]) + if len_li == 4: + # -0300 + setattr(res, offattr, + (int(l[i][:2])*3600+int(l[i][2:])*60)*signal) + elif i+1 < len_l and l[i+1] == ':': + # -03:00 + setattr(res, offattr, + (int(l[i])*3600+int(l[i+2])*60)*signal) + i += 2 + elif len_li <= 2: + # -[0]3 + setattr(res, offattr, + int(l[i][:2])*3600*signal) + else: + return None + i += 1 + if res.dstabbr: + break + else: + break + + if i < len_l: + for j in range(i, len_l): + if l[j] == ';': l[j] = ',' + + assert l[i] == ',' + + i += 1 + + if i >= len_l: + pass + elif (8 <= l.count(',') <= 9 and + not [y for x in l[i:] if x != ',' + for y in x if y not in "0123456789"]): + # GMT0BST,3,0,30,3600,10,0,26,7200[,3600] + for x in (res.start, res.end): + x.month = int(l[i]) + i += 2 + if l[i] == '-': + value = int(l[i+1])*-1 + i += 1 + else: + value = int(l[i]) + i += 2 + if value: + x.week = value + x.weekday = (int(l[i])-1)%7 + else: + x.day = int(l[i]) + i += 2 + x.time = int(l[i]) + i += 2 + if i < len_l: + if l[i] in ('-','+'): + signal = (-1,1)[l[i] == "+"] + i += 1 + else: + signal = 1 + res.dstoffset = (res.stdoffset+int(l[i]))*signal + elif (l.count(',') == 2 and l[i:].count('/') <= 2 and + not [y for x in l[i:] if x not in (',','/','J','M', + '.','-',':') + for y in x if y not in "0123456789"]): + for x in (res.start, res.end): + if l[i] == 'J': + # non-leap year day (1 based) + i += 1 + x.jyday = int(l[i]) + elif l[i] == 'M': + # month[-.]week[-.]weekday + i += 1 + x.month = int(l[i]) + i += 1 + assert l[i] in ('-', '.') + i += 1 + x.week = int(l[i]) + if x.week == 5: + x.week = -1 + i += 1 + assert l[i] in ('-', '.') + i += 1 + x.weekday = (int(l[i])-1)%7 + else: + # year day (zero based) + x.yday = int(l[i])+1 + + i += 1 + + if i < len_l and l[i] == '/': + i += 1 + # start time + len_li = len(l[i]) + if len_li == 4: + # -0300 + x.time = (int(l[i][:2])*3600+int(l[i][2:])*60) + elif i+1 < len_l and l[i+1] == ':': + # -03:00 + x.time = int(l[i])*3600+int(l[i+2])*60 + i += 2 + if i+1 < len_l and l[i+1] == ':': + i += 2 + x.time += int(l[i]) + elif len_li <= 2: + # -[0]3 + x.time = (int(l[i][:2])*3600) + else: + return None + i += 1 + + assert i == len_l or l[i] == ',' + + i += 1 + + assert i >= len_l + + except (IndexError, ValueError, AssertionError): + return None + + return res + + +DEFAULTTZPARSER = _tzparser() +def _parsetz(tzstr): + return DEFAULTTZPARSER.parse(tzstr) + + +def _parsems(value): + """Parse a I[.F] seconds value into (seconds, microseconds).""" + if "." not in value: + return int(value), 0 + else: + i, f = value.split(".") + return int(i), int(f.ljust(6, "0")[:6]) + + +# vim:ts=4:sw=4:et diff --git a/lib/dateutil/relativedelta.py b/lib/dateutil/relativedelta.py new file mode 100644 index 0000000000000000000000000000000000000000..0c72a8180fb707eef4a1072edb171bad42f4d294 --- /dev/null +++ b/lib/dateutil/relativedelta.py @@ -0,0 +1,432 @@ +""" +Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net> + +This module offers extensions to the standard python 2.3+ +datetime module. +""" +__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" +__license__ = "PSF License" + +import datetime +import calendar + +__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"] + +class weekday(object): + __slots__ = ["weekday", "n"] + + def __init__(self, weekday, n=None): + self.weekday = weekday + self.n = n + + def __call__(self, n): + if n == self.n: + return self + else: + return self.__class__(self.weekday, n) + + def __eq__(self, other): + try: + if self.weekday != other.weekday or self.n != other.n: + return False + except AttributeError: + return False + return True + + def __repr__(self): + s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] + if not self.n: + return s + else: + return "%s(%+d)" % (s, self.n) + +MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) + +class relativedelta: + """ +The relativedelta type is based on the specification of the excelent +work done by M.-A. Lemburg in his mx.DateTime extension. However, +notice that this type does *NOT* implement the same algorithm as +his work. Do *NOT* expect it to behave like mx.DateTime's counterpart. + +There's two different ways to build a relativedelta instance. The +first one is passing it two date/datetime classes: + + relativedelta(datetime1, datetime2) + +And the other way is to use the following keyword arguments: + + year, month, day, hour, minute, second, microsecond: + Absolute information. + + years, months, weeks, days, hours, minutes, seconds, microseconds: + Relative information, may be negative. + + weekday: + One of the weekday instances (MO, TU, etc). These instances may + receive a parameter N, specifying the Nth weekday, which could + be positive or negative (like MO(+1) or MO(-2). Not specifying + it is the same as specifying +1. You can also use an integer, + where 0=MO. + + leapdays: + Will add given days to the date found, if year is a leap + year, and the date found is post 28 of february. + + yearday, nlyearday: + Set the yearday or the non-leap year day (jump leap days). + These are converted to day/month/leapdays information. + +Here is the behavior of operations with relativedelta: + +1) Calculate the absolute year, using the 'year' argument, or the + original datetime year, if the argument is not present. + +2) Add the relative 'years' argument to the absolute year. + +3) Do steps 1 and 2 for month/months. + +4) Calculate the absolute day, using the 'day' argument, or the + original datetime day, if the argument is not present. Then, + subtract from the day until it fits in the year and month + found after their operations. + +5) Add the relative 'days' argument to the absolute day. Notice + that the 'weeks' argument is multiplied by 7 and added to + 'days'. + +6) Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds, + microsecond/microseconds. + +7) If the 'weekday' argument is present, calculate the weekday, + with the given (wday, nth) tuple. wday is the index of the + weekday (0-6, 0=Mon), and nth is the number of weeks to add + forward or backward, depending on its signal. Notice that if + the calculated date is already Monday, for example, using + (0, 1) or (0, -1) won't change the day. + """ + + def __init__(self, dt1=None, dt2=None, + years=0, months=0, days=0, leapdays=0, weeks=0, + hours=0, minutes=0, seconds=0, microseconds=0, + year=None, month=None, day=None, weekday=None, + yearday=None, nlyearday=None, + hour=None, minute=None, second=None, microsecond=None): + if dt1 and dt2: + if not isinstance(dt1, datetime.date) or \ + not isinstance(dt2, datetime.date): + raise TypeError, "relativedelta only diffs datetime/date" + if type(dt1) is not type(dt2): + if not isinstance(dt1, datetime.datetime): + dt1 = datetime.datetime.fromordinal(dt1.toordinal()) + elif not isinstance(dt2, datetime.datetime): + dt2 = datetime.datetime.fromordinal(dt2.toordinal()) + self.years = 0 + self.months = 0 + self.days = 0 + self.leapdays = 0 + self.hours = 0 + self.minutes = 0 + self.seconds = 0 + self.microseconds = 0 + self.year = None + self.month = None + self.day = None + self.weekday = None + self.hour = None + self.minute = None + self.second = None + self.microsecond = None + self._has_time = 0 + + months = (dt1.year*12+dt1.month)-(dt2.year*12+dt2.month) + self._set_months(months) + dtm = self.__radd__(dt2) + if dt1 < dt2: + while dt1 > dtm: + months += 1 + self._set_months(months) + dtm = self.__radd__(dt2) + else: + while dt1 < dtm: + months -= 1 + self._set_months(months) + dtm = self.__radd__(dt2) + delta = dt1 - dtm + self.seconds = delta.seconds+delta.days*86400 + self.microseconds = delta.microseconds + else: + self.years = years + self.months = months + self.days = days+weeks*7 + self.leapdays = leapdays + self.hours = hours + self.minutes = minutes + self.seconds = seconds + self.microseconds = microseconds + self.year = year + self.month = month + self.day = day + self.hour = hour + self.minute = minute + self.second = second + self.microsecond = microsecond + + if type(weekday) is int: + self.weekday = weekdays[weekday] + else: + self.weekday = weekday + + yday = 0 + if nlyearday: + yday = nlyearday + elif yearday: + yday = yearday + if yearday > 59: + self.leapdays = -1 + if yday: + ydayidx = [31,59,90,120,151,181,212,243,273,304,334,366] + for idx, ydays in enumerate(ydayidx): + if yday <= ydays: + self.month = idx+1 + if idx == 0: + self.day = yday + else: + self.day = yday-ydayidx[idx-1] + break + else: + raise ValueError, "invalid year day (%d)" % yday + + self._fix() + + def _fix(self): + if abs(self.microseconds) > 999999: + s = self.microseconds//abs(self.microseconds) + div, mod = divmod(self.microseconds*s, 1000000) + self.microseconds = mod*s + self.seconds += div*s + if abs(self.seconds) > 59: + s = self.seconds//abs(self.seconds) + div, mod = divmod(self.seconds*s, 60) + self.seconds = mod*s + self.minutes += div*s + if abs(self.minutes) > 59: + s = self.minutes//abs(self.minutes) + div, mod = divmod(self.minutes*s, 60) + self.minutes = mod*s + self.hours += div*s + if abs(self.hours) > 23: + s = self.hours//abs(self.hours) + div, mod = divmod(self.hours*s, 24) + self.hours = mod*s + self.days += div*s + if abs(self.months) > 11: + s = self.months//abs(self.months) + div, mod = divmod(self.months*s, 12) + self.months = mod*s + self.years += div*s + if (self.hours or self.minutes or self.seconds or self.microseconds or + self.hour is not None or self.minute is not None or + self.second is not None or self.microsecond is not None): + self._has_time = 1 + else: + self._has_time = 0 + + def _set_months(self, months): + self.months = months + if abs(self.months) > 11: + s = self.months//abs(self.months) + div, mod = divmod(self.months*s, 12) + self.months = mod*s + self.years = div*s + else: + self.years = 0 + + def __radd__(self, other): + if not isinstance(other, datetime.date): + raise TypeError, "unsupported type for add operation" + elif self._has_time and not isinstance(other, datetime.datetime): + other = datetime.datetime.fromordinal(other.toordinal()) + year = (self.year or other.year)+self.years + month = self.month or other.month + if self.months: + assert 1 <= abs(self.months) <= 12 + month += self.months + if month > 12: + year += 1 + month -= 12 + elif month < 1: + year -= 1 + month += 12 + day = min(calendar.monthrange(year, month)[1], + self.day or other.day) + repl = {"year": year, "month": month, "day": day} + for attr in ["hour", "minute", "second", "microsecond"]: + value = getattr(self, attr) + if value is not None: + repl[attr] = value + days = self.days + if self.leapdays and month > 2 and calendar.isleap(year): + days += self.leapdays + ret = (other.replace(**repl) + + datetime.timedelta(days=days, + hours=self.hours, + minutes=self.minutes, + seconds=self.seconds, + microseconds=self.microseconds)) + if self.weekday: + weekday, nth = self.weekday.weekday, self.weekday.n or 1 + jumpdays = (abs(nth)-1)*7 + if nth > 0: + jumpdays += (7-ret.weekday()+weekday)%7 + else: + jumpdays += (ret.weekday()-weekday)%7 + jumpdays *= -1 + ret += datetime.timedelta(days=jumpdays) + return ret + + def __rsub__(self, other): + return self.__neg__().__radd__(other) + + def __add__(self, other): + if not isinstance(other, relativedelta): + raise TypeError, "unsupported type for add operation" + return relativedelta(years=other.years+self.years, + months=other.months+self.months, + days=other.days+self.days, + hours=other.hours+self.hours, + minutes=other.minutes+self.minutes, + seconds=other.seconds+self.seconds, + microseconds=other.microseconds+self.microseconds, + leapdays=other.leapdays or self.leapdays, + year=other.year or self.year, + month=other.month or self.month, + day=other.day or self.day, + weekday=other.weekday or self.weekday, + hour=other.hour or self.hour, + minute=other.minute or self.minute, + second=other.second or self.second, + microsecond=other.second or self.microsecond) + + def __sub__(self, other): + if not isinstance(other, relativedelta): + raise TypeError, "unsupported type for sub operation" + return relativedelta(years=other.years-self.years, + months=other.months-self.months, + days=other.days-self.days, + hours=other.hours-self.hours, + minutes=other.minutes-self.minutes, + seconds=other.seconds-self.seconds, + microseconds=other.microseconds-self.microseconds, + leapdays=other.leapdays or self.leapdays, + year=other.year or self.year, + month=other.month or self.month, + day=other.day or self.day, + weekday=other.weekday or self.weekday, + hour=other.hour or self.hour, + minute=other.minute or self.minute, + second=other.second or self.second, + microsecond=other.second or self.microsecond) + + def __neg__(self): + return relativedelta(years=-self.years, + months=-self.months, + days=-self.days, + hours=-self.hours, + minutes=-self.minutes, + seconds=-self.seconds, + microseconds=-self.microseconds, + leapdays=self.leapdays, + year=self.year, + month=self.month, + day=self.day, + weekday=self.weekday, + hour=self.hour, + minute=self.minute, + second=self.second, + microsecond=self.microsecond) + + def __nonzero__(self): + return not (not self.years and + not self.months and + not self.days and + not self.hours and + not self.minutes and + not self.seconds and + not self.microseconds and + not self.leapdays and + self.year is None and + self.month is None and + self.day is None and + self.weekday is None and + self.hour is None and + self.minute is None and + self.second is None and + self.microsecond is None) + + def __mul__(self, other): + f = float(other) + return relativedelta(years=self.years*f, + months=self.months*f, + days=self.days*f, + hours=self.hours*f, + minutes=self.minutes*f, + seconds=self.seconds*f, + microseconds=self.microseconds*f, + leapdays=self.leapdays, + year=self.year, + month=self.month, + day=self.day, + weekday=self.weekday, + hour=self.hour, + minute=self.minute, + second=self.second, + microsecond=self.microsecond) + + def __eq__(self, other): + if not isinstance(other, relativedelta): + return False + if self.weekday or other.weekday: + if not self.weekday or not other.weekday: + return False + if self.weekday.weekday != other.weekday.weekday: + return False + n1, n2 = self.weekday.n, other.weekday.n + if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)): + return False + return (self.years == other.years and + self.months == other.months and + self.days == other.days and + self.hours == other.hours and + self.minutes == other.minutes and + self.seconds == other.seconds and + self.leapdays == other.leapdays and + self.year == other.year and + self.month == other.month and + self.day == other.day and + self.hour == other.hour and + self.minute == other.minute and + self.second == other.second and + self.microsecond == other.microsecond) + + def __ne__(self, other): + return not self.__eq__(other) + + def __div__(self, other): + return self.__mul__(1/float(other)) + + def __repr__(self): + l = [] + for attr in ["years", "months", "days", "leapdays", + "hours", "minutes", "seconds", "microseconds"]: + value = getattr(self, attr) + if value: + l.append("%s=%+d" % (attr, value)) + for attr in ["year", "month", "day", "weekday", + "hour", "minute", "second", "microsecond"]: + value = getattr(self, attr) + if value is not None: + l.append("%s=%s" % (attr, `value`)) + return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) + +# vim:ts=4:sw=4:et diff --git a/lib/dateutil/rrule.py b/lib/dateutil/rrule.py new file mode 100644 index 0000000000000000000000000000000000000000..6bd83cad372262acd26f14cc2936c25823fe7f14 --- /dev/null +++ b/lib/dateutil/rrule.py @@ -0,0 +1,1097 @@ +""" +Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net> + +This module offers extensions to the standard python 2.3+ +datetime module. +""" +__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" +__license__ = "PSF License" + +import itertools +import datetime +import calendar +import thread +import sys + +__all__ = ["rrule", "rruleset", "rrulestr", + "YEARLY", "MONTHLY", "WEEKLY", "DAILY", + "HOURLY", "MINUTELY", "SECONDLY", + "MO", "TU", "WE", "TH", "FR", "SA", "SU"] + +# Every mask is 7 days longer to handle cross-year weekly periods. +M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+ + [7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7) +M365MASK = list(M366MASK) +M29, M30, M31 = range(1,30), range(1,31), range(1,32) +MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) +MDAY365MASK = list(MDAY366MASK) +M29, M30, M31 = range(-29,0), range(-30,0), range(-31,0) +NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) +NMDAY365MASK = list(NMDAY366MASK) +M366RANGE = (0,31,60,91,121,152,182,213,244,274,305,335,366) +M365RANGE = (0,31,59,90,120,151,181,212,243,273,304,334,365) +WDAYMASK = [0,1,2,3,4,5,6]*55 +del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31] +MDAY365MASK = tuple(MDAY365MASK) +M365MASK = tuple(M365MASK) + +(YEARLY, + MONTHLY, + WEEKLY, + DAILY, + HOURLY, + MINUTELY, + SECONDLY) = range(7) + +# Imported on demand. +easter = None +parser = None + +class weekday(object): + __slots__ = ["weekday", "n"] + + def __init__(self, weekday, n=None): + if n == 0: + raise ValueError, "Can't create weekday with n == 0" + self.weekday = weekday + self.n = n + + def __call__(self, n): + if n == self.n: + return self + else: + return self.__class__(self.weekday, n) + + def __eq__(self, other): + try: + if self.weekday != other.weekday or self.n != other.n: + return False + except AttributeError: + return False + return True + + def __repr__(self): + s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] + if not self.n: + return s + else: + return "%s(%+d)" % (s, self.n) + +MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) + +class rrulebase: + def __init__(self, cache=False): + if cache: + self._cache = [] + self._cache_lock = thread.allocate_lock() + self._cache_gen = self._iter() + self._cache_complete = False + else: + self._cache = None + self._cache_complete = False + self._len = None + + def __iter__(self): + if self._cache_complete: + return iter(self._cache) + elif self._cache is None: + return self._iter() + else: + return self._iter_cached() + + def _iter_cached(self): + i = 0 + gen = self._cache_gen + cache = self._cache + acquire = self._cache_lock.acquire + release = self._cache_lock.release + while gen: + if i == len(cache): + acquire() + if self._cache_complete: + break + try: + for j in range(10): + cache.append(gen.next()) + except StopIteration: + self._cache_gen = gen = None + self._cache_complete = True + break + release() + yield cache[i] + i += 1 + while i < self._len: + yield cache[i] + i += 1 + + def __getitem__(self, item): + if self._cache_complete: + return self._cache[item] + elif isinstance(item, slice): + if item.step and item.step < 0: + return list(iter(self))[item] + else: + return list(itertools.islice(self, + item.start or 0, + item.stop or sys.maxint, + item.step or 1)) + elif item >= 0: + gen = iter(self) + try: + for i in range(item+1): + res = gen.next() + except StopIteration: + raise IndexError + return res + else: + return list(iter(self))[item] + + def __contains__(self, item): + if self._cache_complete: + return item in self._cache + else: + for i in self: + if i == item: + return True + elif i > item: + return False + return False + + # __len__() introduces a large performance penality. + def count(self): + if self._len is None: + for x in self: pass + return self._len + + def before(self, dt, inc=False): + if self._cache_complete: + gen = self._cache + else: + gen = self + last = None + if inc: + for i in gen: + if i > dt: + break + last = i + else: + for i in gen: + if i >= dt: + break + last = i + return last + + def after(self, dt, inc=False): + if self._cache_complete: + gen = self._cache + else: + gen = self + if inc: + for i in gen: + if i >= dt: + return i + else: + for i in gen: + if i > dt: + return i + return None + + def between(self, after, before, inc=False): + if self._cache_complete: + gen = self._cache + else: + gen = self + started = False + l = [] + if inc: + for i in gen: + if i > before: + break + elif not started: + if i >= after: + started = True + l.append(i) + else: + l.append(i) + else: + for i in gen: + if i >= before: + break + elif not started: + if i > after: + started = True + l.append(i) + else: + l.append(i) + return l + +class rrule(rrulebase): + def __init__(self, freq, dtstart=None, + interval=1, wkst=None, count=None, until=None, bysetpos=None, + bymonth=None, bymonthday=None, byyearday=None, byeaster=None, + byweekno=None, byweekday=None, + byhour=None, byminute=None, bysecond=None, + cache=False): + rrulebase.__init__(self, cache) + global easter + if not dtstart: + dtstart = datetime.datetime.now().replace(microsecond=0) + elif not isinstance(dtstart, datetime.datetime): + dtstart = datetime.datetime.fromordinal(dtstart.toordinal()) + else: + dtstart = dtstart.replace(microsecond=0) + self._dtstart = dtstart + self._tzinfo = dtstart.tzinfo + self._freq = freq + self._interval = interval + self._count = count + if until and not isinstance(until, datetime.datetime): + until = datetime.datetime.fromordinal(until.toordinal()) + self._until = until + if wkst is None: + self._wkst = calendar.firstweekday() + elif type(wkst) is int: + self._wkst = wkst + else: + self._wkst = wkst.weekday + if bysetpos is None: + self._bysetpos = None + elif type(bysetpos) is int: + if bysetpos == 0 or not (-366 <= bysetpos <= 366): + raise ValueError("bysetpos must be between 1 and 366, " + "or between -366 and -1") + self._bysetpos = (bysetpos,) + else: + self._bysetpos = tuple(bysetpos) + for pos in self._bysetpos: + if pos == 0 or not (-366 <= pos <= 366): + raise ValueError("bysetpos must be between 1 and 366, " + "or between -366 and -1") + if not (byweekno or byyearday or bymonthday or + byweekday is not None or byeaster is not None): + if freq == YEARLY: + if not bymonth: + bymonth = dtstart.month + bymonthday = dtstart.day + elif freq == MONTHLY: + bymonthday = dtstart.day + elif freq == WEEKLY: + byweekday = dtstart.weekday() + # bymonth + if not bymonth: + self._bymonth = None + elif type(bymonth) is int: + self._bymonth = (bymonth,) + else: + self._bymonth = tuple(bymonth) + # byyearday + if not byyearday: + self._byyearday = None + elif type(byyearday) is int: + self._byyearday = (byyearday,) + else: + self._byyearday = tuple(byyearday) + # byeaster + if byeaster is not None: + if not easter: + from dateutil import easter + if type(byeaster) is int: + self._byeaster = (byeaster,) + else: + self._byeaster = tuple(byeaster) + else: + self._byeaster = None + # bymonthay + if not bymonthday: + self._bymonthday = () + self._bynmonthday = () + elif type(bymonthday) is int: + if bymonthday < 0: + self._bynmonthday = (bymonthday,) + self._bymonthday = () + else: + self._bymonthday = (bymonthday,) + self._bynmonthday = () + else: + self._bymonthday = tuple([x for x in bymonthday if x > 0]) + self._bynmonthday = tuple([x for x in bymonthday if x < 0]) + # byweekno + if byweekno is None: + self._byweekno = None + elif type(byweekno) is int: + self._byweekno = (byweekno,) + else: + self._byweekno = tuple(byweekno) + # byweekday / bynweekday + if byweekday is None: + self._byweekday = None + self._bynweekday = None + elif type(byweekday) is int: + self._byweekday = (byweekday,) + self._bynweekday = None + elif hasattr(byweekday, "n"): + if not byweekday.n or freq > MONTHLY: + self._byweekday = (byweekday.weekday,) + self._bynweekday = None + else: + self._bynweekday = ((byweekday.weekday, byweekday.n),) + self._byweekday = None + else: + self._byweekday = [] + self._bynweekday = [] + for wday in byweekday: + if type(wday) is int: + self._byweekday.append(wday) + elif not wday.n or freq > MONTHLY: + self._byweekday.append(wday.weekday) + else: + self._bynweekday.append((wday.weekday, wday.n)) + self._byweekday = tuple(self._byweekday) + self._bynweekday = tuple(self._bynweekday) + if not self._byweekday: + self._byweekday = None + elif not self._bynweekday: + self._bynweekday = None + # byhour + if byhour is None: + if freq < HOURLY: + self._byhour = (dtstart.hour,) + else: + self._byhour = None + elif type(byhour) is int: + self._byhour = (byhour,) + else: + self._byhour = tuple(byhour) + # byminute + if byminute is None: + if freq < MINUTELY: + self._byminute = (dtstart.minute,) + else: + self._byminute = None + elif type(byminute) is int: + self._byminute = (byminute,) + else: + self._byminute = tuple(byminute) + # bysecond + if bysecond is None: + if freq < SECONDLY: + self._bysecond = (dtstart.second,) + else: + self._bysecond = None + elif type(bysecond) is int: + self._bysecond = (bysecond,) + else: + self._bysecond = tuple(bysecond) + + if self._freq >= HOURLY: + self._timeset = None + else: + self._timeset = [] + for hour in self._byhour: + for minute in self._byminute: + for second in self._bysecond: + self._timeset.append( + datetime.time(hour, minute, second, + tzinfo=self._tzinfo)) + self._timeset.sort() + self._timeset = tuple(self._timeset) + + def _iter(self): + year, month, day, hour, minute, second, weekday, yearday, _ = \ + self._dtstart.timetuple() + + # Some local variables to speed things up a bit + freq = self._freq + interval = self._interval + wkst = self._wkst + until = self._until + bymonth = self._bymonth + byweekno = self._byweekno + byyearday = self._byyearday + byweekday = self._byweekday + byeaster = self._byeaster + bymonthday = self._bymonthday + bynmonthday = self._bynmonthday + bysetpos = self._bysetpos + byhour = self._byhour + byminute = self._byminute + bysecond = self._bysecond + + ii = _iterinfo(self) + ii.rebuild(year, month) + + getdayset = {YEARLY:ii.ydayset, + MONTHLY:ii.mdayset, + WEEKLY:ii.wdayset, + DAILY:ii.ddayset, + HOURLY:ii.ddayset, + MINUTELY:ii.ddayset, + SECONDLY:ii.ddayset}[freq] + + if freq < HOURLY: + timeset = self._timeset + else: + gettimeset = {HOURLY:ii.htimeset, + MINUTELY:ii.mtimeset, + SECONDLY:ii.stimeset}[freq] + if ((freq >= HOURLY and + self._byhour and hour not in self._byhour) or + (freq >= MINUTELY and + self._byminute and minute not in self._byminute) or + (freq >= SECONDLY and + self._bysecond and second not in self._bysecond)): + timeset = () + else: + timeset = gettimeset(hour, minute, second) + + total = 0 + count = self._count + while True: + # Get dayset with the right frequency + dayset, start, end = getdayset(year, month, day) + + # Do the "hard" work ;-) + filtered = False + for i in dayset[start:end]: + if ((bymonth and ii.mmask[i] not in bymonth) or + (byweekno and not ii.wnomask[i]) or + (byweekday and ii.wdaymask[i] not in byweekday) or + (ii.nwdaymask and not ii.nwdaymask[i]) or + (byeaster and not ii.eastermask[i]) or + ((bymonthday or bynmonthday) and + ii.mdaymask[i] not in bymonthday and + ii.nmdaymask[i] not in bynmonthday) or + (byyearday and + ((i < ii.yearlen and i+1 not in byyearday + and -ii.yearlen+i not in byyearday) or + (i >= ii.yearlen and i+1-ii.yearlen not in byyearday + and -ii.nextyearlen+i-ii.yearlen + not in byyearday)))): + dayset[i] = None + filtered = True + + # Output results + if bysetpos and timeset: + poslist = [] + for pos in bysetpos: + if pos < 0: + daypos, timepos = divmod(pos, len(timeset)) + else: + daypos, timepos = divmod(pos-1, len(timeset)) + try: + i = [x for x in dayset[start:end] + if x is not None][daypos] + time = timeset[timepos] + except IndexError: + pass + else: + date = datetime.date.fromordinal(ii.yearordinal+i) + res = datetime.datetime.combine(date, time) + if res not in poslist: + poslist.append(res) + poslist.sort() + for res in poslist: + if until and res > until: + self._len = total + return + elif res >= self._dtstart: + total += 1 + yield res + if count: + count -= 1 + if not count: + self._len = total + return + else: + for i in dayset[start:end]: + if i is not None: + date = datetime.date.fromordinal(ii.yearordinal+i) + for time in timeset: + res = datetime.datetime.combine(date, time) + if until and res > until: + self._len = total + return + elif res >= self._dtstart: + total += 1 + yield res + if count: + count -= 1 + if not count: + self._len = total + return + + # Handle frequency and interval + fixday = False + if freq == YEARLY: + year += interval + if year > datetime.MAXYEAR: + self._len = total + return + ii.rebuild(year, month) + elif freq == MONTHLY: + month += interval + if month > 12: + div, mod = divmod(month, 12) + month = mod + year += div + if month == 0: + month = 12 + year -= 1 + if year > datetime.MAXYEAR: + self._len = total + return + ii.rebuild(year, month) + elif freq == WEEKLY: + if wkst > weekday: + day += -(weekday+1+(6-wkst))+self._interval*7 + else: + day += -(weekday-wkst)+self._interval*7 + weekday = wkst + fixday = True + elif freq == DAILY: + day += interval + fixday = True + elif freq == HOURLY: + if filtered: + # Jump to one iteration before next day + hour += ((23-hour)//interval)*interval + while True: + hour += interval + div, mod = divmod(hour, 24) + if div: + hour = mod + day += div + fixday = True + if not byhour or hour in byhour: + break + timeset = gettimeset(hour, minute, second) + elif freq == MINUTELY: + if filtered: + # Jump to one iteration before next day + minute += ((1439-(hour*60+minute))//interval)*interval + while True: + minute += interval + div, mod = divmod(minute, 60) + if div: + minute = mod + hour += div + div, mod = divmod(hour, 24) + if div: + hour = mod + day += div + fixday = True + filtered = False + if ((not byhour or hour in byhour) and + (not byminute or minute in byminute)): + break + timeset = gettimeset(hour, minute, second) + elif freq == SECONDLY: + if filtered: + # Jump to one iteration before next day + second += (((86399-(hour*3600+minute*60+second)) + //interval)*interval) + while True: + second += self._interval + div, mod = divmod(second, 60) + if div: + second = mod + minute += div + div, mod = divmod(minute, 60) + if div: + minute = mod + hour += div + div, mod = divmod(hour, 24) + if div: + hour = mod + day += div + fixday = True + if ((not byhour or hour in byhour) and + (not byminute or minute in byminute) and + (not bysecond or second in bysecond)): + break + timeset = gettimeset(hour, minute, second) + + if fixday and day > 28: + daysinmonth = calendar.monthrange(year, month)[1] + if day > daysinmonth: + while day > daysinmonth: + day -= daysinmonth + month += 1 + if month == 13: + month = 1 + year += 1 + if year > datetime.MAXYEAR: + self._len = total + return + daysinmonth = calendar.monthrange(year, month)[1] + ii.rebuild(year, month) + +class _iterinfo(object): + __slots__ = ["rrule", "lastyear", "lastmonth", + "yearlen", "nextyearlen", "yearordinal", "yearweekday", + "mmask", "mrange", "mdaymask", "nmdaymask", + "wdaymask", "wnomask", "nwdaymask", "eastermask"] + + def __init__(self, rrule): + for attr in self.__slots__: + setattr(self, attr, None) + self.rrule = rrule + + def rebuild(self, year, month): + # Every mask is 7 days longer to handle cross-year weekly periods. + rr = self.rrule + if year != self.lastyear: + self.yearlen = 365+calendar.isleap(year) + self.nextyearlen = 365+calendar.isleap(year+1) + firstyday = datetime.date(year, 1, 1) + self.yearordinal = firstyday.toordinal() + self.yearweekday = firstyday.weekday() + + wday = datetime.date(year, 1, 1).weekday() + if self.yearlen == 365: + self.mmask = M365MASK + self.mdaymask = MDAY365MASK + self.nmdaymask = NMDAY365MASK + self.wdaymask = WDAYMASK[wday:] + self.mrange = M365RANGE + else: + self.mmask = M366MASK + self.mdaymask = MDAY366MASK + self.nmdaymask = NMDAY366MASK + self.wdaymask = WDAYMASK[wday:] + self.mrange = M366RANGE + + if not rr._byweekno: + self.wnomask = None + else: + self.wnomask = [0]*(self.yearlen+7) + #no1wkst = firstwkst = self.wdaymask.index(rr._wkst) + no1wkst = firstwkst = (7-self.yearweekday+rr._wkst)%7 + if no1wkst >= 4: + no1wkst = 0 + # Number of days in the year, plus the days we got + # from last year. + wyearlen = self.yearlen+(self.yearweekday-rr._wkst)%7 + else: + # Number of days in the year, minus the days we + # left in last year. + wyearlen = self.yearlen-no1wkst + div, mod = divmod(wyearlen, 7) + numweeks = div+mod//4 + for n in rr._byweekno: + if n < 0: + n += numweeks+1 + if not (0 < n <= numweeks): + continue + if n > 1: + i = no1wkst+(n-1)*7 + if no1wkst != firstwkst: + i -= 7-firstwkst + else: + i = no1wkst + for j in range(7): + self.wnomask[i] = 1 + i += 1 + if self.wdaymask[i] == rr._wkst: + break + if 1 in rr._byweekno: + # Check week number 1 of next year as well + # TODO: Check -numweeks for next year. + i = no1wkst+numweeks*7 + if no1wkst != firstwkst: + i -= 7-firstwkst + if i < self.yearlen: + # If week starts in next year, we + # don't care about it. + for j in range(7): + self.wnomask[i] = 1 + i += 1 + if self.wdaymask[i] == rr._wkst: + break + if no1wkst: + # Check last week number of last year as + # well. If no1wkst is 0, either the year + # started on week start, or week number 1 + # got days from last year, so there are no + # days from last year's last week number in + # this year. + if -1 not in rr._byweekno: + lyearweekday = datetime.date(year-1,1,1).weekday() + lno1wkst = (7-lyearweekday+rr._wkst)%7 + lyearlen = 365+calendar.isleap(year-1) + if lno1wkst >= 4: + lno1wkst = 0 + lnumweeks = 52+(lyearlen+ + (lyearweekday-rr._wkst)%7)%7//4 + else: + lnumweeks = 52+(self.yearlen-no1wkst)%7//4 + else: + lnumweeks = -1 + if lnumweeks in rr._byweekno: + for i in range(no1wkst): + self.wnomask[i] = 1 + + if (rr._bynweekday and + (month != self.lastmonth or year != self.lastyear)): + ranges = [] + if rr._freq == YEARLY: + if rr._bymonth: + for month in rr._bymonth: + ranges.append(self.mrange[month-1:month+1]) + else: + ranges = [(0, self.yearlen)] + elif rr._freq == MONTHLY: + ranges = [self.mrange[month-1:month+1]] + if ranges: + # Weekly frequency won't get here, so we may not + # care about cross-year weekly periods. + self.nwdaymask = [0]*self.yearlen + for first, last in ranges: + last -= 1 + for wday, n in rr._bynweekday: + if n < 0: + i = last+(n+1)*7 + i -= (self.wdaymask[i]-wday)%7 + else: + i = first+(n-1)*7 + i += (7-self.wdaymask[i]+wday)%7 + if first <= i <= last: + self.nwdaymask[i] = 1 + + if rr._byeaster: + self.eastermask = [0]*(self.yearlen+7) + eyday = easter.easter(year).toordinal()-self.yearordinal + for offset in rr._byeaster: + self.eastermask[eyday+offset] = 1 + + self.lastyear = year + self.lastmonth = month + + def ydayset(self, year, month, day): + return range(self.yearlen), 0, self.yearlen + + def mdayset(self, year, month, day): + set = [None]*self.yearlen + start, end = self.mrange[month-1:month+1] + for i in range(start, end): + set[i] = i + return set, start, end + + def wdayset(self, year, month, day): + # We need to handle cross-year weeks here. + set = [None]*(self.yearlen+7) + i = datetime.date(year, month, day).toordinal()-self.yearordinal + start = i + for j in range(7): + set[i] = i + i += 1 + #if (not (0 <= i < self.yearlen) or + # self.wdaymask[i] == self.rrule._wkst): + # This will cross the year boundary, if necessary. + if self.wdaymask[i] == self.rrule._wkst: + break + return set, start, i + + def ddayset(self, year, month, day): + set = [None]*self.yearlen + i = datetime.date(year, month, day).toordinal()-self.yearordinal + set[i] = i + return set, i, i+1 + + def htimeset(self, hour, minute, second): + set = [] + rr = self.rrule + for minute in rr._byminute: + for second in rr._bysecond: + set.append(datetime.time(hour, minute, second, + tzinfo=rr._tzinfo)) + set.sort() + return set + + def mtimeset(self, hour, minute, second): + set = [] + rr = self.rrule + for second in rr._bysecond: + set.append(datetime.time(hour, minute, second, tzinfo=rr._tzinfo)) + set.sort() + return set + + def stimeset(self, hour, minute, second): + return (datetime.time(hour, minute, second, + tzinfo=self.rrule._tzinfo),) + + +class rruleset(rrulebase): + + class _genitem: + def __init__(self, genlist, gen): + try: + self.dt = gen() + genlist.append(self) + except StopIteration: + pass + self.genlist = genlist + self.gen = gen + + def next(self): + try: + self.dt = self.gen() + except StopIteration: + self.genlist.remove(self) + + def __cmp__(self, other): + return cmp(self.dt, other.dt) + + def __init__(self, cache=False): + rrulebase.__init__(self, cache) + self._rrule = [] + self._rdate = [] + self._exrule = [] + self._exdate = [] + + def rrule(self, rrule): + self._rrule.append(rrule) + + def rdate(self, rdate): + self._rdate.append(rdate) + + def exrule(self, exrule): + self._exrule.append(exrule) + + def exdate(self, exdate): + self._exdate.append(exdate) + + def _iter(self): + rlist = [] + self._rdate.sort() + self._genitem(rlist, iter(self._rdate).next) + for gen in [iter(x).next for x in self._rrule]: + self._genitem(rlist, gen) + rlist.sort() + exlist = [] + self._exdate.sort() + self._genitem(exlist, iter(self._exdate).next) + for gen in [iter(x).next for x in self._exrule]: + self._genitem(exlist, gen) + exlist.sort() + lastdt = None + total = 0 + while rlist: + ritem = rlist[0] + if not lastdt or lastdt != ritem.dt: + while exlist and exlist[0] < ritem: + exlist[0].next() + exlist.sort() + if not exlist or ritem != exlist[0]: + total += 1 + yield ritem.dt + lastdt = ritem.dt + ritem.next() + rlist.sort() + self._len = total + +class _rrulestr: + + _freq_map = {"YEARLY": YEARLY, + "MONTHLY": MONTHLY, + "WEEKLY": WEEKLY, + "DAILY": DAILY, + "HOURLY": HOURLY, + "MINUTELY": MINUTELY, + "SECONDLY": SECONDLY} + + _weekday_map = {"MO":0,"TU":1,"WE":2,"TH":3,"FR":4,"SA":5,"SU":6} + + def _handle_int(self, rrkwargs, name, value, **kwargs): + rrkwargs[name.lower()] = int(value) + + def _handle_int_list(self, rrkwargs, name, value, **kwargs): + rrkwargs[name.lower()] = [int(x) for x in value.split(',')] + + _handle_INTERVAL = _handle_int + _handle_COUNT = _handle_int + _handle_BYSETPOS = _handle_int_list + _handle_BYMONTH = _handle_int_list + _handle_BYMONTHDAY = _handle_int_list + _handle_BYYEARDAY = _handle_int_list + _handle_BYEASTER = _handle_int_list + _handle_BYWEEKNO = _handle_int_list + _handle_BYHOUR = _handle_int_list + _handle_BYMINUTE = _handle_int_list + _handle_BYSECOND = _handle_int_list + + def _handle_FREQ(self, rrkwargs, name, value, **kwargs): + rrkwargs["freq"] = self._freq_map[value] + + def _handle_UNTIL(self, rrkwargs, name, value, **kwargs): + global parser + if not parser: + from dateutil import parser + try: + rrkwargs["until"] = parser.parse(value, + ignoretz=kwargs.get("ignoretz"), + tzinfos=kwargs.get("tzinfos")) + except ValueError: + raise ValueError, "invalid until date" + + def _handle_WKST(self, rrkwargs, name, value, **kwargs): + rrkwargs["wkst"] = self._weekday_map[value] + + def _handle_BYWEEKDAY(self, rrkwargs, name, value, **kwarsg): + l = [] + for wday in value.split(','): + for i in range(len(wday)): + if wday[i] not in '+-0123456789': + break + n = wday[:i] or None + w = wday[i:] + if n: n = int(n) + l.append(weekdays[self._weekday_map[w]](n)) + rrkwargs["byweekday"] = l + + _handle_BYDAY = _handle_BYWEEKDAY + + def _parse_rfc_rrule(self, line, + dtstart=None, + cache=False, + ignoretz=False, + tzinfos=None): + if line.find(':') != -1: + name, value = line.split(':') + if name != "RRULE": + raise ValueError, "unknown parameter name" + else: + value = line + rrkwargs = {} + for pair in value.split(';'): + name, value = pair.split('=') + name = name.upper() + value = value.upper() + try: + getattr(self, "_handle_"+name)(rrkwargs, name, value, + ignoretz=ignoretz, + tzinfos=tzinfos) + except AttributeError: + raise ValueError, "unknown parameter '%s'" % name + except (KeyError, ValueError): + raise ValueError, "invalid '%s': %s" % (name, value) + return rrule(dtstart=dtstart, cache=cache, **rrkwargs) + + def _parse_rfc(self, s, + dtstart=None, + cache=False, + unfold=False, + forceset=False, + compatible=False, + ignoretz=False, + tzinfos=None): + global parser + if compatible: + forceset = True + unfold = True + s = s.upper() + if not s.strip(): + raise ValueError, "empty string" + if unfold: + lines = s.splitlines() + i = 0 + while i < len(lines): + line = lines[i].rstrip() + if not line: + del lines[i] + elif i > 0 and line[0] == " ": + lines[i-1] += line[1:] + del lines[i] + else: + i += 1 + else: + lines = s.split() + if (not forceset and len(lines) == 1 and + (s.find(':') == -1 or s.startswith('RRULE:'))): + return self._parse_rfc_rrule(lines[0], cache=cache, + dtstart=dtstart, ignoretz=ignoretz, + tzinfos=tzinfos) + else: + rrulevals = [] + rdatevals = [] + exrulevals = [] + exdatevals = [] + for line in lines: + if not line: + continue + if line.find(':') == -1: + name = "RRULE" + value = line + else: + name, value = line.split(':', 1) + parms = name.split(';') + if not parms: + raise ValueError, "empty property name" + name = parms[0] + parms = parms[1:] + if name == "RRULE": + for parm in parms: + raise ValueError, "unsupported RRULE parm: "+parm + rrulevals.append(value) + elif name == "RDATE": + for parm in parms: + if parm != "VALUE=DATE-TIME": + raise ValueError, "unsupported RDATE parm: "+parm + rdatevals.append(value) + elif name == "EXRULE": + for parm in parms: + raise ValueError, "unsupported EXRULE parm: "+parm + exrulevals.append(value) + elif name == "EXDATE": + for parm in parms: + if parm != "VALUE=DATE-TIME": + raise ValueError, "unsupported RDATE parm: "+parm + exdatevals.append(value) + elif name == "DTSTART": + for parm in parms: + raise ValueError, "unsupported DTSTART parm: "+parm + if not parser: + from dateutil import parser + dtstart = parser.parse(value, ignoretz=ignoretz, + tzinfos=tzinfos) + else: + raise ValueError, "unsupported property: "+name + if (forceset or len(rrulevals) > 1 or + rdatevals or exrulevals or exdatevals): + if not parser and (rdatevals or exdatevals): + from dateutil import parser + set = rruleset(cache=cache) + for value in rrulevals: + set.rrule(self._parse_rfc_rrule(value, dtstart=dtstart, + ignoretz=ignoretz, + tzinfos=tzinfos)) + for value in rdatevals: + for datestr in value.split(','): + set.rdate(parser.parse(datestr, + ignoretz=ignoretz, + tzinfos=tzinfos)) + for value in exrulevals: + set.exrule(self._parse_rfc_rrule(value, dtstart=dtstart, + ignoretz=ignoretz, + tzinfos=tzinfos)) + for value in exdatevals: + for datestr in value.split(','): + set.exdate(parser.parse(datestr, + ignoretz=ignoretz, + tzinfos=tzinfos)) + if compatible and dtstart: + set.rdate(dtstart) + return set + else: + return self._parse_rfc_rrule(rrulevals[0], + dtstart=dtstart, + cache=cache, + ignoretz=ignoretz, + tzinfos=tzinfos) + + def __call__(self, s, **kwargs): + return self._parse_rfc(s, **kwargs) + +rrulestr = _rrulestr() + +# vim:ts=4:sw=4:et diff --git a/lib/dateutil/tz.py b/lib/dateutil/tz.py new file mode 100644 index 0000000000000000000000000000000000000000..0e28d6b3320953a71aace88d4043c80e2b71a4b8 --- /dev/null +++ b/lib/dateutil/tz.py @@ -0,0 +1,951 @@ +""" +Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net> + +This module offers extensions to the standard python 2.3+ +datetime module. +""" +__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" +__license__ = "PSF License" + +import datetime +import struct +import time +import sys +import os + +relativedelta = None +parser = None +rrule = None + +__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange", + "tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"] + +try: + from dateutil.tzwin import tzwin, tzwinlocal +except (ImportError, OSError): + tzwin, tzwinlocal = None, None + +ZERO = datetime.timedelta(0) +EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal() + +class tzutc(datetime.tzinfo): + + def utcoffset(self, dt): + return ZERO + + def dst(self, dt): + return ZERO + + def tzname(self, dt): + return "UTC" + + def __eq__(self, other): + return (isinstance(other, tzutc) or + (isinstance(other, tzoffset) and other._offset == ZERO)) + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return "%s()" % self.__class__.__name__ + + __reduce__ = object.__reduce__ + +class tzoffset(datetime.tzinfo): + + def __init__(self, name, offset): + self._name = name + self._offset = datetime.timedelta(seconds=offset) + + def utcoffset(self, dt): + return self._offset + + def dst(self, dt): + return ZERO + + def tzname(self, dt): + return self._name + + def __eq__(self, other): + return (isinstance(other, tzoffset) and + self._offset == other._offset) + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return "%s(%s, %s)" % (self.__class__.__name__, + `self._name`, + self._offset.days*86400+self._offset.seconds) + + __reduce__ = object.__reduce__ + +class tzlocal(datetime.tzinfo): + + _std_offset = datetime.timedelta(seconds=-time.timezone) + if time.daylight: + _dst_offset = datetime.timedelta(seconds=-time.altzone) + else: + _dst_offset = _std_offset + + def utcoffset(self, dt): + if self._isdst(dt): + return self._dst_offset + else: + return self._std_offset + + def dst(self, dt): + if self._isdst(dt): + return self._dst_offset-self._std_offset + else: + return ZERO + + def tzname(self, dt): + return time.tzname[self._isdst(dt)] + + def _isdst(self, dt): + # We can't use mktime here. It is unstable when deciding if + # the hour near to a change is DST or not. + # + # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour, + # dt.minute, dt.second, dt.weekday(), 0, -1)) + # return time.localtime(timestamp).tm_isdst + # + # The code above yields the following result: + # + #>>> import tz, datetime + #>>> t = tz.tzlocal() + #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() + #'BRDT' + #>>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname() + #'BRST' + #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() + #'BRST' + #>>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname() + #'BRDT' + #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() + #'BRDT' + # + # Here is a more stable implementation: + # + timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 + + dt.hour * 3600 + + dt.minute * 60 + + dt.second) + return time.localtime(timestamp+time.timezone).tm_isdst + + def __eq__(self, other): + if not isinstance(other, tzlocal): + return False + return (self._std_offset == other._std_offset and + self._dst_offset == other._dst_offset) + return True + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return "%s()" % self.__class__.__name__ + + __reduce__ = object.__reduce__ + +class _ttinfo(object): + __slots__ = ["offset", "delta", "isdst", "abbr", "isstd", "isgmt"] + + def __init__(self): + for attr in self.__slots__: + setattr(self, attr, None) + + def __repr__(self): + l = [] + for attr in self.__slots__: + value = getattr(self, attr) + if value is not None: + l.append("%s=%s" % (attr, `value`)) + return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) + + def __eq__(self, other): + if not isinstance(other, _ttinfo): + return False + return (self.offset == other.offset and + self.delta == other.delta and + self.isdst == other.isdst and + self.abbr == other.abbr and + self.isstd == other.isstd and + self.isgmt == other.isgmt) + + def __ne__(self, other): + return not self.__eq__(other) + + def __getstate__(self): + state = {} + for name in self.__slots__: + state[name] = getattr(self, name, None) + return state + + def __setstate__(self, state): + for name in self.__slots__: + if name in state: + setattr(self, name, state[name]) + +class tzfile(datetime.tzinfo): + + # http://www.twinsun.com/tz/tz-link.htm + # ftp://elsie.nci.nih.gov/pub/tz*.tar.gz + + def __init__(self, fileobj): + if isinstance(fileobj, basestring): + self._filename = fileobj + fileobj = open(fileobj) + elif hasattr(fileobj, "name"): + self._filename = fileobj.name + else: + self._filename = `fileobj` + + # From tzfile(5): + # + # The time zone information files used by tzset(3) + # begin with the magic characters "TZif" to identify + # them as time zone information files, followed by + # sixteen bytes reserved for future use, followed by + # six four-byte values of type long, written in a + # ``standard'' byte order (the high-order byte + # of the value is written first). + + if fileobj.read(4) != "TZif": + raise ValueError, "magic not found" + + fileobj.read(16) + + ( + # The number of UTC/local indicators stored in the file. + ttisgmtcnt, + + # The number of standard/wall indicators stored in the file. + ttisstdcnt, + + # The number of leap seconds for which data is + # stored in the file. + leapcnt, + + # The number of "transition times" for which data + # is stored in the file. + timecnt, + + # The number of "local time types" for which data + # is stored in the file (must not be zero). + typecnt, + + # The number of characters of "time zone + # abbreviation strings" stored in the file. + charcnt, + + ) = struct.unpack(">6l", fileobj.read(24)) + + # The above header is followed by tzh_timecnt four-byte + # values of type long, sorted in ascending order. + # These values are written in ``standard'' byte order. + # Each is used as a transition time (as returned by + # time(2)) at which the rules for computing local time + # change. + + if timecnt: + self._trans_list = struct.unpack(">%dl" % timecnt, + fileobj.read(timecnt*4)) + else: + self._trans_list = [] + + # Next come tzh_timecnt one-byte values of type unsigned + # char; each one tells which of the different types of + # ``local time'' types described in the file is associated + # with the same-indexed transition time. These values + # serve as indices into an array of ttinfo structures that + # appears next in the file. + + if timecnt: + self._trans_idx = struct.unpack(">%dB" % timecnt, + fileobj.read(timecnt)) + else: + self._trans_idx = [] + + # Each ttinfo structure is written as a four-byte value + # for tt_gmtoff of type long, in a standard byte + # order, followed by a one-byte value for tt_isdst + # and a one-byte value for tt_abbrind. In each + # structure, tt_gmtoff gives the number of + # seconds to be added to UTC, tt_isdst tells whether + # tm_isdst should be set by localtime(3), and + # tt_abbrind serves as an index into the array of + # time zone abbreviation characters that follow the + # ttinfo structure(s) in the file. + + ttinfo = [] + + for i in range(typecnt): + ttinfo.append(struct.unpack(">lbb", fileobj.read(6))) + + abbr = fileobj.read(charcnt) + + # Then there are tzh_leapcnt pairs of four-byte + # values, written in standard byte order; the + # first value of each pair gives the time (as + # returned by time(2)) at which a leap second + # occurs; the second gives the total number of + # leap seconds to be applied after the given time. + # The pairs of values are sorted in ascending order + # by time. + + # Not used, for now + if leapcnt: + leap = struct.unpack(">%dl" % (leapcnt*2), + fileobj.read(leapcnt*8)) + + # Then there are tzh_ttisstdcnt standard/wall + # indicators, each stored as a one-byte value; + # they tell whether the transition times associated + # with local time types were specified as standard + # time or wall clock time, and are used when + # a time zone file is used in handling POSIX-style + # time zone environment variables. + + if ttisstdcnt: + isstd = struct.unpack(">%db" % ttisstdcnt, + fileobj.read(ttisstdcnt)) + + # Finally, there are tzh_ttisgmtcnt UTC/local + # indicators, each stored as a one-byte value; + # they tell whether the transition times associated + # with local time types were specified as UTC or + # local time, and are used when a time zone file + # is used in handling POSIX-style time zone envi- + # ronment variables. + + if ttisgmtcnt: + isgmt = struct.unpack(">%db" % ttisgmtcnt, + fileobj.read(ttisgmtcnt)) + + # ** Everything has been read ** + + # Build ttinfo list + self._ttinfo_list = [] + for i in range(typecnt): + gmtoff, isdst, abbrind = ttinfo[i] + # Round to full-minutes if that's not the case. Python's + # datetime doesn't accept sub-minute timezones. Check + # http://python.org/sf/1447945 for some information. + gmtoff = (gmtoff+30)//60*60 + tti = _ttinfo() + tti.offset = gmtoff + tti.delta = datetime.timedelta(seconds=gmtoff) + tti.isdst = isdst + tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)] + tti.isstd = (ttisstdcnt > i and isstd[i] != 0) + tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0) + self._ttinfo_list.append(tti) + + # Replace ttinfo indexes for ttinfo objects. + trans_idx = [] + for idx in self._trans_idx: + trans_idx.append(self._ttinfo_list[idx]) + self._trans_idx = tuple(trans_idx) + + # Set standard, dst, and before ttinfos. before will be + # used when a given time is before any transitions, + # and will be set to the first non-dst ttinfo, or to + # the first dst, if all of them are dst. + self._ttinfo_std = None + self._ttinfo_dst = None + self._ttinfo_before = None + if self._ttinfo_list: + if not self._trans_list: + self._ttinfo_std = self._ttinfo_first = self._ttinfo_list[0] + else: + for i in range(timecnt-1,-1,-1): + tti = self._trans_idx[i] + if not self._ttinfo_std and not tti.isdst: + self._ttinfo_std = tti + elif not self._ttinfo_dst and tti.isdst: + self._ttinfo_dst = tti + if self._ttinfo_std and self._ttinfo_dst: + break + else: + if self._ttinfo_dst and not self._ttinfo_std: + self._ttinfo_std = self._ttinfo_dst + + for tti in self._ttinfo_list: + if not tti.isdst: + self._ttinfo_before = tti + break + else: + self._ttinfo_before = self._ttinfo_list[0] + + # Now fix transition times to become relative to wall time. + # + # I'm not sure about this. In my tests, the tz source file + # is setup to wall time, and in the binary file isstd and + # isgmt are off, so it should be in wall time. OTOH, it's + # always in gmt time. Let me know if you have comments + # about this. + laststdoffset = 0 + self._trans_list = list(self._trans_list) + for i in range(len(self._trans_list)): + tti = self._trans_idx[i] + if not tti.isdst: + # This is std time. + self._trans_list[i] += tti.offset + laststdoffset = tti.offset + else: + # This is dst time. Convert to std. + self._trans_list[i] += laststdoffset + self._trans_list = tuple(self._trans_list) + + def _find_ttinfo(self, dt, laststd=0): + timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 + + dt.hour * 3600 + + dt.minute * 60 + + dt.second) + idx = 0 + for trans in self._trans_list: + if timestamp < trans: + break + idx += 1 + else: + return self._ttinfo_std + if idx == 0: + return self._ttinfo_before + if laststd: + while idx > 0: + tti = self._trans_idx[idx-1] + if not tti.isdst: + return tti + idx -= 1 + else: + return self._ttinfo_std + else: + return self._trans_idx[idx-1] + + def utcoffset(self, dt): + if not self._ttinfo_std: + return ZERO + return self._find_ttinfo(dt).delta + + def dst(self, dt): + if not self._ttinfo_dst: + return ZERO + tti = self._find_ttinfo(dt) + if not tti.isdst: + return ZERO + + # The documentation says that utcoffset()-dst() must + # be constant for every dt. + return tti.delta-self._find_ttinfo(dt, laststd=1).delta + + # An alternative for that would be: + # + # return self._ttinfo_dst.offset-self._ttinfo_std.offset + # + # However, this class stores historical changes in the + # dst offset, so I belive that this wouldn't be the right + # way to implement this. + + def tzname(self, dt): + if not self._ttinfo_std: + return None + return self._find_ttinfo(dt).abbr + + def __eq__(self, other): + if not isinstance(other, tzfile): + return False + return (self._trans_list == other._trans_list and + self._trans_idx == other._trans_idx and + self._ttinfo_list == other._ttinfo_list) + + def __ne__(self, other): + return not self.__eq__(other) + + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, `self._filename`) + + def __reduce__(self): + if not os.path.isfile(self._filename): + raise ValueError, "Unpickable %s class" % self.__class__.__name__ + return (self.__class__, (self._filename,)) + +class tzrange(datetime.tzinfo): + + def __init__(self, stdabbr, stdoffset=None, + dstabbr=None, dstoffset=None, + start=None, end=None): + global relativedelta + if not relativedelta: + from dateutil import relativedelta + self._std_abbr = stdabbr + self._dst_abbr = dstabbr + if stdoffset is not None: + self._std_offset = datetime.timedelta(seconds=stdoffset) + else: + self._std_offset = ZERO + if dstoffset is not None: + self._dst_offset = datetime.timedelta(seconds=dstoffset) + elif dstabbr and stdoffset is not None: + self._dst_offset = self._std_offset+datetime.timedelta(hours=+1) + else: + self._dst_offset = ZERO + if dstabbr and start is None: + self._start_delta = relativedelta.relativedelta( + hours=+2, month=4, day=1, weekday=relativedelta.SU(+1)) + else: + self._start_delta = start + if dstabbr and end is None: + self._end_delta = relativedelta.relativedelta( + hours=+1, month=10, day=31, weekday=relativedelta.SU(-1)) + else: + self._end_delta = end + + def utcoffset(self, dt): + if self._isdst(dt): + return self._dst_offset + else: + return self._std_offset + + def dst(self, dt): + if self._isdst(dt): + return self._dst_offset-self._std_offset + else: + return ZERO + + def tzname(self, dt): + if self._isdst(dt): + return self._dst_abbr + else: + return self._std_abbr + + def _isdst(self, dt): + if not self._start_delta: + return False + year = datetime.datetime(dt.year,1,1) + start = year+self._start_delta + end = year+self._end_delta + dt = dt.replace(tzinfo=None) + if start < end: + return dt >= start and dt < end + else: + return dt >= start or dt < end + + def __eq__(self, other): + if not isinstance(other, tzrange): + return False + return (self._std_abbr == other._std_abbr and + self._dst_abbr == other._dst_abbr and + self._std_offset == other._std_offset and + self._dst_offset == other._dst_offset and + self._start_delta == other._start_delta and + self._end_delta == other._end_delta) + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return "%s(...)" % self.__class__.__name__ + + __reduce__ = object.__reduce__ + +class tzstr(tzrange): + + def __init__(self, s): + global parser + if not parser: + from dateutil import parser + self._s = s + + res = parser._parsetz(s) + if res is None: + raise ValueError, "unknown string format" + + # Here we break the compatibility with the TZ variable handling. + # GMT-3 actually *means* the timezone -3. + if res.stdabbr in ("GMT", "UTC"): + res.stdoffset *= -1 + + # We must initialize it first, since _delta() needs + # _std_offset and _dst_offset set. Use False in start/end + # to avoid building it two times. + tzrange.__init__(self, res.stdabbr, res.stdoffset, + res.dstabbr, res.dstoffset, + start=False, end=False) + + if not res.dstabbr: + self._start_delta = None + self._end_delta = None + else: + self._start_delta = self._delta(res.start) + if self._start_delta: + self._end_delta = self._delta(res.end, isend=1) + + def _delta(self, x, isend=0): + kwargs = {} + if x.month is not None: + kwargs["month"] = x.month + if x.weekday is not None: + kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week) + if x.week > 0: + kwargs["day"] = 1 + else: + kwargs["day"] = 31 + elif x.day: + kwargs["day"] = x.day + elif x.yday is not None: + kwargs["yearday"] = x.yday + elif x.jyday is not None: + kwargs["nlyearday"] = x.jyday + if not kwargs: + # Default is to start on first sunday of april, and end + # on last sunday of october. + if not isend: + kwargs["month"] = 4 + kwargs["day"] = 1 + kwargs["weekday"] = relativedelta.SU(+1) + else: + kwargs["month"] = 10 + kwargs["day"] = 31 + kwargs["weekday"] = relativedelta.SU(-1) + if x.time is not None: + kwargs["seconds"] = x.time + else: + # Default is 2AM. + kwargs["seconds"] = 7200 + if isend: + # Convert to standard time, to follow the documented way + # of working with the extra hour. See the documentation + # of the tzinfo class. + delta = self._dst_offset-self._std_offset + kwargs["seconds"] -= delta.seconds+delta.days*86400 + return relativedelta.relativedelta(**kwargs) + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, `self._s`) + +class _tzicalvtzcomp: + def __init__(self, tzoffsetfrom, tzoffsetto, isdst, + tzname=None, rrule=None): + self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom) + self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto) + self.tzoffsetdiff = self.tzoffsetto-self.tzoffsetfrom + self.isdst = isdst + self.tzname = tzname + self.rrule = rrule + +class _tzicalvtz(datetime.tzinfo): + def __init__(self, tzid, comps=[]): + self._tzid = tzid + self._comps = comps + self._cachedate = [] + self._cachecomp = [] + + def _find_comp(self, dt): + if len(self._comps) == 1: + return self._comps[0] + dt = dt.replace(tzinfo=None) + try: + return self._cachecomp[self._cachedate.index(dt)] + except ValueError: + pass + lastcomp = None + lastcompdt = None + for comp in self._comps: + if not comp.isdst: + # Handle the extra hour in DST -> STD + compdt = comp.rrule.before(dt-comp.tzoffsetdiff, inc=True) + else: + compdt = comp.rrule.before(dt, inc=True) + if compdt and (not lastcompdt or lastcompdt < compdt): + lastcompdt = compdt + lastcomp = comp + if not lastcomp: + # RFC says nothing about what to do when a given + # time is before the first onset date. We'll look for the + # first standard component, or the first component, if + # none is found. + for comp in self._comps: + if not comp.isdst: + lastcomp = comp + break + else: + lastcomp = comp[0] + self._cachedate.insert(0, dt) + self._cachecomp.insert(0, lastcomp) + if len(self._cachedate) > 10: + self._cachedate.pop() + self._cachecomp.pop() + return lastcomp + + def utcoffset(self, dt): + return self._find_comp(dt).tzoffsetto + + def dst(self, dt): + comp = self._find_comp(dt) + if comp.isdst: + return comp.tzoffsetdiff + else: + return ZERO + + def tzname(self, dt): + return self._find_comp(dt).tzname + + def __repr__(self): + return "<tzicalvtz %s>" % `self._tzid` + + __reduce__ = object.__reduce__ + +class tzical: + def __init__(self, fileobj): + global rrule + if not rrule: + from dateutil import rrule + + if isinstance(fileobj, basestring): + self._s = fileobj + fileobj = open(fileobj) + elif hasattr(fileobj, "name"): + self._s = fileobj.name + else: + self._s = `fileobj` + + self._vtz = {} + + self._parse_rfc(fileobj.read()) + + def keys(self): + return self._vtz.keys() + + def get(self, tzid=None): + if tzid is None: + keys = self._vtz.keys() + if len(keys) == 0: + raise ValueError, "no timezones defined" + elif len(keys) > 1: + raise ValueError, "more than one timezone available" + tzid = keys[0] + return self._vtz.get(tzid) + + def _parse_offset(self, s): + s = s.strip() + if not s: + raise ValueError, "empty offset" + if s[0] in ('+', '-'): + signal = (-1,+1)[s[0]=='+'] + s = s[1:] + else: + signal = +1 + if len(s) == 4: + return (int(s[:2])*3600+int(s[2:])*60)*signal + elif len(s) == 6: + return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal + else: + raise ValueError, "invalid offset: "+s + + def _parse_rfc(self, s): + lines = s.splitlines() + if not lines: + raise ValueError, "empty string" + + # Unfold + i = 0 + while i < len(lines): + line = lines[i].rstrip() + if not line: + del lines[i] + elif i > 0 and line[0] == " ": + lines[i-1] += line[1:] + del lines[i] + else: + i += 1 + + tzid = None + comps = [] + invtz = False + comptype = None + for line in lines: + if not line: + continue + name, value = line.split(':', 1) + parms = name.split(';') + if not parms: + raise ValueError, "empty property name" + name = parms[0].upper() + parms = parms[1:] + if invtz: + if name == "BEGIN": + if value in ("STANDARD", "DAYLIGHT"): + # Process component + pass + else: + raise ValueError, "unknown component: "+value + comptype = value + founddtstart = False + tzoffsetfrom = None + tzoffsetto = None + rrulelines = [] + tzname = None + elif name == "END": + if value == "VTIMEZONE": + if comptype: + raise ValueError, \ + "component not closed: "+comptype + if not tzid: + raise ValueError, \ + "mandatory TZID not found" + if not comps: + raise ValueError, \ + "at least one component is needed" + # Process vtimezone + self._vtz[tzid] = _tzicalvtz(tzid, comps) + invtz = False + elif value == comptype: + if not founddtstart: + raise ValueError, \ + "mandatory DTSTART not found" + if tzoffsetfrom is None: + raise ValueError, \ + "mandatory TZOFFSETFROM not found" + if tzoffsetto is None: + raise ValueError, \ + "mandatory TZOFFSETFROM not found" + # Process component + rr = None + if rrulelines: + rr = rrule.rrulestr("\n".join(rrulelines), + compatible=True, + ignoretz=True, + cache=True) + comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto, + (comptype == "DAYLIGHT"), + tzname, rr) + comps.append(comp) + comptype = None + else: + raise ValueError, \ + "invalid component end: "+value + elif comptype: + if name == "DTSTART": + rrulelines.append(line) + founddtstart = True + elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"): + rrulelines.append(line) + elif name == "TZOFFSETFROM": + if parms: + raise ValueError, \ + "unsupported %s parm: %s "%(name, parms[0]) + tzoffsetfrom = self._parse_offset(value) + elif name == "TZOFFSETTO": + if parms: + raise ValueError, \ + "unsupported TZOFFSETTO parm: "+parms[0] + tzoffsetto = self._parse_offset(value) + elif name == "TZNAME": + if parms: + raise ValueError, \ + "unsupported TZNAME parm: "+parms[0] + tzname = value + elif name == "COMMENT": + pass + else: + raise ValueError, "unsupported property: "+name + else: + if name == "TZID": + if parms: + raise ValueError, \ + "unsupported TZID parm: "+parms[0] + tzid = value + elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"): + pass + else: + raise ValueError, "unsupported property: "+name + elif name == "BEGIN" and value == "VTIMEZONE": + tzid = None + comps = [] + invtz = True + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, `self._s`) + +if sys.platform != "win32": + TZFILES = ["/etc/localtime", "localtime"] + TZPATHS = ["/usr/share/zoneinfo", "/usr/lib/zoneinfo", "/etc/zoneinfo"] +else: + TZFILES = [] + TZPATHS = [] + +def gettz(name=None): + tz = None + if not name: + try: + name = os.environ["TZ"] + except KeyError: + pass + if name is None or name == ":": + for filepath in TZFILES: + if not os.path.isabs(filepath): + filename = filepath + for path in TZPATHS: + filepath = os.path.join(path, filename) + if os.path.isfile(filepath): + break + else: + continue + if os.path.isfile(filepath): + try: + tz = tzfile(filepath) + break + except (IOError, OSError, ValueError): + pass + else: + tz = tzlocal() + else: + if name.startswith(":"): + name = name[:-1] + if os.path.isabs(name): + if os.path.isfile(name): + tz = tzfile(name) + else: + tz = None + else: + for path in TZPATHS: + filepath = os.path.join(path, name) + if not os.path.isfile(filepath): + filepath = filepath.replace(' ','_') + if not os.path.isfile(filepath): + continue + try: + tz = tzfile(filepath) + break + except (IOError, OSError, ValueError): + pass + else: + tz = None + if tzwin: + try: + tz = tzwin(name) + except OSError: + pass + if not tz: + from dateutil.zoneinfo import gettz + tz = gettz(name) + if not tz: + for c in name: + # name must have at least one offset to be a tzstr + if c in "0123456789": + try: + tz = tzstr(name) + except ValueError: + pass + break + else: + if name in ("GMT", "UTC"): + tz = tzutc() + elif name in time.tzname: + tz = tzlocal() + return tz + +# vim:ts=4:sw=4:et diff --git a/lib/dateutil/tzwin.py b/lib/dateutil/tzwin.py new file mode 100644 index 0000000000000000000000000000000000000000..073e0ff68e3fb586af05908407982cfec34599b5 --- /dev/null +++ b/lib/dateutil/tzwin.py @@ -0,0 +1,180 @@ +# This code was originally contributed by Jeffrey Harris. +import datetime +import struct +import _winreg + +__author__ = "Jeffrey Harris & Gustavo Niemeyer <gustavo@niemeyer.net>" + +__all__ = ["tzwin", "tzwinlocal"] + +ONEWEEK = datetime.timedelta(7) + +TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" +TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones" +TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" + +def _settzkeyname(): + global TZKEYNAME + handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + try: + _winreg.OpenKey(handle, TZKEYNAMENT).Close() + TZKEYNAME = TZKEYNAMENT + except WindowsError: + TZKEYNAME = TZKEYNAME9X + handle.Close() + +_settzkeyname() + +class tzwinbase(datetime.tzinfo): + """tzinfo class based on win32's timezones available in the registry.""" + + def utcoffset(self, dt): + if self._isdst(dt): + return datetime.timedelta(minutes=self._dstoffset) + else: + return datetime.timedelta(minutes=self._stdoffset) + + def dst(self, dt): + if self._isdst(dt): + minutes = self._dstoffset - self._stdoffset + return datetime.timedelta(minutes=minutes) + else: + return datetime.timedelta(0) + + def tzname(self, dt): + if self._isdst(dt): + return self._dstname + else: + return self._stdname + + def list(): + """Return a list of all time zones known to the system.""" + handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + tzkey = _winreg.OpenKey(handle, TZKEYNAME) + result = [_winreg.EnumKey(tzkey, i) + for i in range(_winreg.QueryInfoKey(tzkey)[0])] + tzkey.Close() + handle.Close() + return result + list = staticmethod(list) + + def display(self): + return self._display + + def _isdst(self, dt): + dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek, + self._dsthour, self._dstminute, + self._dstweeknumber) + dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek, + self._stdhour, self._stdminute, + self._stdweeknumber) + if dston < dstoff: + return dston <= dt.replace(tzinfo=None) < dstoff + else: + return not dstoff <= dt.replace(tzinfo=None) < dston + + +class tzwin(tzwinbase): + + def __init__(self, name): + self._name = name + + handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + tzkey = _winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name)) + keydict = valuestodict(tzkey) + tzkey.Close() + handle.Close() + + self._stdname = keydict["Std"].encode("iso-8859-1") + self._dstname = keydict["Dlt"].encode("iso-8859-1") + + self._display = keydict["Display"] + + # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm + tup = struct.unpack("=3l16h", keydict["TZI"]) + self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1 + self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1 + + (self._stdmonth, + self._stddayofweek, # Sunday = 0 + self._stdweeknumber, # Last = 5 + self._stdhour, + self._stdminute) = tup[4:9] + + (self._dstmonth, + self._dstdayofweek, # Sunday = 0 + self._dstweeknumber, # Last = 5 + self._dsthour, + self._dstminute) = tup[12:17] + + def __repr__(self): + return "tzwin(%s)" % repr(self._name) + + def __reduce__(self): + return (self.__class__, (self._name,)) + + +class tzwinlocal(tzwinbase): + + def __init__(self): + + handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + + tzlocalkey = _winreg.OpenKey(handle, TZLOCALKEYNAME) + keydict = valuestodict(tzlocalkey) + tzlocalkey.Close() + + self._stdname = keydict["StandardName"].encode("iso-8859-1") + self._dstname = keydict["DaylightName"].encode("iso-8859-1") + + try: + tzkey = _winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname)) + _keydict = valuestodict(tzkey) + self._display = _keydict["Display"] + tzkey.Close() + except OSError: + self._display = None + + handle.Close() + + self._stdoffset = -keydict["Bias"]-keydict["StandardBias"] + self._dstoffset = self._stdoffset-keydict["DaylightBias"] + + + # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm + tup = struct.unpack("=8h", keydict["StandardStart"]) + + (self._stdmonth, + self._stddayofweek, # Sunday = 0 + self._stdweeknumber, # Last = 5 + self._stdhour, + self._stdminute) = tup[1:6] + + tup = struct.unpack("=8h", keydict["DaylightStart"]) + + (self._dstmonth, + self._dstdayofweek, # Sunday = 0 + self._dstweeknumber, # Last = 5 + self._dsthour, + self._dstminute) = tup[1:6] + + def __reduce__(self): + return (self.__class__, ()) + +def picknthweekday(year, month, dayofweek, hour, minute, whichweek): + """dayofweek == 0 means Sunday, whichweek 5 means last instance""" + first = datetime.datetime(year, month, 1, hour, minute) + weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1)) + for n in xrange(whichweek): + dt = weekdayone+(whichweek-n)*ONEWEEK + if dt.month == month: + return dt + +def valuestodict(key): + """Convert a registry key's values to a dictionary.""" + dict = {} + size = _winreg.QueryInfoKey(key)[1] + for i in range(size): + data = _winreg.EnumValue(key, i) + dict[data[0]] = data[1] + return dict diff --git a/lib/dateutil/zoneinfo/__init__.py b/lib/dateutil/zoneinfo/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9bed6264c8b97230e787e31d56a2b7318d9f63f9 --- /dev/null +++ b/lib/dateutil/zoneinfo/__init__.py @@ -0,0 +1,87 @@ +""" +Copyright (c) 2003-2005 Gustavo Niemeyer <gustavo@niemeyer.net> + +This module offers extensions to the standard python 2.3+ +datetime module. +""" +from dateutil.tz import tzfile +from tarfile import TarFile +import os + +__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" +__license__ = "PSF License" + +__all__ = ["setcachesize", "gettz", "rebuild"] + +CACHE = [] +CACHESIZE = 10 + +class tzfile(tzfile): + def __reduce__(self): + return (gettz, (self._filename,)) + +def getzoneinfofile(): + filenames = os.listdir(os.path.join(os.path.dirname(__file__))) + filenames.sort() + filenames.reverse() + for entry in filenames: + if entry.startswith("zoneinfo") and ".tar." in entry: + return os.path.join(os.path.dirname(__file__), entry) + return None + +ZONEINFOFILE = getzoneinfofile() + +del getzoneinfofile + +def setcachesize(size): + global CACHESIZE, CACHE + CACHESIZE = size + del CACHE[size:] + +def gettz(name): + tzinfo = None + if ZONEINFOFILE: + for cachedname, tzinfo in CACHE: + if cachedname == name: + break + else: + tf = TarFile.open(ZONEINFOFILE) + try: + zonefile = tf.extractfile(name) + except KeyError: + tzinfo = None + else: + tzinfo = tzfile(zonefile) + tf.close() + CACHE.insert(0, (name, tzinfo)) + del CACHE[CACHESIZE:] + return tzinfo + +def rebuild(filename, tag=None, format="gz"): + import tempfile, shutil + tmpdir = tempfile.mkdtemp() + zonedir = os.path.join(tmpdir, "zoneinfo") + moduledir = os.path.dirname(__file__) + if tag: tag = "-"+tag + targetname = "zoneinfo%s.tar.%s" % (tag, format) + try: + tf = TarFile.open(filename) + for name in tf.getnames(): + if not (name.endswith(".sh") or + name.endswith(".tab") or + name == "leapseconds"): + tf.extract(name, tmpdir) + filepath = os.path.join(tmpdir, name) + os.system("zic -d %s %s" % (zonedir, filepath)) + tf.close() + target = os.path.join(moduledir, targetname) + for entry in os.listdir(moduledir): + if entry.startswith("zoneinfo") and ".tar." in entry: + os.unlink(os.path.join(moduledir, entry)) + tf = TarFile.open(target, "w:%s" % format) + for entry in os.listdir(zonedir): + entrypath = os.path.join(zonedir, entry) + tf.add(entrypath, entry) + tf.close() + finally: + shutil.rmtree(tmpdir) diff --git a/lib/dateutil/zoneinfo/zoneinfo-2010g.tar.gz b/lib/dateutil/zoneinfo/zoneinfo-2010g.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..8bd4f96402be50779e4b2749688d077347a6eef0 Binary files /dev/null and b/lib/dateutil/zoneinfo/zoneinfo-2010g.tar.gz differ diff --git a/lib/profilehooks.py b/lib/profilehooks.py new file mode 100644 index 0000000000000000000000000000000000000000..fcc0cdc2f7864f1bd7de7603ed6ce68e3bf53474 --- /dev/null +++ b/lib/profilehooks.py @@ -0,0 +1,733 @@ +""" +Profiling hooks + +This module contains a couple of decorators (`profile` and `coverage`) that +can be used to wrap functions and/or methods to produce profiles and line +coverage reports. There's a third convenient decorator (`timecall`) that +measures the duration of function execution without the extra profiling +overhead. + +Usage example (Python 2.4 or newer):: + + from profilehooks import profile, coverage + + @profile # or @coverage + def fn(n): + if n < 2: return 1 + else: return n * fn(n-1) + + print fn(42) + +Usage example (Python 2.3 or older):: + + from profilehooks import profile, coverage + + def fn(n): + if n < 2: return 1 + else: return n * fn(n-1) + + # Now wrap that function in a decorator + fn = profile(fn) # or coverage(fn) + + print fn(42) + +Reports for all thusly decorated functions will be printed to sys.stdout +on program termination. You can alternatively request for immediate +reports for each call by passing immediate=True to the profile decorator. + +There's also a @timecall decorator for printing the time to sys.stderr +every time a function is called, when you just want to get a rough measure +instead of a detailed (but costly) profile. + +Caveats + + A thread on python-dev convinced me that hotshot produces bogus numbers. + See http://mail.python.org/pipermail/python-dev/2005-November/058264.html + + I don't know what will happen if a decorated function will try to call + another decorated function. All decorators probably need to explicitly + support nested profiling (currently TraceFuncCoverage is the only one + that supports this, while HotShotFuncProfile has support for recursive + functions.) + + Profiling with hotshot creates temporary files (*.prof for profiling, + *.cprof for coverage) in the current directory. These files are not + cleaned up. Exception: when you specify a filename to the profile + decorator (to store the pstats.Stats object for later inspection), + the temporary file will be the filename you specified with '.raw' + appended at the end. + + Coverage analysis with hotshot seems to miss some executions resulting + in lower line counts and some lines errorneously marked as never + executed. For this reason coverage analysis now uses trace.py which is + slower, but more accurate. + +Copyright (c) 2004--2008 Marius Gedminas <marius@pov.lt> +Copyright (c) 2007 Hanno Schlichting +Copyright (c) 2008 Florian Schulze + +Released under the MIT licence since December 2006: + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +(Previously it was distributed under the GNU General Public Licence.) +""" +# $Id: profilehooks.py 29 2010-08-13 16:29:20Z mg $ + +__author__ = "Marius Gedminas (marius@gedmin.as)" +__copyright__ = "Copyright 2004-2009 Marius Gedminas" +__license__ = "MIT" +__version__ = "1.4" +__date__ = "2009-03-31" + + +import atexit +import inspect +import sys +import re + +# For profiling +from profile import Profile +import pstats + +# For hotshot profiling (inaccurate!) +try: + import hotshot + import hotshot.stats +except ImportError: + hotshot = None + +# For trace.py coverage +import trace + +# For hotshot coverage (inaccurate!; uses undocumented APIs; might break) +if hotshot is not None: + import _hotshot + import hotshot.log + +# For cProfile profiling (best) +try: + import cProfile +except ImportError: + cProfile = None + +# For timecall +import time + + +# registry of available profilers +AVAILABLE_PROFILERS = {} + + +def profile(fn=None, skip=0, filename=None, immediate=False, dirs=False, + sort=None, entries=40, + profiler=('cProfile', 'profile', 'hotshot')): + """Mark `fn` for profiling. + + If `skip` is > 0, first `skip` calls to `fn` will not be profiled. + + If `immediate` is False, profiling results will be printed to + sys.stdout on program termination. Otherwise results will be printed + after each call. + + If `dirs` is False only the name of the file will be printed. + Otherwise the full path is used. + + `sort` can be a list of sort keys (defaulting to ['cumulative', + 'time', 'calls']). The following ones are recognized:: + + 'calls' -- call count + 'cumulative' -- cumulative time + 'file' -- file name + 'line' -- line number + 'module' -- file name + 'name' -- function name + 'nfl' -- name/file/line + 'pcalls' -- call count + 'stdname' -- standard name + 'time' -- internal time + + `entries` limits the output to the first N entries. + + `profiler` can be used to select the preferred profiler, or specify a + sequence of them, in order of preference. The default is ('cProfile'. + 'profile', 'hotshot'). + + If `filename` is specified, the profile stats will be stored in the + named file. You can load them pstats.Stats(filename). + + Usage:: + + def fn(...): + ... + fn = profile(fn, skip=1) + + If you are using Python 2.4, you should be able to use the decorator + syntax:: + + @profile(skip=3) + def fn(...): + ... + + or just :: + + @profile + def fn(...): + ... + + """ + if fn is None: # @profile() syntax -- we are a decorator maker + def decorator(fn): + return profile(fn, skip=skip, filename=filename, + immediate=immediate, dirs=dirs, + sort=sort, entries=entries, + profiler=profiler) + return decorator + # @profile syntax -- we are a decorator. + if isinstance(profiler, str): + profiler = [profiler] + for p in profiler: + if p in AVAILABLE_PROFILERS: + profiler_class = AVAILABLE_PROFILERS[p] + break + else: + raise ValueError('only these profilers are available: %s' + % ', '.join(AVAILABLE_PROFILERS)) + fp = profiler_class(fn, skip=skip, filename=filename, + immediate=immediate, dirs=dirs, + sort=sort, entries=entries) + # fp = HotShotFuncProfile(fn, skip=skip, filename=filename, ...) + # or HotShotFuncProfile + # We cannot return fp or fp.__call__ directly as that would break method + # definitions, instead we need to return a plain function. + def new_fn(*args, **kw): + return fp(*args, **kw) + new_fn.__doc__ = fn.__doc__ + new_fn.__name__ = fn.__name__ + new_fn.__dict__ = fn.__dict__ + new_fn.__module__ = fn.__module__ + return new_fn + + +def coverage(fn): + """Mark `fn` for line coverage analysis. + + Results will be printed to sys.stdout on program termination. + + Usage:: + + def fn(...): + ... + fn = coverage(fn) + + If you are using Python 2.4, you should be able to use the decorator + syntax:: + + @coverage + def fn(...): + ... + + """ + fp = TraceFuncCoverage(fn) # or HotShotFuncCoverage + # We cannot return fp or fp.__call__ directly as that would break method + # definitions, instead we need to return a plain function. + def new_fn(*args, **kw): + return fp(*args, **kw) + new_fn.__doc__ = fn.__doc__ + new_fn.__name__ = fn.__name__ + new_fn.__dict__ = fn.__dict__ + new_fn.__module__ = fn.__module__ + return new_fn + + +def coverage_with_hotshot(fn): + """Mark `fn` for line coverage analysis. + + Uses the 'hotshot' module for fast coverage analysis. + + BUG: Produces inaccurate results. + + See the docstring of `coverage` for usage examples. + """ + fp = HotShotFuncCoverage(fn) + # We cannot return fp or fp.__call__ directly as that would break method + # definitions, instead we need to return a plain function. + def new_fn(*args, **kw): + return fp(*args, **kw) + new_fn.__doc__ = fn.__doc__ + new_fn.__name__ = fn.__name__ + new_fn.__dict__ = fn.__dict__ + new_fn.__module__ = fn.__module__ + return new_fn + + +class FuncProfile(object): + """Profiler for a function (uses profile).""" + + # This flag is shared between all instances + in_profiler = False + + Profile = Profile + + def __init__(self, fn, skip=0, filename=None, immediate=False, dirs=False, + sort=None, entries=40): + """Creates a profiler for a function. + + Every profiler has its own log file (the name of which is derived + from the function name). + + FuncProfile registers an atexit handler that prints profiling + information to sys.stderr when the program terminates. + """ + self.fn = fn + self.skip = skip + self.filename = filename + self.immediate = immediate + self.dirs = dirs + self.sort = sort or ('cumulative', 'time', 'calls') + if isinstance(self.sort, str): + self.sort = (self.sort, ) + self.entries = entries + self.reset_stats() + atexit.register(self.atexit) + + def __call__(self, *args, **kw): + """Profile a singe call to the function.""" + self.ncalls += 1 + if self.skip > 0: + self.skip -= 1 + self.skipped += 1 + return self.fn(*args, **kw) + if FuncProfile.in_profiler: + # handle recursive calls + return self.fn(*args, **kw) + # You cannot reuse the same profiler for many calls and accumulate + # stats that way. :-/ + profiler = self.Profile() + try: + FuncProfile.in_profiler = True + return profiler.runcall(self.fn, *args, **kw) + finally: + FuncProfile.in_profiler = False + self.stats.add(profiler) + if self.immediate: + self.print_stats() + self.reset_stats() + + def print_stats(self): + """Print profile information to sys.stdout.""" + funcname = self.fn.__name__ + filename = self.fn.func_code.co_filename + lineno = self.fn.func_code.co_firstlineno + print + print "*** PROFILER RESULTS ***" + print "%s (%s:%s)" % (funcname, filename, lineno) + print "function called %d times" % self.ncalls, + if self.skipped: + print "(%d calls not profiled)" % self.skipped + else: + print + print + stats = self.stats + if self.filename: + stats.dump_stats(self.filename) + if not self.dirs: + stats.strip_dirs() + stats.sort_stats(*self.sort) + stats.print_stats(self.entries) + + def reset_stats(self): + """Reset accumulated profiler statistics.""" + # Note: not using self.Profile, since pstats.Stats() fails then + self.stats = pstats.Stats(Profile()) + self.ncalls = 0 + self.skipped = 0 + + def atexit(self): + """Stop profiling and print profile information to sys.stdout. + + This function is registered as an atexit hook. + """ + if not self.immediate: + self.print_stats() + + +AVAILABLE_PROFILERS['profile'] = FuncProfile + + +if cProfile is not None: + + class CProfileFuncProfile(FuncProfile): + """Profiler for a function (uses cProfile).""" + + Profile = cProfile.Profile + + AVAILABLE_PROFILERS['cProfile'] = CProfileFuncProfile + + +if hotshot is not None: + + class HotShotFuncProfile(object): + """Profiler for a function (uses hotshot).""" + + # This flag is shared between all instances + in_profiler = False + + def __init__(self, fn, skip=0, filename=None): + """Creates a profiler for a function. + + Every profiler has its own log file (the name of which is derived + from the function name). + + HotShotFuncProfile registers an atexit handler that prints + profiling information to sys.stderr when the program terminates. + + The log file is not removed and remains there to clutter the + current working directory. + """ + self.fn = fn + self.filename = filename + if self.filename: + self.logfilename = filename + ".raw" + else: + self.logfilename = fn.__name__ + ".prof" + self.profiler = hotshot.Profile(self.logfilename) + self.ncalls = 0 + self.skip = skip + self.skipped = 0 + atexit.register(self.atexit) + + def __call__(self, *args, **kw): + """Profile a singe call to the function.""" + self.ncalls += 1 + if self.skip > 0: + self.skip -= 1 + self.skipped += 1 + return self.fn(*args, **kw) + if HotShotFuncProfile.in_profiler: + # handle recursive calls + return self.fn(*args, **kw) + try: + HotShotFuncProfile.in_profiler = True + return self.profiler.runcall(self.fn, *args, **kw) + finally: + HotShotFuncProfile.in_profiler = False + + def atexit(self): + """Stop profiling and print profile information to sys.stderr. + + This function is registered as an atexit hook. + """ + self.profiler.close() + funcname = self.fn.__name__ + filename = self.fn.func_code.co_filename + lineno = self.fn.func_code.co_firstlineno + print + print "*** PROFILER RESULTS ***" + print "%s (%s:%s)" % (funcname, filename, lineno) + print "function called %d times" % self.ncalls, + if self.skipped: + print "(%d calls not profiled)" % self.skipped + else: + print + print + stats = hotshot.stats.load(self.logfilename) + # hotshot.stats.load takes ages, and the .prof file eats megabytes, but + # a saved stats object is small and fast + if self.filename: + stats.dump_stats(self.filename) + # it is best to save before strip_dirs + stats.strip_dirs() + stats.sort_stats('cumulative', 'time', 'calls') + stats.print_stats(40) + + AVAILABLE_PROFILERS['hotshot'] = HotShotFuncProfile + + + class HotShotFuncCoverage: + """Coverage analysis for a function (uses _hotshot). + + HotShot coverage is reportedly faster than trace.py, but it appears to + have problems with exceptions; also line counts in coverage reports + are generally lower from line counts produced by TraceFuncCoverage. + Is this my bug, or is it a problem with _hotshot? + """ + + def __init__(self, fn): + """Creates a profiler for a function. + + Every profiler has its own log file (the name of which is derived + from the function name). + + HotShotFuncCoverage registers an atexit handler that prints + profiling information to sys.stderr when the program terminates. + + The log file is not removed and remains there to clutter the + current working directory. + """ + self.fn = fn + self.logfilename = fn.__name__ + ".cprof" + self.profiler = _hotshot.coverage(self.logfilename) + self.ncalls = 0 + atexit.register(self.atexit) + + def __call__(self, *args, **kw): + """Profile a singe call to the function.""" + self.ncalls += 1 + return self.profiler.runcall(self.fn, args, kw) + + def atexit(self): + """Stop profiling and print profile information to sys.stderr. + + This function is registered as an atexit hook. + """ + self.profiler.close() + funcname = self.fn.__name__ + filename = self.fn.func_code.co_filename + lineno = self.fn.func_code.co_firstlineno + print + print "*** COVERAGE RESULTS ***" + print "%s (%s:%s)" % (funcname, filename, lineno) + print "function called %d times" % self.ncalls + print + fs = FuncSource(self.fn) + reader = hotshot.log.LogReader(self.logfilename) + for what, (filename, lineno, funcname), tdelta in reader: + if filename != fs.filename: + continue + if what == hotshot.log.LINE: + fs.mark(lineno) + if what == hotshot.log.ENTER: + # hotshot gives us the line number of the function definition + # and never gives us a LINE event for the first statement in + # a function, so if we didn't perform this mapping, the first + # statement would be marked as never executed + if lineno == fs.firstlineno: + lineno = fs.firstcodelineno + fs.mark(lineno) + reader.close() + print fs + + +class TraceFuncCoverage: + """Coverage analysis for a function (uses trace module). + + HotShot coverage analysis is reportedly faster, but it appears to have + problems with exceptions. + """ + + # Shared between all instances so that nested calls work + tracer = trace.Trace(count=True, trace=False, + ignoredirs=[sys.prefix, sys.exec_prefix]) + + # This flag is also shared between all instances + tracing = False + + def __init__(self, fn): + """Creates a profiler for a function. + + Every profiler has its own log file (the name of which is derived + from the function name). + + TraceFuncCoverage registers an atexit handler that prints + profiling information to sys.stderr when the program terminates. + + The log file is not removed and remains there to clutter the + current working directory. + """ + self.fn = fn + self.logfilename = fn.__name__ + ".cprof" + self.ncalls = 0 + atexit.register(self.atexit) + + def __call__(self, *args, **kw): + """Profile a singe call to the function.""" + self.ncalls += 1 + if TraceFuncCoverage.tracing: + return self.fn(*args, **kw) + try: + TraceFuncCoverage.tracing = True + return self.tracer.runfunc(self.fn, *args, **kw) + finally: + TraceFuncCoverage.tracing = False + + def atexit(self): + """Stop profiling and print profile information to sys.stderr. + + This function is registered as an atexit hook. + """ + funcname = self.fn.__name__ + filename = self.fn.func_code.co_filename + lineno = self.fn.func_code.co_firstlineno + print + print "*** COVERAGE RESULTS ***" + print "%s (%s:%s)" % (funcname, filename, lineno) + print "function called %d times" % self.ncalls + print + fs = FuncSource(self.fn) + for (filename, lineno), count in self.tracer.counts.items(): + if filename != fs.filename: + continue + fs.mark(lineno, count) + print fs + never_executed = fs.count_never_executed() + if never_executed: + print "%d lines were not executed." % never_executed + + +class FuncSource: + """Source code annotator for a function.""" + + blank_rx = re.compile(r"^\s*finally:\s*(#.*)?$") + + def __init__(self, fn): + self.fn = fn + self.filename = inspect.getsourcefile(fn) + self.source, self.firstlineno = inspect.getsourcelines(fn) + self.sourcelines = {} + self.firstcodelineno = self.firstlineno + self.find_source_lines() + + def find_source_lines(self): + """Mark all executable source lines in fn as executed 0 times.""" + strs = trace.find_strings(self.filename) + lines = trace.find_lines_from_code(self.fn.func_code, strs) + self.firstcodelineno = sys.maxint + for lineno in lines: + self.firstcodelineno = min(self.firstcodelineno, lineno) + self.sourcelines.setdefault(lineno, 0) + if self.firstcodelineno == sys.maxint: + self.firstcodelineno = self.firstlineno + + def mark(self, lineno, count=1): + """Mark a given source line as executed count times. + + Multiple calls to mark for the same lineno add up. + """ + self.sourcelines[lineno] = self.sourcelines.get(lineno, 0) + count + + def count_never_executed(self): + """Count statements that were never executed.""" + lineno = self.firstlineno + counter = 0 + for line in self.source: + if self.sourcelines.get(lineno) == 0: + if not self.blank_rx.match(line): + counter += 1 + lineno += 1 + return counter + + def __str__(self): + """Return annotated source code for the function.""" + lines = [] + lineno = self.firstlineno + for line in self.source: + counter = self.sourcelines.get(lineno) + if counter is None: + prefix = ' ' * 7 + elif counter == 0: + if self.blank_rx.match(line): + prefix = ' ' * 7 + else: + prefix = '>' * 6 + ' ' + else: + prefix = '%5d: ' % counter + lines.append(prefix + line) + lineno += 1 + return ''.join(lines) + + +def timecall(fn=None, immediate=True, timer=time.time): + """Wrap `fn` and print its execution time. + + Example:: + + @timecall + def somefunc(x, y): + time.sleep(x * y) + + somefunc(2, 3) + + will print the time taken by somefunc on every call. If you want just + a summary at program termination, use + + @timecall(immediate=False) + + You can also choose a timing method other than the default ``time.time()``, + e.g.: + + @timecall(timer=time.clock) + + """ + if fn is None: # @timecall() syntax -- we are a decorator maker + def decorator(fn): + return timecall(fn, immediate=immediate, timer=timer) + return decorator + # @timecall syntax -- we are a decorator. + fp = FuncTimer(fn, immediate=immediate, timer=timer) + # We cannot return fp or fp.__call__ directly as that would break method + # definitions, instead we need to return a plain function. + def new_fn(*args, **kw): + return fp(*args, **kw) + new_fn.__doc__ = fn.__doc__ + new_fn.__name__ = fn.__name__ + new_fn.__dict__ = fn.__dict__ + new_fn.__module__ = fn.__module__ + return new_fn + + +class FuncTimer(object): + + def __init__(self, fn, immediate, timer): + self.fn = fn + self.ncalls = 0 + self.totaltime = 0 + self.immediate = immediate + self.timer = timer + if not immediate: + atexit.register(self.atexit) + + def __call__(self, *args, **kw): + """Profile a singe call to the function.""" + fn = self.fn + timer = self.timer + self.ncalls += 1 + try: + start = timer() + return fn(*args, **kw) + finally: + duration = timer() - start + self.totaltime += duration + if self.immediate: + funcname = fn.__name__ + filename = fn.func_code.co_filename + lineno = fn.func_code.co_firstlineno + print >> sys.stderr, "\n %s (%s:%s):\n %.3f seconds\n" % ( + funcname, filename, lineno, duration) + def atexit(self): + if not self.ncalls: + return + funcname = self.fn.__name__ + filename = self.fn.func_code.co_filename + lineno = self.fn.func_code.co_firstlineno + print ("\n %s (%s:%s):\n" + " %d calls, %.3f seconds (%.3f seconds per call)\n" % ( + funcname, filename, lineno, self.ncalls, + self.totaltime, self.totaltime / self.ncalls)) + diff --git a/lib/pygithub/__init__.py b/lib/pygithub/__init__.py deleted file mode 100644 index ad56e08736281760d4c5d20c45411ed16e552588..0000000000000000000000000000000000000000 --- a/lib/pygithub/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# <http://www.opensource.org/licenses/mit-license.php> -""" -github module. -""" -__all__ = ['github','ghsearch','githubsync'] diff --git a/lib/pygithub/ghsearch.py b/lib/pygithub/ghsearch.py deleted file mode 100644 index 586e502b18297fd16026e579ec70fe611e297284..0000000000000000000000000000000000000000 --- a/lib/pygithub/ghsearch.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# <http://www.opensource.org/licenses/mit-license.php> -""" -Search script. -""" - -import sys - -import github - -def usage(): - """display the usage and exit""" - print "Usage: %s keyword [keyword...]" % (sys.argv[0]) - sys.exit(1) - -def mk_url(repo): - return "http://github.com/%s/%s" % (repo.username, repo.name) - -if __name__ == '__main__': - g = github.GitHub() - if len(sys.argv) < 2: - usage() - res = g.repos.search(' '.join(sys.argv[1:])) - - for repo in res: - try: - print "Found %s at %s" % (repo.name, mk_url(repo)) - except AttributeError: - print "Bug: Couldn't format %s" % repo.__dict__ diff --git a/lib/pygithub/github.py b/lib/pygithub/github.py deleted file mode 100644 index bd9f40776dad1db40696c16fff73849d9452f784..0000000000000000000000000000000000000000 --- a/lib/pygithub/github.py +++ /dev/null @@ -1,520 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# <http://www.opensource.org/licenses/mit-license.php> -""" -Interface to github's API (v2). - -Basic usage: - -g = GitHub() - -for r in g.user.search('dustin'): - print r.name - -See the GitHub docs or README.markdown for more usage. - -Copyright (c) 2007 Dustin Sallings <dustin@spy.net> -""" - -# GAE friendly URL detection (theoretically) -try: - import urllib2 - default_fetcher = urllib2.urlopen -except LoadError: - pass - -import urllib -import xml -import xml.dom.minidom - -def _string_parser(x): - """Extract the data from the first child of the input.""" - return x.firstChild.data - -_types = { - 'string': _string_parser, - 'integer': lambda x: int(_string_parser(x)), - 'float': lambda x: float(_string_parser(x)), - 'datetime': _string_parser, - 'boolean': lambda x: _string_parser(x) == 'true' -} - -def _parse(el): - """Generic response parser.""" - - type = 'string' - if el.attributes and 'type' in el.attributes.keys(): - type = el.attributes['type'].value - elif el.localName in _types: - type = el.localName - elif len(el.childNodes) > 1: - # This is a container, find the child type - type = None - ch = el.firstChild - while ch and not type: - if ch.localName == 'type': - type = ch.firstChild.data - ch = ch.nextSibling - - if not type: - raise Exception("Can't parse %s, known: %s" - % (el.toxml(), repr(_types.keys()))) - - return _types[type](el) - -def parses(t): - """Parser for a specific type in the github response.""" - def f(orig): - orig.parses = t - return orig - return f - -def with_temporary_mappings(m): - """Allow temporary localized altering of type mappings.""" - def f(orig): - def every(self, *args): - global _types - o = _types.copy() - for k,v in m.items(): - if v: - _types[k] = v - else: - del _types[k] - try: - return orig(self, *args) - finally: - _types = o - return every - return f - -@parses('array') -def _parseArray(el): - rv = [] - ch = el.firstChild - while ch: - if ch.nodeType != xml.dom.Node.TEXT_NODE and ch.firstChild: - rv.append(_parse(ch)) - ch=ch.nextSibling - return rv - -class BaseResponse(object): - """Base class for XML Response Handling.""" - - def __init__(self, el): - ch = el.firstChild - while ch: - if ch.nodeType != xml.dom.Node.TEXT_NODE and ch.firstChild: - ln = ch.localName.replace('-', '_') - self.__dict__[ln] = _parse(ch) - ch=ch.nextSibling - - def __repr__(self): - return "<<%s>>" % str(self.__class__) - -class User(BaseResponse): - """A github user.""" - - parses = 'user' - - def __repr__(self): - return "<<User %s>>" % self.name - -class Plan(BaseResponse): - """A github plan.""" - - parses = 'plan' - - def __repr__(self): - return "<<Plan %s>>" % self.name - -class Repository(BaseResponse): - """A repository.""" - - parses = 'repository' - - @property - def owner_name(self): - if hasattr(self, 'owner'): - return self.owner - else: - return self.username - - def __repr__(self): - return "<<Repository %s/%s>>" % (self.owner_name, self.name) - -class PublicKey(BaseResponse): - """A public key.""" - - parses = 'public-key' - title = 'untitled' - - def __repr__(self): - return "<<Public key %s>>" % self.title - -class Commit(BaseResponse): - """A commit.""" - - parses = 'commit' - - def __repr__(self): - return "<<Commit: %s>>" % self.id - -class Parent(Commit): - """A commit parent.""" - - parses = 'parent' - -class Author(User): - """A commit author.""" - - parses = 'author' - -class Committer(User): - """A commit committer.""" - - parses = 'committer' - -class Issue(BaseResponse): - """An issue within the issue tracker.""" - - parses = 'issue' - - def __repr__(self): - return "<<Issue #%d>>" % self.number - -class Label(BaseResponse): - """A Label within the issue tracker.""" - parses = 'label' - - def __repr__(self): - return "<<Label $%d>>" % self.number - -class Tree(BaseResponse): - """A Tree object.""" - - # Parsing is scoped to objects... - def __repr__(self): - return "<<Tree: %s>>" % self.name - -class Blob(BaseResponse): - """A Blob object.""" - - # Parsing is scoped to objects... - def __repr__(self): - return "<<Blob: %s>>" % self.name - -class Modification(BaseResponse): - """A modification object.""" - - # Parsing is scoped to usage - def __repr__(self): - return "<<Modification of %s>>" % self.filename - -class Network(BaseResponse): - """A network entry.""" - - parses = 'network' - - def __repr__(self): - return "<<Network of %s/%s>>" % (self.owner, self.name) - -# Load the known types. -for __t in (t for t in globals().values() if hasattr(t, 'parses')): - _types[__t.parses] = __t - -class BaseEndpoint(object): - - BASE_URL = 'http://github.com/api/v2/xml/' - - def __init__(self, user, token, fetcher): - self.user = user - self.token = token - self.fetcher = fetcher - - def _raw_fetch(self, path): - p = self.BASE_URL + path - args = '' - if self.user and self.token: - params = '&'.join(['login=' + urllib.quote(self.user), - 'token=' + urllib.quote(self.token)]) - if '?' in path: - p += params - else: - p += '?' + params - return self.fetcher(p).read() - - def _fetch(self, path): - return xml.dom.minidom.parseString(self._raw_fetch(path)) - - def _post(self, path, **kwargs): - p = {'login': self.user, 'token': self.token} - p.update(kwargs) - return self.fetcher(self.BASE_URL + path, urllib.urlencode(p)).read() - - def _parsed(self, path): - doc = self._fetch(path) - return _parse(doc.documentElement) - - def _posted(self,path,**kwargs): - stuff = self._post(path,**kwargs) - doc = xml.dom.minidom.parseString(stuff) - return _parse(doc.documentElement) - -class UserEndpoint(BaseEndpoint): - - def search(self, query): - """Search for a user.""" - return self._parsed('user/search/' + query) - - def show(self, username): - """Get the info for a user.""" - return self._parsed('user/show/' + username) - - def keys(self): - """Get the public keys for a user.""" - return self._parsed('user/keys') - - def removeKey(self, keyId): - """Remove the key with the given ID (as retrieved from keys)""" - self._post('user/key/remove', id=keyId) - - def addKey(self, name, key): - """Add an ssh key.""" - self._post('user/key/add', name=name, key=key) - -class RepositoryEndpoint(BaseEndpoint): - - def forUser(self, username): - """Get the repositories for the given user.""" - return self._parsed('repos/show/' + username) - - def branches(self, user, repo): - """List the branches for a repo.""" - doc = self._fetch("repos/show/" + user + "/" + repo + "/branches") - rv = {} - for c in doc.documentElement.childNodes: - if c.nodeType != xml.dom.Node.TEXT_NODE: - rv[c.localName] = str(c.firstChild.data) - return rv - - def search(self, term): - """Search for repositories.""" - return self._parsed('repos/search/' + urllib.quote_plus(term)) - - def show(self, user, repo): - """Lookup an individual repository.""" - return self._parsed('/'.join(['repos', 'show', user, repo])) - - def watch(self, user, repo): - """Watch a repository.""" - self._post('repos/watch/' + user + '/' + repo) - - def unwatch(self, user, repo): - """Stop watching a repository.""" - self._post('repos/unwatch/' + user + '/' + repo) - - def watched(self, user): - """Get watched repositories of a user.""" - return self._parsed('repos/watched/' + user) - - def network(self, user, repo): - """Get the network for a given repo.""" - return self._parsed('repos/show/' + user + '/' + repo + '/network') - - def setVisible(self, repo, public=True): - """Set the visibility of the given repository (owned by the current user).""" - if public: - path = 'repos/set/public/' + repo - else: - path = 'repos/set/private/' + repo - self._post(path) - - def create(self, name, description='', homepage='', public=1): - """Create a new repository.""" - self._post('repos/create', name=name, description=description, - homepage=homepage, public=str(public)) - - def delete(self, repo): - """Delete a repository.""" - self._post('repos/delete/' + repo) - - def fork(self, user, repo): - """Fork a user's repo.""" - self._post('repos/fork/' + user + '/' + repo) - - def collaborators(self, user, repo): - """Find all of the collaborators of one of your repositories.""" - return self._parsed('repos/show/%s/%s/collaborators' % (user, repo)) - - def addCollaborator(self, repo, username): - """Add a collaborator to one of your repositories.""" - self._post('repos/collaborators/' + repo + '/add/' + username) - - def removeCollaborator(self, repo, username): - """Remove a collaborator from one of your repositories.""" - self._post('repos/collaborators/' + repo + '/remove/' + username) - - def collaborators_all(self): - """Find all of the collaborators of every of your repositories. - - Returns a dictionary with reponame as key and a list of collaborators as value.""" - ret = {} - for reponame in (rp.name for rp in self.forUser(self.user)): - ret[reponame] = self.collaborators(self.user, reponame) - return ret - - def addCollaborator_all(self, username): - """Add a collaborator to all of your repositories.""" - for reponame in (rp.name for rp in self.forUser(self.user)): - self.addCollaborator(reponame, username) - - def removeCollaborator_all(self, username): - """Remove a collaborator from all of your repositories.""" - for reponame in (rp.name for rp in self.forUser(self.user)): - self.removeCollaborator(reponame, username) - - def deployKeys(self, repo): - """List the deploy keys for the given repository. - - The repository must be owned by the current user.""" - return self._parsed('repos/keys/' + repo) - - def addDeployKey(self, repo, title, key): - """Add a deploy key to a repository.""" - self._post('repos/key/' + repo + '/add', title=title, key=key) - - def removeDeployKey(self, repo, keyId): - """Remove a deploy key.""" - self._post('repos/key/' + repo + '/remove', id=keyId) - -class CommitEndpoint(BaseEndpoint): - - def forBranch(self, user, repo, branch='master'): - """Get the commits for the given branch.""" - return self._parsed('/'.join(['commits', 'list', user, repo, branch])) - - def forFile(self, user, repo, path, branch='master'): - """Get the commits for the given file within the given branch.""" - return self._parsed('/'.join(['commits', 'list', user, repo, branch, path])) - - @with_temporary_mappings({'removed': _parseArray, - 'added': _parseArray, - 'modified': Modification, - 'diff': _string_parser, - 'filename': _string_parser}) - def show(self, user, repo, sha): - """Get an individual commit.""" - c = self._parsed('/'.join(['commits', 'show', user, repo, sha])) - # Some fixup due to weird XML structure - if hasattr(c, 'removed'): - c.removed = [i[0] for i in c.removed] - if hasattr(c, 'added'): - c.added = [i[0] for i in c.added] - return c - -class IssuesEndpoint(BaseEndpoint): - - @with_temporary_mappings({'user': None}) - def list(self, user, repo, state='open'): - """Get the list of issues for the given repo in the given state.""" - return self._parsed('/'.join(['issues', 'list', user, repo, state])) - - @with_temporary_mappings({'user': None}) - def show(self, user, repo, issue_id): - """Show an individual issue.""" - return self._parsed('/'.join(['issues', 'show', user, repo, str(issue_id)])) - - def add_label(self, user, repo, issue_id, label): - """Add a label to an issue.""" - self._post('issues/label/add/' + user + '/' - + repo + '/' + label + '/' + str(issue_id)) - - def remove_label(self, user, repo, issue_id, label): - """Remove a label from an issue.""" - self._post('issues/label/remove/' + user + '/' - + repo + '/' + label + '/' + str(issue_id)) - - def close(self, user, repo, issue_id): - """Close an issue.""" - self._post('/'.join(['issues', 'close', user, repo, str(issue_id)])) - - def reopen(self, user, repo, issue_id): - """Reopen an issue.""" - self._post('/'.join(['issues', 'reopen', user, repo, str(issue_id)])) - - def new(self, user, repo, title, body=''): - """Create a new issue.""" - return self._posted('/'.join(['issues', 'open', user, repo]), - title=title, body=body) - - def edit(self, user, repo, issue_id, title, body): - """Create a new issue.""" - self._post('/'.join(['issues', 'edit', user, repo, str(issue_id)]), - title=title, body=body) - -class ObjectsEndpoint(BaseEndpoint): - - @with_temporary_mappings({'tree': Tree, 'type': _string_parser}) - def tree(self, user, repo, t): - """Get the given tree from the given repo.""" - tl = self._parsed('/'.join(['tree', 'show', user, repo, t])) - return dict([(t.name, t) for t in tl]) - - @with_temporary_mappings({'blob': Blob}) - def blob(self, user, repo, t, fn): - return self._parsed('/'.join(['blob', 'show', user, repo, t, fn])) - - def raw_blob(self, user, repo, sha): - """Get a raw blob from a repo.""" - path = 'blob/show/%s/%s/%s' % (user, repo, sha) - return self._raw_fetch(path) - -class GitHub(object): - """Interface to github.""" - - def __init__(self, user=None, token=None, fetcher=default_fetcher): - self.user = user - self.token = token - self.fetcher = fetcher - - @property - def users(self): - """Get access to the user API.""" - return UserEndpoint(self.user, self.token, self.fetcher) - - @property - def repos(self): - """Get access to the user API.""" - return RepositoryEndpoint(self.user, self.token, self.fetcher) - - @property - def commits(self): - return CommitEndpoint(self.user, self.token, self.fetcher) - - @property - def issues(self): - return IssuesEndpoint(self.user, self.token, self.fetcher) - - @property - def objects(self): - return ObjectsEndpoint(self.user, self.token, self.fetcher) diff --git a/lib/pygithub/githubsync.py b/lib/pygithub/githubsync.py deleted file mode 100644 index 50d70a076ad566970637f9f812dd733ee07f9b26..0000000000000000000000000000000000000000 --- a/lib/pygithub/githubsync.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# <http://www.opensource.org/licenses/mit-license.php> -""" -Grab all of a user's projects from github. -""" - -import os -import sys -import subprocess - -import github - -def check_for_old_format(path, url): - p = subprocess.Popen(['git', '--git-dir=' + path, 'config', - 'remote.origin.fetch'], stdout = subprocess.PIPE) - stdout, stderr = p.communicate() - if stdout.strip() != '+refs/*:refs/*': - print "Not properly configured for mirroring, repairing." - subprocess.call(['git', '--git-dir=' + path, 'remote', 'rm', 'origin']) - add_mirror(path, url) - -def add_mirror(path, url): - subprocess.call(['git', '--git-dir=' + path, 'remote', 'add', '--mirror', - 'origin', url]) - -def sync(path, url, repo_name): - p = os.path.join(path, repo_name) + ".git" - print "Syncing %s -> %s" % (repo_name, p) - if not os.path.exists(p): - subprocess.call(['git', 'clone', '--bare', url, p]) - add_mirror(p, url) - check_for_old_format(p, url) - subprocess.call(['git', '--git-dir=' + p, 'fetch', '-f']) - -def sync_user_repo(path, repo): - sync(path, "git://github.com/%s/%s" % (repo.owner, repo.name), repo.name) - -def usage(): - sys.stderr.write("Usage: %s username destination_url\n" % sys.argv[0]) - sys.stderr.write( - """Ensures you've got the latest stuff for the given user. - -Also, if the file $HOME/.github-private exists, it will be read for -additional projects. - -Each line must be a simple project name (e.g. py-github), a tab character, -and a git URL. -""") - -if __name__ == '__main__': - try: - user, path = sys.argv[1:] - except ValueError: - usage() - exit(1) - - privfile = os.path.join(os.getenv("HOME"), ".github-private") - if os.path.exists(privfile): - f = open(privfile) - for line in f: - name, url = line.strip().split("\t") - sync(path, url, name) - - gh = github.GitHub() - - for repo in gh.repos.forUser(user): - sync_user_repo(path, repo) diff --git a/lib/pygithub/githubtest.py b/lib/pygithub/githubtest.py deleted file mode 100644 index bfb73cd892db1262689bad17bc74c6617fbd83f9..0000000000000000000000000000000000000000 --- a/lib/pygithub/githubtest.py +++ /dev/null @@ -1,493 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# <http://www.opensource.org/licenses/mit-license.php> -""" -Defines and runs unittests. -""" - -import urllib -import hashlib -import unittest - -import github - -class BaseCase(unittest.TestCase): - - def _gh(self, expUrl, filename): - - def opener(url): - self.assertEquals(expUrl, url) - return open(filename) - return github.GitHub(fetcher=opener) - - def _agh(self, expUrl, u, t, filename): - - def opener(url): - self.assertEquals(expUrl, url + '?login=' + u + '&token=' + t) - return open(filename) - return github.GitHub(fetcher=opener) - - def _ghp(self, expUrl, u, t, **kv): - - def opener(url, data): - h = {'login': u, 'token': t} - h.update(kv) - self.assertEquals(github.BaseEndpoint.BASE_URL + expUrl, url) - self.assertEquals(sorted(data.split('&')), - sorted(urllib.urlencode(h).split('&'))) - return github.GitHub(u, t, fetcher=opener) - -class UserTest(BaseCase): - - def __loadUserSearch(self): - return self._gh('http://github.com/api/v2/xml/user/search/dustin', - 'data/user.search.xml').users.search('dustin') - - def __loadUser(self, which, u=None, p=None): - if u: - return self._agh('http://github.com/api/v2/xml/user/show/dustin' - + '?login=' + u + '&token=' + p, - u, p, 'data/' + which).users.show('dustin') - - else: - return self._gh('http://github.com/api/v2/xml/user/show/dustin', - 'data/' + which).users.show('dustin') - - def testUserSearch(self): - """Test the base properties of the user object.""" - u = self.__loadUserSearch()[0] - self.assertEquals("Dustin Sallings", u.fullname) - self.assertEquals("dustin", u.name) - self.assertEquals("dustin@spy.net", u.email) - self.assertEquals("Santa Clara, CA", u.location) - self.assertEquals("Ruby", u.language) - self.assertEquals(35, u.actions) - self.assertEquals(77, u.repos) - self.assertEquals(78, u.followers) - self.assertEquals('user-1779', u.id) - self.assertAlmostEquals(12.231684, u.score) - self.assertEquals('user', u.type) - self.assertEquals('2008-02-29T17:59:09Z', u.created) - self.assertEquals('2009-03-19T09:15:24.663Z', u.pushed) - self.assertEquals("<<User dustin>>", repr(u)) - - def testUserPublic(self): - """Test the user show API with no authentication.""" - u = self.__loadUser('user.public.xml') - self.assertEquals("Dustin Sallings", u.name) - # self.assertEquals(None, u.company) - self.assertEquals(10, u.following_count) - self.assertEquals(21, u.public_gist_count) - self.assertEquals(81, u.public_repo_count) - self.assertEquals('http://bleu.west.spy.net/~dustin/', u.blog) - self.assertEquals(1779, u.id) - self.assertEquals(82, u.followers_count) - self.assertEquals('dustin', u.login) - self.assertEquals('Santa Clara, CA', u.location) - self.assertEquals('dustin@spy.net', u.email) - self.assertEquals('2008-02-29T09:59:09-08:00', u.created_at) - - def testUserPrivate(self): - """Test the user show API with extra info from auth.""" - u = self.__loadUser('user.private.xml', 'dustin', 'blahblah') - self.assertEquals("Dustin Sallings", u.name) - # self.assertEquals(None, u.company) - self.assertEquals(10, u.following_count) - self.assertEquals(21, u.public_gist_count) - self.assertEquals(81, u.public_repo_count) - self.assertEquals('http://bleu.west.spy.net/~dustin/', u.blog) - self.assertEquals(1779, u.id) - self.assertEquals(82, u.followers_count) - self.assertEquals('dustin', u.login) - self.assertEquals('Santa Clara, CA', u.location) - self.assertEquals('dustin@spy.net', u.email) - self.assertEquals('2008-02-29T09:59:09-08:00', u.created_at) - - # Begin private data - - self.assertEquals("micro", u.plan.name) - self.assertEquals(1, u.plan.collaborators) - self.assertEquals(614400, u.plan.space) - self.assertEquals(5, u.plan.private_repos) - self.assertEquals(155191, u.disk_usage) - self.assertEquals(6, u.collaborators) - self.assertEquals(4, u.owned_private_repo_count) - self.assertEquals(5, u.total_private_repo_count) - self.assertEquals(0, u.private_gist_count) - - def testKeysList(self): - """Test key listing.""" - kl = self._agh('http://github.com/api/v2/xml/user/keys?login=dustin&token=blahblah', - 'dustin', 'blahblah', 'data/keys.xml').users.keys() - self.assertEquals(7, len(kl)) - k = kl[0] - - self.assertEquals('some key', k.title) - self.assertEquals(2181, k.id) - self.assertEquals(549, k.key.find('cdEXwCSjAIFp8iRqh3GOkxGyFSc25qv/MuOBg==')) - - def testRemoveKey(self): - """Remove a key.""" - self._ghp('user/key/remove', - 'dustin', 'p', id=828).users.removeKey(828) - - def testAddKey(self): - """Add a key.""" - self._ghp('user/key/add', - 'dustin', 'p', name='my key', key='some key').users.addKey( - 'my key', 'some key') - -class RepoTest(BaseCase): - - def __loadUserRepos(self): - return self._gh('http://github.com/api/v2/xml/repos/show/verbal', - 'data/repos.xml').repos.forUser('verbal') - - def testUserRepoList(self): - """Get a list of repos for a user.""" - rs = self.__loadUserRepos() - self.assertEquals(10, len(rs)) - r = rs[0] - self.assertEquals('A beanstalk client for the twisted network framework.', - r.description) - self.assertEquals(2, r.watchers) - self.assertEquals(0, r.forks) - self.assertEquals('beanstalk-client-twisted', r.name) - self.assertEquals(False, r.private) - self.assertEquals('http://github.com/verbal/beanstalk-client-twisted', - r.url) - self.assertEquals(True, r.fork) - self.assertEquals('verbal', r.owner) - # XXX: Can't parse empty elements. :( - # self.assertEquals('', r.homepage) - - def testRepoSearch(self): - """Test searching a repository.""" - rl = self._gh('http://github.com/api/v2/xml/repos/search/ruby+testing', - 'data/repos.search.xml').repos.search('ruby testing') - self.assertEquals(12, len(rl)) - - r = rl[0] - self.assertEquals('synthesis', r.name) - self.assertAlmostEquals(0.3234576, r.score, 4) - self.assertEquals(4656, r.actions) - self.assertEquals(2048, r.size) - self.assertEquals('Ruby', r.language) - self.assertEquals(26, r.followers) - self.assertEquals('gmalamid', r.username) - self.assertEquals('repo', r.type) - self.assertEquals('repo-3555', r.id) - self.assertEquals(1, r.forks) - self.assertFalse(r.fork) - self.assertEquals('Ruby test code analysis tool employing a ' - '"Synthesized Testing" strategy, aimed to reduce ' - 'the volume of slower, coupled, complex wired tests.', - r.description) - self.assertEquals('2009-01-08T13:45:06Z', r.pushed) - self.assertEquals('2008-03-11T23:38:04Z', r.created) - - def testBranchList(self): - """Test branch listing for a repo.""" - bl = self._gh('http://github.com/api/v2/xml/repos/show/schacon/ruby-git/branches', - 'data/repos.branches.xml').repos.branches('schacon', 'ruby-git') - self.assertEquals(4, len(bl)) - self.assertEquals('ee90922f3da3f67ef19853a0759c1d09860fe3b3', bl['master']) - - def testGetOneRepo(self): - """Fetch an individual repository.""" - r = self._gh('http://github.com/api/v2/xml/repos/show/schacon/grit', - 'data/repo.xml').repos.show('schacon', 'grit') - - self.assertEquals('Grit is a Ruby library for extracting information from a ' - 'git repository in an object oriented manner - this fork ' - 'tries to intergrate as much pure-ruby functionality as possible', - r.description) - self.assertEquals(68, r.watchers) - self.assertEquals(4, r.forks) - self.assertEquals('grit', r.name) - self.assertFalse(r.private) - self.assertEquals('http://github.com/schacon/grit', r.url) - self.assertTrue(r.fork) - self.assertEquals('schacon', r.owner) - self.assertEquals('http://grit.rubyforge.org/', r.homepage) - - def testGetRepoNetwork(self): - """Test network fetching.""" - nl = self._gh('http://github.com/api/v2/xml/repos/show/dustin/py-github/network', - 'data/network.xml').repos.network('dustin', 'py-github') - self.assertEquals(5, len(nl)) - - n = nl[0] - self.assertEquals('Python interface for talking to the github API', - n.description) - self.assertEquals('py-github', n.name) - self.assertFalse(n.private) - self.assertEquals('http://github.com/dustin/py-github', n.url) - self.assertEquals(30, n.watchers) - self.assertEquals(4, n.forks) - self.assertFalse(n.fork) - self.assertEquals('dustin', n.owner) - self.assertEquals('http://dustin.github.com/2008/12/29/github-sync.html', - n.homepage) - - def testSetPublic(self): - """Test setting a repo visible.""" - self._ghp('repos/set/public/py-github', 'dustin', 'p').repos.setVisible( - 'py-github') - - def testSetPrivate(self): - """Test setting a repo to private.""" - self._ghp('repos/set/private/py-github', 'dustin', 'p').repos.setVisible( - 'py-github', False) - - def testCreateRepository(self): - """Test creating a repository.""" - self._ghp('repos/create', 'dustin', 'p', - name='testrepo', - description='woo', - homepage='', - public='1').repos.create( - 'testrepo', description='woo') - - def testDeleteRepo(self): - """Test setting a repo to private.""" - self._ghp('repos/delete/mytest', 'dustin', 'p').repos.delete('mytest') - - def testFork(self): - """Test forking'""" - self._ghp('repos/fork/someuser/somerepo', 'dustin', 'p').repos.fork( - 'someuser', 'somerepo') - - def testAddCollaborator(self): - """Adding a collaborator.""" - self._ghp('repos/collaborators/memcached/add/trondn', - 'dustin', 'p').repos.addCollaborator('memcached', 'trondn') - - def testRemoveCollaborator(self): - """Removing a collaborator.""" - self._ghp('repos/collaborators/memcached/remove/trondn', - 'dustin', 'p').repos.removeCollaborator('memcached', 'trondn') - - def testAddDeployKey(self): - """Add a deploy key.""" - self._ghp('repos/key/blah/add', 'dustin', 'p', - title='title', key='key').repos.addDeployKey('blah', 'title', 'key') - - def testRemoveDeployKey(self): - """Remove a deploy key.""" - self._ghp('repos/key/blah/remove', 'dustin', 'p', - id=5).repos.removeDeployKey('blah', 5) - -class CommitTest(BaseCase): - - def testCommitList(self): - """Test commit list.""" - cl = self._gh('http://github.com/api/v2/xml/commits/list/mojombo/grit/master', - 'data/commits.xml').commits.forBranch('mojombo', 'grit') - self.assertEquals(30, len(cl)) - - c = cl[0] - self.assertEquals("Regenerated gemspec for version 1.1.1", c.message) - self.assertEquals('4ac4acab7fd9c7fd4c0e0f4ff5794b0347baecde', c.id) - self.assertEquals('94490563ebaf733cbb3de4ad659eb58178c2e574', c.tree) - self.assertEquals('2009-03-31T09:54:51-07:00', c.committed_date) - self.assertEquals('2009-03-31T09:54:51-07:00', c.authored_date) - self.assertEquals('http://github.com/mojombo/grit/commit/4ac4acab7fd9c7fd4c0e0f4ff5794b0347baecde', - c.url) - self.assertEquals(1, len(c.parents)) - self.assertEquals('5071bf9fbfb81778c456d62e111440fdc776f76c', c.parents[0].id) - self.assertEquals('Tom Preston-Werner', c.author.name) - self.assertEquals('tom@mojombo.com', c.author.email) - self.assertEquals('Tom Preston-Werner', c.committer.name) - self.assertEquals('tom@mojombo.com', c.committer.email) - - def testCommitListForFile(self): - """Test commit list for a file.""" - cl = self._gh('http://github.com/api/v2/xml/commits/list/mojombo/grit/master/grit.gemspec', - 'data/commits.xml').commits.forFile('mojombo', 'grit', 'grit.gemspec') - self.assertEquals(30, len(cl)) - - c = cl[0] - self.assertEquals("Regenerated gemspec for version 1.1.1", c.message) - self.assertEquals('4ac4acab7fd9c7fd4c0e0f4ff5794b0347baecde', c.id) - self.assertEquals('94490563ebaf733cbb3de4ad659eb58178c2e574', c.tree) - self.assertEquals('2009-03-31T09:54:51-07:00', c.committed_date) - self.assertEquals('2009-03-31T09:54:51-07:00', c.authored_date) - self.assertEquals('http://github.com/mojombo/grit/commit/4ac4acab7fd9c7fd4c0e0f4ff5794b0347baecde', - c.url) - self.assertEquals(1, len(c.parents)) - self.assertEquals('5071bf9fbfb81778c456d62e111440fdc776f76c', c.parents[0].id) - self.assertEquals('Tom Preston-Werner', c.author.name) - self.assertEquals('tom@mojombo.com', c.author.email) - self.assertEquals('Tom Preston-Werner', c.committer.name) - self.assertEquals('tom@mojombo.com', c.committer.email) - - def testIndividualCommit(self): - """Grab a single commit.""" - h = '4c86fa592fcc7cb685c6e9d8b6aebe8dcbac6b3e' - c = self._gh('http://github.com/api/v2/xml/commits/show/dustin/memcached/' + h, - 'data/commit.xml').commits.show('dustin', 'memcached', h) - self.assertEquals(['internal_tests.c'], c.removed) - self.assertEquals(set(['cache.c', 'cache.h', 'testapp.c']), set(c.added)) - self.assertEquals('Create a generic cache for objects of same size\n\n' - 'The suffix pool could be thread-local and use the generic cache', - c.message) - - self.assertEquals(6, len(c.modified)) - self.assertEquals('.gitignore', c.modified[0].filename) - self.assertEquals(140, len(c.modified[0].diff)) - - self.assertEquals(['ee0c3d5ae74d0862b4d9990e2ad13bc79f8c34df'], - [p.id for p in c.parents]) - self.assertEquals('http://github.com/dustin/memcached/commit/' + h, c.url) - self.assertEquals('Trond Norbye', c.author.name) - self.assertEquals('Trond.Norbye@sun.com', c.author.email) - self.assertEquals(h, c.id) - self.assertEquals('2009-04-17T16:15:52-07:00', c.committed_date) - self.assertEquals('2009-03-27T10:30:16-07:00', c.authored_date) - self.assertEquals('94b644163f6381a9930e2d7c583fae023895b903', c.tree) - self.assertEquals('Dustin Sallings', c.committer.name) - self.assertEquals('dustin@spy.net', c.committer.email) - - def testWatchRepo(self): - """Test watching a repo.""" - self._ghp('repos/watch/dustin/py-github', 'dustin', 'p').repos.watch( - 'dustin', 'py-github') - - def testWatchRepo(self): - """Test watching a repo.""" - self._ghp('repos/unwatch/dustin/py-github', 'dustin', 'p').repos.unwatch( - 'dustin', 'py-github') - -class IssueTest(BaseCase): - - def testListIssues(self): - """Test listing issues.""" - il = self._gh('http://github.com/api/v2/xml/issues/list/schacon/simplegit/open', - 'data/issues.list.xml').issues.list('schacon', 'simplegit') - self.assertEquals(1, len(il)) - i = il[0] - - self.assertEquals('schacon', i.user) - self.assertEquals('2009-04-17T16:19:02-07:00', i.updated_at) - self.assertEquals('something', i.body) - self.assertEquals('new', i.title) - self.assertEquals(2, i.number) - self.assertEquals(0, i.votes) - self.assertEquals(1.0, i.position) - self.assertEquals('2009-04-17T16:18:50-07:00', i.created_at) - self.assertEquals('open', i.state) - - def testShowIssue(self): - """Show an individual issue.""" - i = self._gh('http://github.com/api/v2/xml/issues/show/dustin/py-github/1', - 'data/issues.show.xml').issues.show('dustin', 'py-github', 1) - - self.assertEquals('dustin', i.user) - self.assertEquals('2009-04-17T18:37:04-07:00', i.updated_at) - self.assertEquals('http://develop.github.com/p/general.html', i.body) - self.assertEquals('Add auth tokens', i.title) - self.assertEquals(1, i.number) - self.assertEquals(0, i.votes) - self.assertEquals(1.0, i.position) - self.assertEquals('2009-04-17T17:00:58-07:00', i.created_at) - self.assertEquals('closed', i.state) - - def testAddLabel(self): - """Adding a label to an issue.""" - self._ghp('issues/label/add/dustin/py-github/todo/33', 'd', 'pw').issues.add_label( - 'dustin', 'py-github', 33, 'todo') - - def testRemoveLabel(self): - """Removing a label from an issue.""" - self._ghp('issues/label/remove/dustin/py-github/todo/33', - 'd', 'pw').issues.remove_label( - 'dustin', 'py-github', 33, 'todo') - - def testCloseIssue(self): - """Closing an issue.""" - self._ghp('issues/close/dustin/py-github/1', 'd', 'pw').issues.close( - 'dustin', 'py-github', 1) - - def testReopenIssue(self): - """Reopening an issue.""" - self._ghp('issues/reopen/dustin/py-github/1', 'd', 'pw').issues.reopen( - 'dustin', 'py-github', 1) - - def testCreateIssue(self): - """Creating an issue.""" - self._ghp('issues/open/dustin/py-github', 'd', 'pw', - title='test title', body='').issues.new( - 'dustin', 'py-github', title='test title') - - def testEditIssue(self): - """Editing an existing issue.""" - self._ghp('issues/edit/dustin/py-github/1', 'd', 'pw', - title='new title', body='new body').issues.edit( - 'dustin', 'py-github', 1, 'new title', 'new body') - -class ObjectTest(BaseCase): - - def testTree(self): - """Test tree fetching.""" - h = '1ddd3f99f0b96019042239375b3ad4d45796ffba' - tl = self._gh('http://github.com/api/v2/xml/tree/show/dustin/py-github/' + h, - 'data/tree.xml').objects.tree('dustin', 'py-github', h) - self.assertEquals(8, len(tl)) - self.assertEquals('setup.py', tl['setup.py'].name) - self.assertEquals('6e290379ec58fa00ac9d1c2a78f0819a21397445', - tl['setup.py'].sha) - self.assertEquals('100755', tl['setup.py'].mode) - self.assertEquals('blob', tl['setup.py'].type) - - self.assertEquals('src', tl['src'].name) - self.assertEquals('5fb9175803334c82b3fd66f1b69502691b91cf4f', - tl['src'].sha) - self.assertEquals('040000', tl['src'].mode) - self.assertEquals('tree', tl['src'].type) - - def testBlob(self): - """Test blob fetching.""" - h = '1ddd3f99f0b96019042239375b3ad4d45796ffba' - blob = self._gh('http://github.com/api/v2/xml/blob/show/dustin/py-github/' - + h + '/setup.py', - 'data/blob.xml').objects.blob('dustin', 'py-github', h, 'setup.py') - self.assertEquals('setup.py', blob.name) - self.assertEquals(1842, blob.size) - self.assertEquals('6e290379ec58fa00ac9d1c2a78f0819a21397445', blob.sha) - self.assertEquals('100755', blob.mode) - self.assertEquals('text/plain', blob.mime_type) - self.assertEquals(1842, len(blob.data)) - self.assertEquals(1641, blob.data.index('Production/Stable')) - - def testRawBlob(self): - """Test raw blob fetching.""" - h = '6e290379ec58fa00ac9d1c2a78f0819a21397445' - blob = self._gh('http://github.com/api/v2/xml/blob/show/dustin/py-github/' + h, - 'data/setup.py').objects.raw_blob('dustin', 'py-github', h) - self.assertEquals('e2dc8aea9ae8961f4f5923f9febfdd0a', - hashlib.md5(blob).hexdigest()) - - -if __name__ == '__main__': - unittest.main() diff --git a/lib/pynma/__init__.py b/lib/pynma/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f90424eb70e977fa6f417a29fc944a6fba32e65d --- /dev/null +++ b/lib/pynma/__init__.py @@ -0,0 +1,4 @@ +#!/usr/bin/python + +from pynma import PyNMA + diff --git a/lib/pynma/pynma.py b/lib/pynma/pynma.py new file mode 100644 index 0000000000000000000000000000000000000000..fc7d8de2eeb4cf90ec5e6ceae4fb60c6925fd3ac --- /dev/null +++ b/lib/pynma/pynma.py @@ -0,0 +1,137 @@ +#!/usr/bin/python + +from xml.dom.minidom import parseString +from httplib import HTTPSConnection +from urllib import urlencode + +__version__ = "0.1" + +API_SERVER = 'nma.usk.bz' +ADD_PATH = '/publicapi/notify' + +USER_AGENT="PyNMA/v%s"%__version__ + +def uniq_preserve(seq): # Dave Kirby + # Order preserving + seen = set() + return [x for x in seq if x not in seen and not seen.add(x)] + +def uniq(seq): + # Not order preserving + return {}.fromkeys(seq).keys() + +class PyNMA(object): + """PyNMA(apikey=[], developerkey=None) + takes 2 optional arguments: + - (opt) apykey: might me a string containing 1 key or an array of keys + - (opt) developerkey: where you can store your developer key + """ + + def __init__(self, apikey=[], developerkey=None): + self._developerkey = None + self.developerkey(developerkey) + if apikey: + if type(apikey) == str: + apikey = [apikey] + self._apikey = uniq(apikey) + + def addkey(self, key): + "Add a key (register ?)" + if type(key) == str: + if not key in self._apikey: + self._apikey.append(key) + elif type(key) == list: + for k in key: + if not k in self._apikey: + self._apikey.append(k) + + def delkey(self, key): + "Removes a key (unregister ?)" + if type(key) == str: + if key in self._apikey: + self._apikey.remove(key) + elif type(key) == list: + for k in key: + if key in self._apikey: + self._apikey.remove(k) + + def developerkey(self, developerkey): + "Sets the developer key (and check it has the good length)" + if type(developerkey) == str and len(developerkey) == 48: + self._developerkey = developerkey + + def push(self, application="", event="", description="", url="", priority=0, batch_mode=False): + """Pushes a message on the registered API keys. + takes 5 arguments: + - (req) application: application name [256] + - (req) event: event name [1000] + - (req) description: description [10000] + - (opt) url: url [512] + - (opt) priority: from -2 (lowest) to 2 (highest) (def:0) + - (opt) batch_mode: call API 5 by 5 (def:False) + + Warning: using batch_mode will return error only if all API keys are bad + cf: http://nma.usk.bz/api.php + """ + datas = { + 'application': application[:256].encode('utf8'), + 'event': event[:1024].encode('utf8'), + 'description': description[:10000].encode('utf8'), + 'priority': priority + } + + if url: + datas['url'] = url[:512] + + if self._developerkey: + datas['developerkey'] = self._developerkey + + results = {} + + if not batch_mode: + for key in self._apikey: + datas['apikey'] = key + res = self.callapi('POST', ADD_PATH, datas) + results[key] = res + else: + for i in range(0, len(self._apikey), 5): + datas['apikey'] = ",".join(self._apikey[i:i+5]) + res = self.callapi('POST', ADD_PATH, datas) + results[datas['apikey']] = res + return results + + def callapi(self, method, path, args): + headers = { 'User-Agent': USER_AGENT } + if method == "POST": + headers['Content-type'] = "application/x-www-form-urlencoded" + http_handler = HTTPSConnection(API_SERVER) + http_handler.request(method, path, urlencode(args), headers) + resp = http_handler.getresponse() + + try: + res = self._parse_reponse(resp.read()) + except Exception, e: + res = {'type': "pynmaerror", + 'code': 600, + 'message': str(e) + } + pass + + return res + + def _parse_reponse(self, response): + root = parseString(response).firstChild + for elem in root.childNodes: + if elem.nodeType == elem.TEXT_NODE: continue + if elem.tagName == 'success': + res = dict(elem.attributes.items()) + res['message'] = "" + res['type'] = elem.tagName + return res + if elem.tagName == 'error': + res = dict(elem.attributes.items()) + res['message'] = elem.firstChild.nodeValue + res['type'] = elem.tagName + return res + + diff --git a/lib/pythontwitter/__init__.py b/lib/pythontwitter/__init__.py index badc70c310cd7b114651d853cd1af9eb81b62eba..a2f3c7be6bb383683be465f496880f7f92bdc670 100755 --- a/lib/pythontwitter/__init__.py +++ b/lib/pythontwitter/__init__.py @@ -3108,7 +3108,7 @@ class _FileCache(object): os.getenv('USERNAME') or \ os.getlogin() or \ 'nobody' - except (IOError, OSError), e: + except (AttributeError, IOError, OSError), e: return 'nobody' def _GetTmpCachePath(self): diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py index fa3ece36d08cd5cd03743369afd4f6a2af438632..d6bfddadc65fbba67b11e4dfb55e83523059641c 100644 --- a/lib/tvdb_api/tvdb_api.py +++ b/lib/tvdb_api/tvdb_api.py @@ -537,11 +537,11 @@ class Tvdb: """ src = self._loadUrl(url) try: - return ElementTree.fromstring(src) + return ElementTree.fromstring(src.rstrip('\r')) except SyntaxError: src = self._loadUrl(url, recache=True) try: - return ElementTree.fromstring(src) + return ElementTree.fromstring(src.rstrip('\r')) except SyntaxError, exceptionmsg: errormsg = "There was an error with the XML retrieved from thetvdb.com:\n%s" % ( exceptionmsg diff --git a/readme.md b/readme.md index 5d7b62f21251714acb8cc7c88f3baa1b3fc3230f..0fae42e6e0317e48f19e989d6f6627f7b62c54f0 100644 --- a/readme.md +++ b/readme.md @@ -29,6 +29,7 @@ Sick Beard makes use of the following projects: * [jQuery][jquery] * [Python GNTP][pythongntp] * [SocksiPy][socks] +* [python-dateutil][dateutil] ## Dependencies @@ -47,6 +48,7 @@ If you find a bug please report it or it'll never get fixed. Verify that it hasn [jquery]: http://jquery.com [pythongntp]: http://github.com/kfdm/gntp [socks]: http://code.google.com/p/socksipy-branch/ +[dateutil]: http://labix.org/python-dateutil [googledownloads]: http://code.google.com/p/sickbeard/downloads/list [googleissues]: http://code.google.com/p/sickbeard/issues/list [googlenewissue]: http://code.google.com/p/sickbeard/issues/entry \ No newline at end of file diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index f45986f0552324007ff9b4b37ad7a42d16426c08..1984ac00f93bea96cf9e89234fac1dbaf7b4604b 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -30,7 +30,7 @@ from threading import Lock # apparently py2exe won't build these unless they're imported somewhere from sickbeard import providers, metadata -from providers import ezrss, tvtorrents, nzbs_org, nzbmatrix, nzbsrus, newznab, womble, newzbin +from providers import ezrss, tvtorrents, btn, nzbmatrix, nzbsrus, newznab, womble, newzbin, nzbs_org_old from sickbeard import searchCurrent, searchBacklog, showUpdater, versionChecker, properFinder, autoPostProcesser from sickbeard import helpers, db, exceptions, show_queue, search_queue, scheduler @@ -96,6 +96,13 @@ WEB_PASSWORD = None WEB_HOST = None WEB_IPV6 = None +USE_API = False +API_KEY = None + +ENABLE_HTTPS = False +HTTPS_CERT = None +HTTPS_KEY = None + LAUNCH_BROWSER = None CACHE_DIR = None ACTUAL_CACHE_DIR = None @@ -108,6 +115,7 @@ METADATA_MEDIABROWSER = None METADATA_PS3 = None METADATA_WDTV = None METADATA_TIVO = None +METADATA_SYNOLOGY = None QUALITY_DEFAULT = None STATUS_DEFAULT = None @@ -148,6 +156,11 @@ TVTORRENTS = False TVTORRENTS_DIGEST = None TVTORRENTS_HASH = None +BTN = False +BTN_USER_ID = None +BTN_AUTH_TOKEN = None +BTN_PASSKEY = None +BTN_AUTHKEY = None TORRENT_DIR = None @@ -194,10 +207,10 @@ XBMC_HOST = '' XBMC_USERNAME = None XBMC_PASSWORD = None -USE_PLEX = False +USE_PLEX = False PLEX_NOTIFY_ONSNATCH = False PLEX_NOTIFY_ONDOWNLOAD = False -PLEX_UPDATE_LIBRARY = False +PLEX_UPDATE_LIBRARY = False PLEX_SERVER_HOST = None PLEX_HOST = None PLEX_USERNAME = None @@ -229,6 +242,18 @@ NOTIFO_USERNAME = None NOTIFO_APISECRET = None NOTIFO_PREFIX = None +USE_BOXCAR = False +BOXCAR_NOTIFY_ONSNATCH = False +BOXCAR_NOTIFY_ONDOWNLOAD = False +BOXCAR_USERNAME = None +BOXCAR_PASSWORD = None +BOXCAR_PREFIX = None + +USE_PUSHOVER = False +PUSHOVER_NOTIFY_ONSNATCH = False +PUSHOVER_NOTIFY_ONDOWNLOAD = False +PUSHOVER_USERKEY = None + USE_LIBNOTIFY = False LIBNOTIFY_NOTIFY_ONSNATCH = False LIBNOTIFY_NOTIFY_ONDOWNLOAD = False @@ -240,6 +265,25 @@ NMJ_MOUNT = None USE_SYNOINDEX = False +USE_TRAKT = False +TRAKT_USERNAME = None +TRAKT_PASSWORD = None +TRAKT_API = '' + +USE_PYTIVO = False +PYTIVO_NOTIFY_ONSNATCH = False +PYTIVO_NOTIFY_ONDOWNLOAD = False +PYTIVO_UPDATE_LIBRARY = False +PYTIVO_HOST = '' +PYTIVO_SHARE_NAME = '' +PYTIVO_TIVO_NAME = '' + +USE_NMA = False +NMA_NOTIFY_ONSNATCH = False +NMA_NOTIFY_ONDOWNLOAD = False +NMA_API = None +NMA_PRIORITY = 0 + COMING_EPS_LAYOUT = None COMING_EPS_DISPLAY_PAUSED = None COMING_EPS_SORT = None @@ -339,20 +383,23 @@ def initialize(consoleLogging=True): with INIT_LOCK: - global LOG_DIR, WEB_PORT, WEB_LOG, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, \ + global LOG_DIR, WEB_PORT, WEB_LOG, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, USE_API, API_KEY, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, \ USE_NZBS, USE_TORRENTS, NZB_METHOD, NZB_DIR, DOWNLOAD_PROPERS, \ SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, SAB_HOST, \ NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_HOST, currentSearchScheduler, backlogSearchScheduler, \ USE_XBMC, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_UPDATE_FULL, \ - XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, \ + XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, \ + USE_TRAKT, TRAKT_USERNAME, TRAKT_PASSWORD, TRAKT_API, \ USE_PLEX, PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_UPDATE_LIBRARY, \ PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, \ showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, showList, loadingShowList, \ - NZBS, NZBS_UID, NZBS_HASH, EZRSS, TVTORRENTS, TVTORRENTS_DIGEST, TVTORRENTS_HASH, TORRENT_DIR, USENET_RETENTION, SOCKET_TIMEOUT, \ + NZBS, NZBS_UID, NZBS_HASH, EZRSS, TVTORRENTS, TVTORRENTS_DIGEST, TVTORRENTS_HASH, BTN, BTN_USER_ID, BTN_AUTH_TOKEN, BTN_PASSKEY, BTN_AUTHKEY, TORRENT_DIR, USENET_RETENTION, SOCKET_TIMEOUT, \ SEARCH_FREQUENCY, DEFAULT_SEARCH_FREQUENCY, BACKLOG_SEARCH_FREQUENCY, \ QUALITY_DEFAULT, SEASON_FOLDERS_FORMAT, SEASON_FOLDERS_DEFAULT, STATUS_DEFAULT, \ GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, TWITTER_NOTIFY_ONSNATCH, TWITTER_NOTIFY_ONDOWNLOAD, \ USE_GROWL, GROWL_HOST, GROWL_PASSWORD, USE_PROWL, PROWL_NOTIFY_ONSNATCH, PROWL_NOTIFY_ONDOWNLOAD, PROWL_API, PROWL_PRIORITY, PROG_DIR, NZBMATRIX, NZBMATRIX_USERNAME, \ + USE_PYTIVO, PYTIVO_NOTIFY_ONSNATCH, PYTIVO_NOTIFY_ONDOWNLOAD, PYTIVO_UPDATE_LIBRARY, PYTIVO_HOST, PYTIVO_SHARE_NAME, PYTIVO_TIVO_NAME, \ + USE_NMA, NMA_NOTIFY_ONSNATCH, NMA_NOTIFY_ONDOWNLOAD, NMA_API, NMA_PRIORITY, \ NZBMATRIX_APIKEY, versionCheckScheduler, VERSION_NOTIFY, PROCESS_AUTOMATICALLY, \ KEEP_PROCESSED_DIR, TV_DOWNLOAD_DIR, TVDB_BASE_URL, MIN_SEARCH_FREQUENCY, \ showQueueScheduler, searchQueueScheduler, ROOT_DIRS, \ @@ -362,8 +409,10 @@ def initialize(consoleLogging=True): NZBSRUS, NZBSRUS_UID, NZBSRUS_HASH, NAMING_QUALITY, providerList, newznabProviderList, \ NAMING_DATES, EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \ USE_NOTIFO, NOTIFO_USERNAME, NOTIFO_APISECRET, NOTIFO_NOTIFY_ONDOWNLOAD, NOTIFO_NOTIFY_ONSNATCH, \ + USE_BOXCAR, BOXCAR_USERNAME, BOXCAR_PASSWORD, BOXCAR_NOTIFY_ONDOWNLOAD, BOXCAR_NOTIFY_ONSNATCH, \ + USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, \ USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, USE_SYNOINDEX, \ - USE_BANNER, USE_LISTVIEW, METADATA_XBMC, METADATA_MEDIABROWSER, METADATA_PS3, metadata_provider_dict, \ + USE_BANNER, USE_LISTVIEW, METADATA_XBMC, METADATA_MEDIABROWSER, METADATA_PS3, METADATA_SYNOLOGY, metadata_provider_dict, \ NEWZBIN, NEWZBIN_USERNAME, NEWZBIN_PASSWORD, GIT_PATH, MOVE_ASSOCIATED_FILES, \ COMING_EPS_LAYOUT, COMING_EPS_SORT, COMING_EPS_DISPLAY_PAUSED, METADATA_WDTV, METADATA_TIVO, IGNORE_WORDS @@ -378,12 +427,14 @@ def initialize(consoleLogging=True): CheckSection('SABnzbd') CheckSection('NZBget') CheckSection('XBMC') - CheckSection('PLEX') + CheckSection('PLEX') CheckSection('Growl') CheckSection('Prowl') CheckSection('Twitter') CheckSection('NMJ') CheckSection('Synology') + CheckSection('pyTivo') + CheckSection('NMA') LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', 'Logs') if not helpers.makeDir(LOG_DIR): @@ -405,6 +456,14 @@ def initialize(consoleLogging=True): WEB_PASSWORD = check_setting_str(CFG, 'General', 'web_password', '') LAUNCH_BROWSER = bool(check_setting_int(CFG, 'General', 'launch_browser', 1)) + USE_API = bool(check_setting_int(CFG, 'General', 'use_api', 0)) + API_KEY = check_setting_str(CFG, 'General', 'api_key', '') + + ENABLE_HTTPS = bool(check_setting_int(CFG, 'General', 'enable_https', 0)) + + HTTPS_CERT = check_setting_str(CFG, 'General', 'https_cert', 'server.crt') + HTTPS_KEY = check_setting_str(CFG, 'General', 'https_key', 'server.key') + ACTUAL_CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', 'cache') # fix bad configs due to buggy code if ACTUAL_CACHE_DIR == 'None': @@ -492,10 +551,16 @@ def initialize(consoleLogging=True): TVTORRENTS_DIGEST = check_setting_str(CFG, 'TVTORRENTS', 'tvtorrents_digest', '') TVTORRENTS_HASH = check_setting_str(CFG, 'TVTORRENTS', 'tvtorrents_hash', '') + BTN = bool(check_setting_int(CFG, 'BTN', 'btn', 0)) + BTN_USER_ID = check_setting_str(CFG, 'BTN', 'btn_user_id', '') + BTN_AUTH_TOKEN = check_setting_str(CFG, 'BTN', 'btn_auth_token', '') + BTN_AUTHKEY = check_setting_str(CFG, 'BTN', 'btn_authkey', '') + BTN_PASSKEY = check_setting_str(CFG, 'BTN', 'btn_passkey', '') + NZBS = bool(check_setting_int(CFG, 'NZBs', 'nzbs', 0)) NZBS_UID = check_setting_str(CFG, 'NZBs', 'nzbs_uid', '') NZBS_HASH = check_setting_str(CFG, 'NZBs', 'nzbs_hash', '') - + NZBSRUS = bool(check_setting_int(CFG, 'NZBsRUS', 'nzbsrus', 0)) NZBSRUS_UID = check_setting_str(CFG, 'NZBsRUS', 'nzbsrus_uid', '') NZBSRUS_HASH = check_setting_str(CFG, 'NZBsRUS', 'nzbsrus_hash', '') @@ -529,10 +594,10 @@ def initialize(consoleLogging=True): XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '') XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '') - USE_PLEX = bool(check_setting_int(CFG, 'Plex', 'use_plex', 0)) + USE_PLEX = bool(check_setting_int(CFG, 'Plex', 'use_plex', 0)) PLEX_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Plex', 'plex_notify_onsnatch', 0)) PLEX_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Plex', 'plex_notify_ondownload', 0)) - PLEX_UPDATE_LIBRARY = bool(check_setting_int(CFG, 'Plex', 'plex_update_library', 0)) + PLEX_UPDATE_LIBRARY = bool(check_setting_int(CFG, 'Plex', 'plex_update_library', 0)) PLEX_SERVER_HOST = check_setting_str(CFG, 'Plex', 'plex_server_host', '') PLEX_HOST = check_setting_str(CFG, 'Plex', 'plex_host', '') PLEX_USERNAME = check_setting_str(CFG, 'Plex', 'plex_username', '') @@ -563,6 +628,16 @@ def initialize(consoleLogging=True): NOTIFO_USERNAME = check_setting_str(CFG, 'Notifo', 'notifo_username', '') NOTIFO_APISECRET = check_setting_str(CFG, 'Notifo', 'notifo_apisecret', '') + USE_BOXCAR = bool(check_setting_int(CFG, 'Boxcar', 'use_boxcar', 0)) + BOXCAR_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Boxcar', 'boxcar_notify_onsnatch', 0)) + BOXCAR_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Boxcar', 'boxcar_notify_ondownload', 0)) + BOXCAR_USERNAME = check_setting_str(CFG, 'Boxcar', 'boxcar_username', '') + + USE_PUSHOVER = bool(check_setting_int(CFG, 'Pushover', 'use_pushover', 0)) + PUSHOVER_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Pushover', 'pushover_notify_onsnatch', 0)) + PUSHOVER_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Pushover', 'pushover_notify_ondownload', 0)) + PUSHOVER_USERKEY = check_setting_str(CFG, 'Pushover', 'pushover_userkey', '') + USE_LIBNOTIFY = bool(check_setting_int(CFG, 'Libnotify', 'use_libnotify', 0)) LIBNOTIFY_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Libnotify', 'libnotify_notify_onsnatch', 0)) LIBNOTIFY_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Libnotify', 'libnotify_notify_ondownload', 0)) @@ -574,6 +649,25 @@ def initialize(consoleLogging=True): USE_SYNOINDEX = bool(check_setting_int(CFG, 'Synology', 'use_synoindex', 0)) + USE_TRAKT = bool(check_setting_int(CFG, 'Trakt', 'use_trakt', 0)) + TRAKT_USERNAME = check_setting_str(CFG, 'Trakt', 'trakt_username', '') + TRAKT_PASSWORD = check_setting_str(CFG, 'Trakt', 'trakt_password', '') + TRAKT_API = check_setting_str(CFG, 'Trakt', 'trakt_api', '') + + USE_PYTIVO = bool(check_setting_int(CFG, 'pyTivo', 'use_pytivo', 0)) + PYTIVO_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'pyTivo', 'pytivo_notify_onsnatch', 0)) + PYTIVO_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'pyTivo', 'pytivo_notify_ondownload', 0)) + PYTIVO_UPDATE_LIBRARY = bool(check_setting_int(CFG, 'pyTivo', 'pyTivo_update_library', 0)) + PYTIVO_HOST = check_setting_str(CFG, 'pyTivo', 'pytivo_host', '') + PYTIVO_SHARE_NAME = check_setting_str(CFG, 'pyTivo', 'pytivo_share_name', '') + PYTIVO_TIVO_NAME = check_setting_str(CFG, 'pyTivo', 'pytivo_tivo_name', '') + + USE_NMA = bool(check_setting_int(CFG, 'NMA', 'use_nma', 0)) + NMA_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'NMA', 'nma_notify_onsnatch', 0)) + NMA_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'NMA', 'nma_notify_ondownload', 0)) + NMA_API = check_setting_str(CFG, 'NMA', 'nma_api', '') + NMA_PRIORITY = check_setting_str(CFG, 'NMA', 'nma_priority', "0") + GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '') IGNORE_WORDS = check_setting_str(CFG, 'General', 'ignore_words', IGNORE_WORDS) @@ -624,12 +718,14 @@ def initialize(consoleLogging=True): METADATA_PS3 = check_setting_str(CFG, 'General', 'metadata_ps3', '0|0|0|0|0|0') METADATA_WDTV = check_setting_str(CFG, 'General', 'metadata_wdtv', '0|0|0|0|0|0') METADATA_TIVO = check_setting_str(CFG, 'General', 'metadata_tivo', '0|0|0|0|0|0') - + METADATA_SYNOLOGY = check_setting_str(CFG, 'General', 'metadata_synology', '0|0|0|0|0|0') + for cur_metadata_tuple in [(METADATA_XBMC, metadata.xbmc), (METADATA_MEDIABROWSER, metadata.mediabrowser), (METADATA_PS3, metadata.ps3), (METADATA_WDTV, metadata.wdtv), (METADATA_TIVO, metadata.tivo), + (METADATA_SYNOLOGY, metadata.synology), ]: (cur_metadata_config, cur_metadata_class) = cur_metadata_tuple @@ -915,11 +1011,16 @@ def save_config(): new_config['General']['log_dir'] = LOG_DIR new_config['General']['web_port'] = WEB_PORT new_config['General']['web_host'] = WEB_HOST - new_config['General']['web_ipv6'] = WEB_IPV6 + new_config['General']['web_ipv6'] = int(WEB_IPV6) new_config['General']['web_log'] = int(WEB_LOG) new_config['General']['web_root'] = WEB_ROOT new_config['General']['web_username'] = WEB_USERNAME new_config['General']['web_password'] = WEB_PASSWORD + new_config['General']['use_api'] = int(USE_API) + new_config['General']['api_key'] = API_KEY + new_config['General']['enable_https'] = int(ENABLE_HTTPS) + new_config['General']['https_cert'] = HTTPS_CERT + new_config['General']['https_key'] = HTTPS_KEY new_config['General']['use_nzbs'] = int(USE_NZBS) new_config['General']['use_torrents'] = int(USE_TORRENTS) new_config['General']['nzb_method'] = NZB_METHOD @@ -949,6 +1050,7 @@ def save_config(): new_config['General']['metadata_ps3'] = metadata_provider_dict['Sony PS3'].get_config() new_config['General']['metadata_wdtv'] = metadata_provider_dict['WDTV'].get_config() new_config['General']['metadata_tivo'] = metadata_provider_dict['TIVO'].get_config() + new_config['General']['metadata_synology'] = metadata_provider_dict['Synology'].get_config() new_config['General']['cache_dir'] = ACTUAL_CACHE_DIR if ACTUAL_CACHE_DIR else 'cache' new_config['General']['root_dirs'] = ROOT_DIRS if ROOT_DIRS else '' @@ -974,6 +1076,13 @@ def save_config(): new_config['TVTORRENTS']['tvtorrents_digest'] = TVTORRENTS_DIGEST new_config['TVTORRENTS']['tvtorrents_hash'] = TVTORRENTS_HASH + new_config['BTN'] = {} + new_config['BTN']['btn'] = int(BTN) + new_config['BTN']['btn_user_id'] = BTN_USER_ID + new_config['BTN']['btn_auth_token'] = BTN_AUTH_TOKEN + new_config['BTN']['btn_authkey'] = BTN_AUTHKEY + new_config['BTN']['btn_passkey'] = BTN_PASSKEY + new_config['NZBs'] = {} new_config['NZBs']['nzbs'] = int(NZBS) new_config['NZBs']['nzbs_uid'] = NZBS_UID @@ -1018,12 +1127,12 @@ def save_config(): new_config['XBMC']['xbmc_host'] = XBMC_HOST new_config['XBMC']['xbmc_username'] = XBMC_USERNAME new_config['XBMC']['xbmc_password'] = XBMC_PASSWORD - - new_config['Plex'] = {} - new_config['Plex']['use_plex'] = int(USE_PLEX) + + new_config['Plex'] = {} + new_config['Plex']['use_plex'] = int(USE_PLEX) new_config['Plex']['plex_notify_onsnatch'] = int(PLEX_NOTIFY_ONSNATCH) new_config['Plex']['plex_notify_ondownload'] = int(PLEX_NOTIFY_ONDOWNLOAD) - new_config['Plex']['plex_update_library'] = int(PLEX_UPDATE_LIBRARY) + new_config['Plex']['plex_update_library'] = int(PLEX_UPDATE_LIBRARY) new_config['Plex']['plex_server_host'] = PLEX_SERVER_HOST new_config['Plex']['plex_host'] = PLEX_HOST new_config['Plex']['plex_username'] = PLEX_USERNAME @@ -1058,6 +1167,18 @@ def save_config(): new_config['Notifo']['notifo_username'] = NOTIFO_USERNAME new_config['Notifo']['notifo_apisecret'] = NOTIFO_APISECRET + new_config['Boxcar'] = {} + new_config['Boxcar']['use_boxcar'] = int(USE_BOXCAR) + new_config['Boxcar']['boxcar_notify_onsnatch'] = int(BOXCAR_NOTIFY_ONSNATCH) + new_config['Boxcar']['boxcar_notify_ondownload'] = int(BOXCAR_NOTIFY_ONDOWNLOAD) + new_config['Boxcar']['boxcar_username'] = BOXCAR_USERNAME + + new_config['Pushover'] = {} + new_config['Pushover']['use_pushover'] = int(USE_PUSHOVER) + new_config['Pushover']['pushover_notify_onsnatch'] = int(PUSHOVER_NOTIFY_ONSNATCH) + new_config['Pushover']['pushover_notify_ondownload'] = int(PUSHOVER_NOTIFY_ONDOWNLOAD) + new_config['Pushover']['pushover_userkey'] = PUSHOVER_USERKEY + new_config['Libnotify'] = {} new_config['Libnotify']['use_libnotify'] = int(USE_LIBNOTIFY) new_config['Libnotify']['libnotify_notify_onsnatch'] = int(LIBNOTIFY_NOTIFY_ONSNATCH) @@ -1072,6 +1193,28 @@ def save_config(): new_config['Synology'] = {} new_config['Synology']['use_synoindex'] = int(USE_SYNOINDEX) + new_config['Trakt'] = {} + new_config['Trakt']['use_trakt'] = int(USE_TRAKT) + new_config['Trakt']['trakt_username'] = TRAKT_USERNAME + new_config['Trakt']['trakt_password'] = TRAKT_PASSWORD + new_config['Trakt']['trakt_api'] = TRAKT_API + + new_config['pyTivo'] = {} + new_config['pyTivo']['use_pytivo'] = int(USE_PYTIVO) + new_config['pyTivo']['pytivo_notify_onsnatch'] = int(PYTIVO_NOTIFY_ONSNATCH) + new_config['pyTivo']['pytivo_notify_ondownload'] = int(PYTIVO_NOTIFY_ONDOWNLOAD) + new_config['pyTivo']['pyTivo_update_library'] = int(PYTIVO_UPDATE_LIBRARY) + new_config['pyTivo']['pytivo_host'] = PYTIVO_HOST + new_config['pyTivo']['pytivo_share_name'] = PYTIVO_SHARE_NAME + new_config['pyTivo']['pytivo_tivo_name'] = PYTIVO_TIVO_NAME + + new_config['NMA'] = {} + new_config['NMA']['use_nma'] = int(USE_NMA) + new_config['NMA']['nma_notify_onsnatch'] = int(NMA_NOTIFY_ONSNATCH) + new_config['NMA']['nma_notify_ondownload'] = int(NMA_NOTIFY_ONDOWNLOAD) + new_config['NMA']['nma_api'] = NMA_API + new_config['NMA']['nma_priority'] = NMA_PRIORITY + new_config['Newznab'] = {} new_config['Newznab']['newznab_data'] = '!!!'.join([x.configStr() for x in newznabProviderList]) @@ -1086,7 +1229,10 @@ def save_config(): def launchBrowser(startPort=None): if not startPort: startPort = WEB_PORT - browserURL = 'http://localhost:%d%s' % (startPort, WEB_ROOT) + if ENABLE_HTTPS: + browserURL = 'https://localhost:%d%s' % (startPort, WEB_ROOT) + else: + browserURL = 'http://localhost:%d%s' % (startPort, WEB_ROOT) try: webbrowser.open(browserURL, 2, 1) except: diff --git a/sickbeard/browser.py b/sickbeard/browser.py index efbb3c0697a904ea136b588272191d0ba74deb74..a2dbbaea48ee0e95d46a92ff5f892aec95598c81 100644 --- a/sickbeard/browser.py +++ b/sickbeard/browser.py @@ -52,7 +52,6 @@ def foldersAtPath(path, includeParent = False): Give the empty string as the path to list the contents of the root path under Unix this means "/", on Windows this will be a list of drive letters) """ - assert os.path.isabs(path) or path == "" # walk up the tree until we find a valid path while path and not os.path.isdir(path): diff --git a/sickbeard/common.py b/sickbeard/common.py index f6d69abb733a1fb8e4674188f277dc46e0c2f08d..4cab684f7b334c50ef6a75fe913d5666bf539aa9 100644 --- a/sickbeard/common.py +++ b/sickbeard/common.py @@ -28,7 +28,7 @@ mediaExtensions = ['avi', 'mkv', 'mpg', 'mpeg', 'wmv', 'ogm', 'mp4', 'iso', 'img', 'divx', 'm2ts', 'm4v', 'ts', 'flv', 'f4v', 'mov', 'rmvb', 'vob', 'dvr-ms', 'wtv', - ] + 'ogv'] ### Other constants MULTI_EP_RESULT = -1 @@ -124,9 +124,9 @@ class Quality: checkName = lambda list, func: func([re.search(x, name, re.I) for x in list]) - if checkName(["pdtv.xvid", "hdtv.xvid", "dsr.xvid"], any) and not checkName(["720p"], all): + if checkName(["(pdtv|hdtv|dsr).(xvid|x264)"], all) and not checkName(["(720|1080)[pi]"], all): return Quality.SDTV - elif checkName(["dvdrip.xvid", "bdrip.xvid", "dvdrip.divx", "dvdrip.ws.xvid"], any) and not checkName(["720p"], all): + elif checkName(["(dvdrip|bdrip)(.ws)?.(xvid|divx|x264)"], any) and not checkName(["(720|1080)[pi]"], all): return Quality.SDDVD elif checkName(["720p", "hdtv", "x264"], all) or checkName(["hr.ws.pdtv.x264"], any): return Quality.HDTV diff --git a/sickbeard/config.py b/sickbeard/config.py index e7683b5861c7b10c2f6af8001b05d9f288a77add..118e5a2fc99a7fb186da500efec220c8a860b23b 100644 --- a/sickbeard/config.py +++ b/sickbeard/config.py @@ -41,6 +41,36 @@ naming_multi_ep_type_text = ("extend", "duplicate", "repeat") naming_sep_type = (" - ", " ") naming_sep_type_text = (" - ", "space") +def change_HTTPS_CERT(https_cert): + + if https_cert == '': + sickbeard.HTTPS_CERT = '' + return True + + if os.path.normpath(sickbeard.HTTPS_CERT) != os.path.normpath(https_cert): + if helpers.makeDir(os.path.dirname(os.path.abspath(https_cert))): + sickbeard.HTTPS_CERT = os.path.normpath(https_cert) + logger.log(u"Changed https cert path to " + https_cert) + else: + return False + + return True + +def change_HTTPS_KEY(https_key): + + if https_key == '': + sickbeard.HTTPS_KEY = '' + return True + + if os.path.normpath(sickbeard.HTTPS_KEY) != os.path.normpath(https_key): + if helpers.makeDir(os.path.dirname(os.path.abspath(https_key))): + sickbeard.HTTPS_KEY = os.path.normpath(https_key) + logger.log(u"Changed https key path to " + https_key) + else: + return False + + return True + def change_LOG_DIR(log_dir): if os.path.normpath(sickbeard.LOG_DIR) != os.path.normpath(log_dir): diff --git a/sickbeard/db.py b/sickbeard/db.py index 5e63b28a2f980bcf45ef474cd85891d7580e7262..2d00745b045ee88796905c5cc53b59c0cb886cef 100644 --- a/sickbeard/db.py +++ b/sickbeard/db.py @@ -45,11 +45,14 @@ def dbFilename(filename="sickbeard.db", suffix=None): return ek.ek(os.path.join, sickbeard.DATA_DIR, filename) class DBConnection: - def __init__(self, filename="sickbeard.db", suffix=None): + def __init__(self, filename="sickbeard.db", suffix=None, row_type=None): self.filename = filename self.connection = sqlite3.connect(dbFilename(filename), 20) - self.connection.row_factory = sqlite3.Row + if row_type == "dict": + self.connection.row_factory = self._dict_factory + else: + self.connection.row_factory = sqlite3.Row def action(self, query, args=None): @@ -118,7 +121,14 @@ class DBConnection: for column in cursor: columns[column['name']] = { 'type': column['type'] } return columns - + + # http://stackoverflow.com/questions/3300464/how-can-i-get-dict-from-sqlite-query + def _dict_factory(self, cursor, row): + d = {} + for idx, col in enumerate(cursor.description): + d[col[0]] = row[idx] + return d + def sanityCheckDatabase(connection, sanity_check): sanity_check(connection).check() diff --git a/sickbeard/gh_api.py b/sickbeard/gh_api.py new file mode 100644 index 0000000000000000000000000000000000000000..32bb9cec8608a348db94403904afe2842c381529 --- /dev/null +++ b/sickbeard/gh_api.py @@ -0,0 +1,59 @@ +# Author: Nic Wolfe <nic@wolfeden.ca> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +try: + import json +except ImportError: + from lib import simplejson as json + +import urllib + +class GitHub(object): + """ + Simple api wrapper for the Github API v3. Currently only supports the small thing that SB + needs it for - list of cimmots. + """ + + def _access_API(self, path, params=None): + """ + Access the API at the path given and with the optional params given. + + path: A list of the path elements to use (eg. ['repos', 'midgetspy', 'Sick-Beard', 'commits']) + params: Optional dict of name/value pairs for extra params to send. (eg. {'per_page': 10}) + + Returns a deserialized json object of the result. Doesn't do any error checking (hope it works). + """ + + url = 'https://api.github.com/' + '/'.join(path) + + if params and type(params) is dict: + url += '?' + '&'.join([str(x) + '=' + str(params[x]) for x in params.keys()]) + + return json.load(urllib.urlopen(url)) + + def commits(self, user, repo, branch='master'): + """ + Uses the API to get a list of the 100 most recent commits from the specified user/repo/branch, starting from HEAD. + + user: The github username of the person whose repo you're querying + repo: The repo name to query + branch: Optional, the branch name to show commits from + + Returns a deserialized json object containing the commit info. See http://developer.github.com/v3/repos/commits/ + """ + return self._access_API(['repos', user, repo, 'commits'], {'per_page': 100, 'branch': branch}) diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py index 959f0815181afb0d42fa505bb7e804a4cb1c014e..67d9324db0b182ac5a2ad3a65de292d6d8638b23 100644 --- a/sickbeard/helpers.py +++ b/sickbeard/helpers.py @@ -23,6 +23,9 @@ import stat import urllib, urllib2 import re, socket import shutil +import traceback + +from xml.dom.minidom import Node import sickbeard @@ -103,11 +106,17 @@ def sanitizeFileName (name): 'abc' >>> sanitizeFileName('a"b') 'ab' + >>> sanitizeFileName('.a.b..') + 'a.b' ''' - for x in "\\/*": - name = name.replace(x, "-") - for x in ":\"<>|?": - name = name.replace(x, "") + + # remove bad chars from the filename + name = re.sub(r'[\\/\*]', '-', name) + name = re.sub(r'[:"<>|?]', '', name) + + # remove leading/trailing periods + name = re.sub(r'(^\.+|\.+$)', '', name) + return name @@ -140,6 +149,12 @@ def getURL (url, headers=[]): except socket.timeout: logger.log(u"Timed out while loading URL "+url, logger.WARNING) return None + except ValueError: + logger.log(u"Unknown error while loading URL "+url, logger.WARNING) + return None + except Exception: + logger.log(u"Unknown exception while loading URL "+url+": "+traceback.format_exc(), logger.WARNING) + return None return result @@ -428,12 +443,23 @@ def chmodAsParent(childPath): return parentMode = stat.S_IMODE(os.stat(parentPath)[stat.ST_MODE]) + childPath_mode = stat.S_IMODE(os.stat(childPath)[stat.ST_MODE]) if ek.ek(os.path.isfile, childPath): childMode = fileBitFilter(parentMode) else: childMode = parentMode + if childPath_mode == childMode: + return + + childPath_owner = os.stat(childPath).st_uid + user_id = os.geteuid() + + if user_id !=0 and user_id != childPath_owner: + logger.log(u"Not running as root or owner of "+childPath+", not trying to set permissions", logger.DEBUG) + return + try: ek.ek(os.chmod, childPath, childMode) logger.log(u"Setting permissions for %s to %o as parent directory has %o" % (childPath, childMode, parentMode), logger.DEBUG) @@ -462,6 +488,13 @@ def fixSetGroupID(childPath): if childGID == parentGID: return + childPath_owner = os.stat(childPath).st_uid + user_id = os.geteuid() + + if user_id !=0 and user_id != childPath_owner: + logger.log(u"Not running as root or owner of "+childPath+", not trying to set the set-group-ID", logger.DEBUG) + return + try: ek.ek(os.chown, childPath, -1, parentGID) #@UndefinedVariable - only available on UNIX logger.log(u"Respecting the set-group-ID bit on the parent directory for %s" % (childPath), logger.DEBUG) @@ -496,7 +529,44 @@ def sanitizeSceneName (name, ezrss=False): return name +def create_https_certificates(ssl_cert, ssl_key): + """ + Create self-signed HTTPS certificares and store in paths 'ssl_cert' and 'ssl_key' + """ + try: + from OpenSSL import crypto #@UnresolvedImport + from lib.certgen import createKeyPair, createCertRequest, createCertificate, TYPE_RSA, serial #@UnresolvedImport + except: + logger.log(u"pyopenssl module missing, please install for https access", logger.WARNING) + return False + + # Create the CA Certificate + cakey = createKeyPair(TYPE_RSA, 1024) + careq = createCertRequest(cakey, CN='Certificate Authority') + cacert = createCertificate(careq, (careq, cakey), serial, (0, 60*60*24*365*10)) # ten years + + cname = 'SickBeard' + pkey = createKeyPair(TYPE_RSA, 1024) + req = createCertRequest(pkey, CN=cname) + cert = createCertificate(req, (cacert, cakey), serial, (0, 60*60*24*365*10)) # ten years + + # Save the key and certificate to disk + try: + open(ssl_key, 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) + open(ssl_cert, 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) + except: + logger.log(u"Error creating SSL key and certificate", logger.ERROR) + return False + + return True if __name__ == '__main__': import doctest doctest.testmod() + +def get_xml_text(node): + text = "" + for child_node in node.childNodes: + if child_node.nodeType in (Node.CDATA_SECTION_NODE, Node.TEXT_NODE): + text += child_node.data + return text.strip() diff --git a/sickbeard/metadata/__init__.py b/sickbeard/metadata/__init__.py index e80ff53424fc045b324a71f771c031dd4675ec72..db6601589d28817ff5191acc31c2c3baee77935d 100644 --- a/sickbeard/metadata/__init__.py +++ b/sickbeard/metadata/__init__.py @@ -16,10 +16,10 @@ # You should have received a copy of the GNU General Public License # along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. -__all__ = ['generic', 'helpers', 'xbmc', 'mediabrowser', 'ps3', 'wdtv', 'tivo'] +__all__ = ['generic', 'helpers', 'xbmc', 'mediabrowser', 'synology', 'ps3', 'wdtv', 'tivo'] import sys -import xbmc, mediabrowser, ps3, wdtv, tivo +import xbmc, mediabrowser, synology, ps3, wdtv, tivo def available_generators(): return filter(lambda x: x not in ('generic', 'helpers'), __all__) diff --git a/sickbeard/metadata/synology.py b/sickbeard/metadata/synology.py new file mode 100644 index 0000000000000000000000000000000000000000..8fa0d2fc40b741ab42937b46aa14003298521abe --- /dev/null +++ b/sickbeard/metadata/synology.py @@ -0,0 +1,410 @@ +# Author: Frans Kool <big_cabbage@hotmail.com> +# Created for Synology NAS, based on mediabrowser +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +import datetime +import os +import re + +import sickbeard + +import generic + +from sickbeard.common import XML_NSMAP +from sickbeard import logger, exceptions, helpers +from sickbeard import encodingKludge as ek +from lib.tvdb_api import tvdb_api, tvdb_exceptions +from sickbeard.exceptions import ex + +import xml.etree.cElementTree as etree + +class SynologyMetadata(generic.GenericMetadata): + """ + Metadata generation class for Synology. All xml formatting and + file naming information was contributed by users in the following + ticket's comments: + + http://code.google.com/p/sickbeard/issues/detail?id=311 + + The following file structure is used: + + show_root/series.xml (show metadata) + show_root/folder.jpg (poster) + show_root/backdrop.jpg (fanart) + show_root/Season 01/folder.jpg (season thumb) + show_root/Season 01/show - 1x01 - episode.avi (* example of existing ep of course) + show_root/Season 01/show - 1x01 - episode.xml (episode metadata) + show_root/Season 01/show - 1x01 - episode.jpg (episode thumb) + """ + + def __init__(self, + show_metadata=False, + episode_metadata=False, + poster=False, + fanart=False, + episode_thumbnails=False, + season_thumbnails=False): + + generic.GenericMetadata.__init__(self, + show_metadata, + episode_metadata, + poster, + fanart, + episode_thumbnails, + season_thumbnails) + + self.fanart_name = "backdrop.jpg" + self._show_file_name = 'series.xml' + self._ep_nfo_extension = 'xml' + + self.name = 'Synology' + + self.eg_show_metadata = "series.xml" + self.eg_episode_metadata = "Season##\\<i>filename</i>.xml" + self.eg_fanart = "backdrop.jpg" + self.eg_poster = "folder.jpg" + self.eg_episode_thumbnails = "Season##\\<i>filename</i>.jpg" + self.eg_season_thumbnails = "Season##\\folder.jpg" + + def get_episode_file_path(self, ep_obj): + """ + Returns a full show dir/episode.xml path for Synology + episode metadata files + + ep_obj: a TVEpisode object to get the path for + """ + + if ek.ek(os.path.isfile, ep_obj.location): + xml_file_name = helpers.replaceExtension(ek.ek(os.path.basename, ep_obj.location), self._ep_nfo_extension) + metadata_dir_name = ek.ek(os.path.join, ek.ek(os.path.dirname, ep_obj.location), '') + xml_file_path = ek.ek(os.path.join, metadata_dir_name, xml_file_name) + else: + logger.log(u"Episode location doesn't exist: "+str(ep_obj.location), logger.DEBUG) + return '' + + return xml_file_path + + def get_episode_thumb_path(self, ep_obj): + """ + Returns a full show dir/episode.jpg path for Synology + episode thumbs. + + ep_obj: a TVEpisode object to get the path from + """ + + if ek.ek(os.path.isfile, ep_obj.location): + tbn_file_name = helpers.replaceExtension(ek.ek(os.path.basename, ep_obj.location), 'jpg') + metadata_dir_name = ek.ek(os.path.join, ek.ek(os.path.dirname, ep_obj.location), '') + tbn_file_path = ek.ek(os.path.join, metadata_dir_name, tbn_file_name) + else: + return None + + return tbn_file_path + + def get_season_thumb_path(self, show_obj, season): + """ + Season thumbs for Synology go in Show Dir/Season X/folder.jpg + + If no season folder exists, None is returned + """ + + dir_list = [x for x in ek.ek(os.listdir, show_obj.location) if ek.ek(os.path.isdir, ek.ek(os.path.join, show_obj.location, x))] + + season_dir_regex = '^Season\s+(\d+)$' + + season_dir = None + + for cur_dir in dir_list: + if season == 0 and cur_dir == 'Specials': + season_dir = cur_dir + break + + match = re.match(season_dir_regex, cur_dir, re.I) + if not match: + continue + + cur_season = int(match.group(1)) + + if cur_season == season: + season_dir = cur_dir + break + + if not season_dir: + logger.log(u"Unable to find a season dir for season "+str(season), logger.DEBUG) + return None + + logger.log(u"Using "+str(season_dir)+"/folder.jpg as season dir for season "+str(season), logger.DEBUG) + + return ek.ek(os.path.join, show_obj.location, season_dir, 'folder.jpg') + + def _show_data(self, show_obj): + """ + Creates an elementTree XML structure for a Synology-style series.xml + returns the resulting data object. + + show_obj: a TVShow instance to create the NFO for + """ + + tvdb_lang = show_obj.lang + # There's gotta be a better way of doing this but we don't wanna + # change the language value elsewhere + ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() + + if tvdb_lang and not tvdb_lang == 'en': + ltvdb_api_parms['language'] = tvdb_lang + + t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) + + tv_node = etree.Element("Series") + for ns in XML_NSMAP.keys(): + tv_node.set(ns, XML_NSMAP[ns]) + + try: + myShow = t[int(show_obj.tvdbid)] + except tvdb_exceptions.tvdb_shownotfound: + logger.log("Unable to find show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) + raise + + except tvdb_exceptions.tvdb_error: + logger.log("TVDB is down, can't use its data to make the NFO", logger.ERROR) + raise + + # check for title and id + try: + if myShow["seriesname"] == None or myShow["seriesname"] == "" or myShow["id"] == None or myShow["id"] == "": + logger.log("Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) + return False + except tvdb_exceptions.tvdb_attributenotfound: + logger.log("Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) + + return False + + tvdbid = etree.SubElement(tv_node, "id") + if myShow["id"] != None: + tvdbid.text = myShow["id"] + + Actors = etree.SubElement(tv_node, "Actors") + if myShow["actors"] != None: + Actors.text = myShow["actors"] + + ContentRating = etree.SubElement(tv_node, "ContentRating") + if myShow["contentrating"] != None: + ContentRating.text = myShow["contentrating"] + + premiered = etree.SubElement(tv_node, "FirstAired") + if myShow["firstaired"] != None: + premiered.text = myShow["firstaired"] + + genre = etree.SubElement(tv_node, "genre") + if myShow["genre"] != None: + genre.text = myShow["genre"] + + IMDBId = etree.SubElement(tv_node, "IMDBId") + if myShow["imdb_id"] != None: + IMDBId.text = myShow["imdb_id"] + + IMDB_ID = etree.SubElement(tv_node, "IMDB_ID") + if myShow["imdb_id"] != None: + IMDB_ID.text = myShow["imdb_id"] + + Overview = etree.SubElement(tv_node, "Overview") + if myShow["overview"] != None: + Overview.text = myShow["overview"] + + Network = etree.SubElement(tv_node, "Network") + if myShow["network"] != None: + Network.text = myShow["network"] + + Runtime = etree.SubElement(tv_node, "Runtime") + if myShow["runtime"] != None: + Runtime.text = myShow["runtime"] + + + Rating = etree.SubElement(tv_node, "Rating") + if myShow["rating"] != None: + Rating.text = myShow["rating"] + + SeriesID = etree.SubElement(tv_node, "SeriesID") + if myShow["seriesid"] != None: + SeriesID.text = myShow["seriesid"] + + SeriesName = etree.SubElement(tv_node, "SeriesName") + if myShow["seriesname"] != None: + SeriesName.text = myShow["seriesname"] + + rating = etree.SubElement(tv_node, "Status") + if myShow["status"] != None: + rating.text = myShow["status"] + + helpers.indentXML(tv_node) + + data = etree.ElementTree(tv_node) + + return data + + + def _ep_data(self, ep_obj): + """ + Creates an elementTree XML structure for a Synology style episode.xml + and returns the resulting data object. + + show_obj: a TVShow instance to create the NFO for + """ + + eps_to_write = [ep_obj] + ep_obj.relatedEps + + tvdb_lang = ep_obj.show.lang + + try: + # There's gotta be a better way of doing this but we don't wanna + # change the language value elsewhere + ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() + + if tvdb_lang and not tvdb_lang == 'en': + ltvdb_api_parms['language'] = tvdb_lang + + t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) + myShow = t[ep_obj.show.tvdbid] + except tvdb_exceptions.tvdb_shownotfound, e: + raise exceptions.ShowNotFoundException(e.message) + except tvdb_exceptions.tvdb_error, e: + logger.log("Unable to connect to TVDB while creating meta files - skipping - "+ex(e), logger.ERROR) + return False + + rootNode = etree.Element("Item") + + # Set our namespace correctly + for ns in XML_NSMAP.keys(): + rootNode.set(ns, XML_NSMAP[ns]) + + # write an Synology XML containing info for all matching episodes + for curEpToWrite in eps_to_write: + + try: + myEp = myShow[curEpToWrite.season][curEpToWrite.episode] + except (tvdb_exceptions.tvdb_episodenotfound, tvdb_exceptions.tvdb_seasonnotfound): + logger.log("Unable to find episode " + str(curEpToWrite.season) + "x" + str(curEpToWrite.episode) + " on tvdb... has it been removed? Should I delete from db?") + return None + + if myEp["firstaired"] == None and ep_obj.season == 0: + myEp["firstaired"] = str(datetime.date.fromordinal(1)) + + if myEp["episodename"] == None or myEp["firstaired"] == None: + return None + + if len(eps_to_write) > 1: + episode = etree.SubElement(rootNode, "Item") + else: + episode = rootNode + + ID = etree.SubElement(episode, "ID") + ID.text = str(curEpToWrite.episode) + + #To do get right EpisodeID + episodeID = etree.SubElement(episode, "EpisodeID") + episodeID.text = str(curEpToWrite.tvdbid) + + title = etree.SubElement(episode, "EpisodeName") + if curEpToWrite.name != None: + title.text = curEpToWrite.name + + episodenum = etree.SubElement(episode, "EpisodeNumber") + episodenum.text = str(curEpToWrite.episode) + + FirstAired = etree.SubElement(episode, "FirstAired") + if curEpToWrite.airdate != datetime.date.fromordinal(1): + FirstAired.text = str(curEpToWrite.airdate) + else: + FirstAired.text = '' + + Overview = etree.SubElement(episode, "Overview") + if curEpToWrite.description != None: + Overview.text = curEpToWrite.description + + DVD_chapter = etree.SubElement(episode, "DVD_chapter") + DVD_chapter.text = '' + + DVD_discid = etree.SubElement(episode, "DVD_discid") + DVD_discid.text = '' + + DVD_episodenumber = etree.SubElement(episode, "DVD_episodenumber") + DVD_episodenumber.text = '' + + DVD_season = etree.SubElement(episode, "DVD_season") + DVD_season.text = '' + + director = etree.SubElement(episode, "Director") + director_text = myEp['director'] + if director_text != None: + director.text = director_text + + gueststar = etree.SubElement(episode, "GuestStars") + gueststar_text = myEp['gueststars'] + if gueststar_text != None: + gueststar.text = gueststar_text + + IMDB_ID = etree.SubElement(episode, "IMDB_ID") + IMDB_ID.text = myEp['imdb_id'] + + Language = etree.SubElement(episode, "Language") + Language.text = myEp['language'] + + ProductionCode = etree.SubElement(episode, "ProductionCode") + ProductionCode.text = myEp['productioncode'] + + Rating = etree.SubElement(episode, "Rating") + rating_text = myEp['rating'] + if rating_text != None: + Rating.text = rating_text + + Writer = etree.SubElement(episode, "Writer") + Writer_text = myEp['writer'] + if Writer_text != None: + Writer.text = Writer_text + + SeasonNumber = etree.SubElement(episode, "SeasonNumber") + SeasonNumber.text = str(curEpToWrite.season) + + absolute_number = etree.SubElement(episode, "absolute_number") + absolute_number.text = myEp['absolute_number'] + + seasonid = etree.SubElement(episode, "seasonid") + seasonid.text = myEp['seasonid'] + + seriesid = etree.SubElement(episode, "seriesid") + seriesid.text = str(curEpToWrite.show.tvdbid) + + thumb = etree.SubElement(episode, "filename") + + # just write this to the NFO regardless of whether it actually exists or not + # note: renaming files after nfo generation will break this, tough luck + thumb_text = self.get_episode_thumb_path(ep_obj) + if thumb_text: + thumb.text = thumb_text + + # Make it purdy + helpers.indentXML(rootNode) + data = etree.ElementTree(rootNode) + + return data + + def retrieveShowMetadata(self, dir): + return (None, None) + +# present a standard "interface" +metadata_class = SynologyMetadata diff --git a/sickbeard/metadata/tivo.py b/sickbeard/metadata/tivo.py old mode 100644 new mode 100755 index b55aa5162b6861512436249bdebeb0aa77b17ff7..5328cdf472fffc7fa6f06403ebe6e9203f9fd1ba --- a/sickbeard/metadata/tivo.py +++ b/sickbeard/metadata/tivo.py @@ -26,6 +26,7 @@ import sickbeard from sickbeard import logger, exceptions, helpers from sickbeard.metadata import generic from sickbeard import encodingKludge as ek +from sickbeard import config from lib.tvdb_api import tvdb_api, tvdb_exceptions @@ -174,7 +175,9 @@ class TIVOMetadata(generic.GenericMetadata): # Title of the episode (Pilot, Homer's Night Out, Episode 02, etc.) Should be included for episodic shows. # Leave blank or omit for movies. - data += ("episodeTitle : " + curEpToWrite.name + "\n") + # + # Added season episode to title, so that the shows will sort correctly, as often the date information is wrong. + data += ("episodeTitle : " + config.naming_ep_type[sickbeard.NAMING_EP_TYPE] % {'seasonnumber': curEpToWrite.season, 'episodenumber': curEpToWrite.episode} + " " + curEpToWrite.name + "\n") # This should be entered for episodic shows and omitted for movies. The standard tivo format is to enter @@ -232,7 +235,7 @@ class TIVOMetadata(generic.GenericMetadata): if myShow["actors"]: for actor in myShow["actors"].split('|'): if actor: - data += ("vActor : " + str(actor) + "\n") + data += ("vActor : " + actor + "\n") # This is shown on both the Program screen and the Details screen. It uses a single digit to determine the diff --git a/sickbeard/metadata/wdtv.py b/sickbeard/metadata/wdtv.py index 94c5dced06350fecfb1a73c255fec3f08510fdf7..f0adac1af49f45d6b0e2d5db109fbadb46574414 100644 --- a/sickbeard/metadata/wdtv.py +++ b/sickbeard/metadata/wdtv.py @@ -1,129 +1,232 @@ -# Author: Nic Wolfe <nic@wolfeden.ca> -# URL: http://code.google.com/p/sickbeard/ -# -# This file is part of Sick Beard. -# -# Sick Beard is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Sick Beard is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. - -import os -import re - -import generic - -from sickbeard import logger, helpers - -from sickbeard import encodingKludge as ek - -class WDTVMetadata(generic.GenericMetadata): - """ - Metadata generation class for WDTV - - The following file structure is used: - - show_root/folder.jpg (poster) - show_root/Season 01/folder.jpg (episode thumb) - show_root/Season 01/show - 1x01 - episode.jpg (existing video) - """ - - def __init__(self, - show_metadata=False, - episode_metadata=False, - poster=False, - fanart=False, - episode_thumbnails=False, - season_thumbnails=False): - - generic.GenericMetadata.__init__(self, - show_metadata, - episode_metadata, - poster, - fanart, - episode_thumbnails, - season_thumbnails) - - self.name = 'WDTV' - - self.eg_show_metadata = "<i>not supported</i>" - self.eg_episode_metadata = "<i>not supported</i>" - self.eg_fanart = "<i>not supported</i>" - self.eg_poster = "folder.jpg" - self.eg_episode_thumbnails = "Season##\\<i>filename</i>.jpg" - self.eg_season_thumbnails = "Season##\\folder.jpg" - - # all of the following are not supported, so do nothing - def create_show_metadata(self, show_obj): - pass - - def create_episode_metadata(self, ep_obj): - pass - - def create_fanart(self, show_obj): - pass - - def get_episode_thumb_path(self, ep_obj): - """ - Returns the path where the episode thumbnail should be stored. Defaults to - the same path as the episode file but with a .cover.jpg extension. - - ep_obj: a TVEpisode instance for which to create the thumbnail - """ - if ek.ek(os.path.isfile, ep_obj.location): - tbn_filename = helpers.replaceExtension(ep_obj.location, 'jpg') - else: - return None - - return tbn_filename - - def get_season_thumb_path(self, show_obj, season): - """ - Season thumbs for MediaBrowser go in Show Dir/Season X/folder.jpg - - If no season folder exists, None is returned - """ - - dir_list = [x for x in ek.ek(os.listdir, show_obj.location) if ek.ek(os.path.isdir, ek.ek(os.path.join, show_obj.location, x))] - - season_dir_regex = '^Season\s+(\d+)$' - - season_dir = None - - for cur_dir in dir_list: - if season == 0 and cur_dir == 'Specials': - season_dir = cur_dir - break - - match = re.match(season_dir_regex, cur_dir, re.I) - if not match: - continue - - cur_season = int(match.group(1)) - - if cur_season == season: - season_dir = cur_dir - break - - if not season_dir: - logger.log(u"Unable to find a season dir for season "+str(season), logger.DEBUG) - return None - - logger.log(u"Using "+str(season_dir)+"/folder.jpg as season dir for season "+str(season), logger.DEBUG) - - return ek.ek(os.path.join, show_obj.location, season_dir, 'folder.jpg') - - def retrieveShowMetadata(self, dir): - return (None, None) - -# present a standard "interface" -metadata_class = WDTVMetadata - +# Author: Nic Wolfe <nic@wolfeden.ca> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +import datetime +import os +import re + +import sickbeard + +import generic + +from sickbeard import logger, exceptions, helpers +from sickbeard import encodingKludge as ek +from lib.tvdb_api import tvdb_api, tvdb_exceptions +from sickbeard.exceptions import ex + +import xml.etree.cElementTree as etree + +class WDTVMetadata(generic.GenericMetadata): + """ + Metadata generation class for WDTV + + The following file structure is used: + + show_root/folder.jpg (poster) + show_root/Season 01/folder.jpg (season thumb) + show_root/Season 01/show - 1x01 - episode.metathumb (episode thumb) + show_root/Season 01/show - 1x01 - episode.xml (episode metadata) + """ + + def __init__(self, + show_metadata=False, + episode_metadata=False, + poster=False, + fanart=False, + episode_thumbnails=False, + season_thumbnails=False): + + generic.GenericMetadata.__init__(self, + show_metadata, + episode_metadata, + poster, + fanart, + episode_thumbnails, + season_thumbnails) + + self._ep_nfo_extension = 'xml' + + self.name = 'WDTV' + + self.eg_show_metadata = "<i>not supported</i>" + self.eg_episode_metadata = "Season##\\<i>filename</i>.xml" + self.eg_fanart = "<i>not supported</i>" + self.eg_poster = "folder.jpg" + self.eg_episode_thumbnails = "Season##\\<i>filename</i>.metathumb" + self.eg_season_thumbnails = "Season##\\folder.jpg" + + # all of the following are not supported, so do nothing + def create_show_metadata(self, show_obj): + pass + + def create_fanart(self, show_obj): + pass + + def get_episode_thumb_path(self, ep_obj): + """ + Returns the path where the episode thumbnail should be stored. Defaults to + the same path as the episode file but with a .metathumb extension. + + ep_obj: a TVEpisode instance for which to create the thumbnail + """ + if ek.ek(os.path.isfile, ep_obj.location): + tbn_filename = helpers.replaceExtension(ep_obj.location, 'metathumb') + else: + return None + + return tbn_filename + + def get_season_thumb_path(self, show_obj, season): + """ + Season thumbs for WDTV go in Show Dir/Season X/folder.jpg + + If no season folder exists, None is returned + """ + + dir_list = [x for x in ek.ek(os.listdir, show_obj.location) if ek.ek(os.path.isdir, ek.ek(os.path.join, show_obj.location, x))] + + season_dir_regex = '^Season\s+(\d+)$' + + season_dir = None + + for cur_dir in dir_list: + if season == 0 and cur_dir == 'Specials': + season_dir = cur_dir + break + + match = re.match(season_dir_regex, cur_dir, re.I) + if not match: + continue + + cur_season = int(match.group(1)) + + if cur_season == season: + season_dir = cur_dir + break + + if not season_dir: + logger.log(u"Unable to find a season dir for season "+str(season), logger.DEBUG) + return None + + logger.log(u"Using "+str(season_dir)+"/folder.jpg as season dir for season "+str(season), logger.DEBUG) + + return ek.ek(os.path.join, show_obj.location, season_dir, 'folder.jpg') + + def _ep_data(self, ep_obj): + """ + Creates an elementTree XML structure for a WDTV style episode.xml + and returns the resulting data object. + + ep_obj: a TVShow instance to create the NFO for + """ + + eps_to_write = [ep_obj] + ep_obj.relatedEps + + tvdb_lang = ep_obj.show.lang + + try: + # There's gotta be a better way of doing this but we don't wanna + # change the language value elsewhere + ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() + + if tvdb_lang and not tvdb_lang == 'en': + ltvdb_api_parms['language'] = tvdb_lang + + t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) + myShow = t[ep_obj.show.tvdbid] + except tvdb_exceptions.tvdb_shownotfound, e: + raise exceptions.ShowNotFoundException(e.message) + except tvdb_exceptions.tvdb_error, e: + logger.log("Unable to connect to TVDB while creating meta files - skipping - "+ex(e), logger.ERROR) + return False + + rootNode = etree.Element("details") + + # write an WDTV XML containing info for all matching episodes + for curEpToWrite in eps_to_write: + + try: + myEp = myShow[curEpToWrite.season][curEpToWrite.episode] + except (tvdb_exceptions.tvdb_episodenotfound, tvdb_exceptions.tvdb_seasonnotfound): + logger.log("Unable to find episode " + str(curEpToWrite.season) + "x" + str(curEpToWrite.episode) + " on tvdb... has it been removed? Should I delete from db?") + return None + + if myEp["firstaired"] == None and ep_obj.season == 0: + myEp["firstaired"] = str(datetime.date.fromordinal(1)) + + if myEp["episodename"] == None or myEp["firstaired"] == None: + return None + + if len(eps_to_write) > 1: + episode = etree.SubElement(rootNode, "details") + else: + episode = rootNode + + #To do get right EpisodeID + episodeID = etree.SubElement(episode, "id") + episodeID.text = str(curEpToWrite.tvdbid) + + title = etree.SubElement(episode, "title") + title.text = ep_obj.prettyName() + + seriesName = etree.SubElement(episode, "series_name") + if myShow["seriesname"] != None: + seriesName.text = myShow["seriesname"] + + episodeName = etree.SubElement(episode, "episode_name") + if curEpToWrite.name != None: + episodeName.text = curEpToWrite.name + + seasonNumber = etree.SubElement(episode, "season_number") + seasonNumber.text = str(curEpToWrite.season) + + episodeNum = etree.SubElement(episode, "episode_number") + episodeNum.text = str(curEpToWrite.episode) + + firstAired = etree.SubElement(episode, "firstaired") + if curEpToWrite.airdate != datetime.date.fromordinal(1): + firstAired.text = str(curEpToWrite.airdate) + + genre = etree.SubElement(episode, "genre") + if myShow["genre"] != None: + genre.text = " / ".join([x for x in myShow["genre"].split('|') if x]) + + director = etree.SubElement(episode, "director") + director_text = myEp['director'] + if director_text != None: + director.text = director_text + + actor = etree.SubElement(episode, "actor") + if myShow["actors"] != None: + actor.text = " / ".join([x for x in myShow["actors"].split('|') if x]) + + overview = etree.SubElement(episode, "overview") + if curEpToWrite.description != None: + overview.text = curEpToWrite.description + + # Make it purdy + helpers.indentXML(rootNode) + data = etree.ElementTree(rootNode) + + return data + + def retrieveShowMetadata(self, dir): + return (None, None) + +# present a standard "interface" +metadata_class = WDTVMetadata diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index ed844bcdea1b501b37a8d586d4cfc5d11997ff3a..e6c6cd89ea1a604c0910e1e8f0bc8644eb751f27 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -61,7 +61,7 @@ class NameParser(object): try: cur_regex = re.compile(cur_pattern, re.VERBOSE | re.IGNORECASE) except re.error, errormsg: - logger.log(u"WARNING: Invalid episode_pattern, %s. %s" % (errormsg, cur_regex.pattern)) + logger.log(u"WARNING: Invalid episode_pattern, %s. %s" % (errormsg, cur_pattern)) else: self.compiled_regexes.append((cur_pattern_name, cur_regex)) @@ -282,7 +282,10 @@ class ParseResult(object): return True def __str__(self): - to_return = str(self.series_name) + ' - ' + if self.series_name != None: + to_return = self.series_name + u' - ' + else: + to_return = u'' if self.season_number != None: to_return += 'S'+str(self.season_number) if self.episode_numbers and len(self.episode_numbers): @@ -308,4 +311,4 @@ class ParseResult(object): air_by_date = property(_is_air_by_date) class InvalidNameException(Exception): - "The given name is not valid" \ No newline at end of file + "The given name is not valid" diff --git a/sickbeard/name_parser/regexes.py b/sickbeard/name_parser/regexes.py index f3cc29c3e56aece1756a81f9396020d0133a996a..e7b2900d5d90f5aa1a13a6039cd7a87def10eed3 100644 --- a/sickbeard/name_parser/regexes.py +++ b/sickbeard/name_parser/regexes.py @@ -95,6 +95,7 @@ ep_regexes = [ # tpz-abc102 ''' (?P<release_group>.+?)-\w+?[\. ]? # tpz-abc + (?!264) # don't count x264 (?P<season_num>\d{1,2}) # 1 (?P<ep_num>\d{2})$ # 02 '''), diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index c0c9b489c919657f82c228953bb21c165de6fc39..6e9228fa432f2e9422da43876694e1263d04f87c 100755 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -18,47 +18,63 @@ import sickbeard -import xbmc -import plex +import xbmc +import plex import growl import prowl import tweet from . import libnotify import notifo +import boxcar +import pushover import nmj import synoindex +import trakt +import pytivo +import nma from sickbeard.common import * -xbmc_notifier = xbmc.XBMCNotifier() -plex_notifier = plex.PLEXNotifier() +xbmc_notifier = xbmc.XBMCNotifier() +plex_notifier = plex.PLEXNotifier() growl_notifier = growl.GrowlNotifier() prowl_notifier = prowl.ProwlNotifier() twitter_notifier = tweet.TwitterNotifier() notifo_notifier = notifo.NotifoNotifier() +boxcar_notifier = boxcar.BoxcarNotifier() +pushover_notifier = pushover.PushoverNotifier() libnotify_notifier = libnotify.LibnotifyNotifier() nmj_notifier = nmj.NMJNotifier() synoindex_notifier = synoindex.synoIndexNotifier() +trakt_notifier = trakt.TraktNotifier() +pytivo_notifier = pytivo.pyTivoNotifier() +nma_notifier = nma.NMA_Notifier() notifiers = [ - # Libnotify notifier goes first because it doesn't involve blocking on - # network activity. + # Libnotify notifier goes first because it doesn't involve blocking on + # network activity. libnotify_notifier, - xbmc_notifier, - plex_notifier, + xbmc_notifier, + plex_notifier, growl_notifier, - prowl_notifier, + prowl_notifier, twitter_notifier, nmj_notifier, synoindex_notifier, + boxcar_notifier, + pushover_notifier, + trakt_notifier, + pytivo_notifier, + nma_notifier, ] def notify_download(ep_name): for n in notifiers: n.notify_download(ep_name) - notifo_notifier.notify_download(ep_name) + notifo_notifier.notify_download(ep_name) def notify_snatch(ep_name): for n in notifiers: n.notify_snatch(ep_name) - notifo_notifier.notify_snatch(ep_name) + notifo_notifier.notify_snatch(ep_name) + diff --git a/sickbeard/notifiers/boxcar.py b/sickbeard/notifiers/boxcar.py new file mode 100644 index 0000000000000000000000000000000000000000..35a86942de89b5786e9e574138ce8b8f35a2d14b --- /dev/null +++ b/sickbeard/notifiers/boxcar.py @@ -0,0 +1,145 @@ +# Author: Marvin Pinto <me@marvinp.ca> +# Author: Dennis Lutter <lad1337@gmail.com> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +import urllib, urllib2 +import time + +import sickbeard + +from sickbeard import logger +from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD +from sickbeard.exceptions import ex + +API_URL = "https://boxcar.io/devices/providers/fWc4sgSmpcN6JujtBmR6/notifications" + +class BoxcarNotifier: + + def test_notify(self, email, title="Test"): + return self._sendBoxcar("This is a test notification from SickBeard", title, email) + + def _sendBoxcar(self, msg, title, email, subscribe=False): + """ + Sends a boxcar notification to the address provided + + msg: The message to send (unicode) + title: The title of the message + email: The email address to send the message to (or to subscribe with) + subscribe: If true then instead of sending a message this function will send a subscription notification (optional, default is False) + + returns: True if the message succeeded, False otherwise + """ + + # build up the URL and parameters + msg = msg.strip() + curUrl = API_URL + + # if this is a subscription notification then act accordingly + if subscribe: + data = urllib.urlencode({'email': email}) + curUrl = curUrl + "/subscribe" + + # for normal requests we need all these parameters + else: + data = urllib.urlencode({ + 'email': email, + 'notification[from_screen_name]': title, + 'notification[message]': msg.encode('utf-8'), + 'notification[from_remote_service_id]': int(time.time()) + }) + + + # send the request to boxcar + try: + req = urllib2.Request(curUrl) + handle = urllib2.urlopen(req, data) + handle.close() + + except urllib2.URLError, e: + # if we get an error back that doesn't have an error code then who knows what's really happening + if not hasattr(e, 'code'): + logger.log("Boxcar notification failed." + ex(e), logger.ERROR) + return False + else: + logger.log("Boxcar notification failed. Error code: " + str(e.code), logger.WARNING) + + # HTTP status 404 if the provided email address isn't a Boxcar user. + if e.code == 404: + logger.log("Username is wrong/not a boxcar email. Boxcar will send an email to it", logger.WARNING) + return False + + # For HTTP status code 401's, it is because you are passing in either an invalid token, or the user has not added your service. + elif e.code == 401: + + # If the user has already added your service, we'll return an HTTP status code of 401. + if subscribe: + logger.log("Already subscribed to service", logger.ERROR) + # i dont know if this is true or false ... its neither but i also dont know how we got here in the first place + return False + + #HTTP status 401 if the user doesn't have the service added + else: + subscribeNote = self._sendBoxcar(msg, title, email, True) + if subscribeNote: + logger.log("Subscription send", logger.DEBUG) + return True + else: + logger.log("Subscription could not be send", logger.ERROR) + return False + + # If you receive an HTTP status code of 400, it is because you failed to send the proper parameters + elif e.code == 400: + logger.log("Wrong data send to boxcar", logger.ERROR) + return False + + logger.log("Boxcar notification successful.", logger.DEBUG) + return True + + def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]): + if sickbeard.BOXCAR_NOTIFY_ONSNATCH: + self._notifyBoxcar(title, ep_name) + + + def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]): + if sickbeard.BOXCAR_NOTIFY_ONDOWNLOAD: + self._notifyBoxcar(title, ep_name) + + def _notifyBoxcar(self, title, message, username=None, force=False): + """ + Sends a boxcar notification based on the provided info or SB config + + title: The title of the notification to send + message: The message string to send + username: The username to send the notification to (optional, defaults to the username in the config) + force: If True then the notification will be sent even if Boxcar is disabled in the config + """ + + if not sickbeard.USE_BOXCAR and not force: + logger.log("Notification for Boxcar not enabled, skipping this notification", logger.DEBUG) + return False + + # if no username was given then use the one from the config + if not username: + username = sickbeard.BOXCAR_USERNAME + + logger.log("Sending notification for " + message, logger.DEBUG) + + self._sendBoxcar(message, title, username) + return True + +notifier = BoxcarNotifier diff --git a/sickbeard/notifiers/nma.py b/sickbeard/notifiers/nma.py new file mode 100644 index 0000000000000000000000000000000000000000..a85212715bcebf86d5d953c2767e941a0b7ce1a5 --- /dev/null +++ b/sickbeard/notifiers/nma.py @@ -0,0 +1,52 @@ +import sickbeard + +from sickbeard import logger, common +from lib.pynma import pynma + +class NMA_Notifier: + + def test_notify(self, nma_api, nma_priority): + return self._sendNMA(nma_api, nma_priority, event="Test", message="Testing NMA settings from Sick Beard", force=True) + + def notify_snatch(self, ep_name): + if sickbeard.NMA_NOTIFY_ONSNATCH: + self._sendNMA(nma_api=None, nma_priority=None, event=common.notifyStrings[common.NOTIFY_SNATCH], message=ep_name) + + def notify_download(self, ep_name): + if sickbeard.NMA_NOTIFY_ONDOWNLOAD: + self._sendNMA(nma_api=None, nma_priority=None, event=common.notifyStrings[common.NOTIFY_DOWNLOAD], message=ep_name) + + def _sendNMA(self, nma_api=None, nma_priority=None, event=None, message=None, force=False): + + title = 'Sick-Beard' + + if not sickbeard.USE_NMA and not force: + return False + + if nma_api == None: + nma_api = sickbeard.NMA_API + + if nma_priority == None: + nma_priority = sickbeard.NMA_PRIORITY + + logger.log(u"NMA title: " + title, logger.DEBUG) + logger.log(u"NMA event: " + event, logger.DEBUG) + logger.log(u"NMA message: " + message, logger.DEBUG) + + batch = False + + p = pynma.PyNMA() + keys = nma_api.split(',') + p.addkey(keys) + + if len(keys) > 1: batch = True + + response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) + + if not response[nma_api][u'code'] == u'200': + logger.log(u'Could not send notification to NotifyMyAndroid', logger.ERROR) + return False + else: + return True + +notifier = NMA_Notifier \ No newline at end of file diff --git a/sickbeard/notifiers/nmj.py b/sickbeard/notifiers/nmj.py index de074f048547feb3fe9dda939fe130852abb37ba..b84ae816cf55391ebffea04e0e91f0444a66c3a1 100644 --- a/sickbeard/notifiers/nmj.py +++ b/sickbeard/notifiers/nmj.py @@ -31,6 +31,15 @@ except ImportError: class NMJNotifier: def notify_settings(self, host): + """ + Retrieves the settings from a NMJ/Popcorn hour + + host: The hostname/IP of the Popcorn Hour server + + Returns: True if the settings were retrieved successfully, False otherwise + """ + + # establish a terminal session to the PC terminal = False try: terminal = telnetlib.Telnet(host) @@ -38,6 +47,7 @@ class NMJNotifier: logger.log(u"Warning: unable to get a telnet session to %s" % (host), logger.ERROR) return False + # tell the terminal to output the necessary info to the screen so we can search it later logger.log(u"Connected to %s via telnet" % (host), logger.DEBUG) terminal.read_until("sh-3.00# ") terminal.write("cat /tmp/source\n") @@ -49,6 +59,7 @@ class NMJNotifier: device = "" match = re.search(r"(.+\.db)\r\n?(.+)(?=sh-3.00# cat /tmp/netshare)", tnoutput) + # if we found the database in the terminal output then save that database to the config if match: database = match.group(1) device = match.group(2) @@ -57,7 +68,8 @@ class NMJNotifier: else: logger.log(u"Could not get current NMJ database on %s, NMJ is probably not running!" % (host), logger.ERROR) return False - + + # if the device is a remote host then try to parse the mounting URL and save it to the config if device.startswith("NETWORK_SHARE/"): match = re.search(".*(?=\r\n?%s)" % (re.escape(device[14:])), tnoutput) @@ -82,6 +94,17 @@ class NMJNotifier: return self._sendNMJ(host, database, mount) def _sendNMJ(self, host, database, mount=None): + """ + Sends a NMJ update command to the specified machine + + host: The hostname/IP to send the request to (no port) + database: The database to send the requst to + mount: The mount URL to use (optional) + + Returns: True if the request succeeded, False otherwise + """ + + # if a mount URL is provided then attempt to open a handle to that URL if mount: try: req = urllib2.Request(mount) @@ -91,6 +114,7 @@ class NMJNotifier: logger.log(u"Warning: Couldn't contact popcorn hour on host %s: %s" % (host, e)) return False + # build up the request URL and parameters UPDATE_URL = "http://%(host)s:8008/metadata_database?%(params)s" params = { "arg0": "scanner_start", @@ -100,6 +124,7 @@ class NMJNotifier: params = urllib.urlencode(params) updateUrl = UPDATE_URL % {"host": host, "params": params} + # send the request to the server try: req = urllib2.Request(updateUrl) logger.log(u"Sending NMJ scan update command via url: %s" % (updateUrl), logger.DEBUG) @@ -109,6 +134,7 @@ class NMJNotifier: logger.log(u"Warning: Couldn't contact Popcorn Hour on host %s: %s" % (host, e)) return False + # try to parse the resulting XML try: et = etree.fromstring(response) result = et.findtext("returnValue") @@ -116,6 +142,7 @@ class NMJNotifier: logger.log(u"Unable to parse XML returned from the Popcorn Hour: %s" % (e), logger.ERROR) return False + # if the result was a number then consider that an error if int(result) > 0: logger.log(u"Popcorn Hour returned an errorcode: %s" % (result)) return False @@ -124,10 +151,19 @@ class NMJNotifier: return True def _notifyNMJ(self, host=None, database=None, mount=None, force=False): + """ + Sends a NMJ update command based on the SB config settings + + host: The host to send the command to (optional, defaults to the host in the config) + database: The database to use (optional, defaults to the database in the config) + mount: The mount URL (optional, defaults to the mount URL in the config) + force: If True then the notification will be sent even if NMJ is disabled in the config + """ if not sickbeard.USE_NMJ and not force: logger.log("Notification for NMJ scan update not enabled, skipping this notification", logger.DEBUG) return False + # fill in omitted parameters if not host: host = sickbeard.NMJ_HOST if not database: diff --git a/sickbeard/notifiers/notifo.py b/sickbeard/notifiers/notifo.py index f525c4f777a27f0985176a7dcdda9727fbaf2c7a..11337e0701be9e742c310258030177c0f019c5a7 100644 --- a/sickbeard/notifiers/notifo.py +++ b/sickbeard/notifiers/notifo.py @@ -22,6 +22,7 @@ import urllib import sickbeard from sickbeard import logger +from sickbeard.exceptions import ex try: import lib.simplejson as json #@UnusedImport @@ -36,22 +37,45 @@ class NotifoNotifier: return self._sendNotifo("This is a test notification from SickBeard", title, username, apisecret) def _sendNotifo(self, msg, title, username, apisecret, label="SickBeard"): + """ + Sends a message to notify using the given authentication information + + msg: The string to send to notifo + title: The title of the message + username: The username to send it to + apisecret: The API key for the username + label: The label to use for the message (optional) + + Returns: True if the message was delivered, False otherwise + """ + + # tidy up the message msg = msg.strip() + + # build up the URL and parameters apiurl = API_URL % {"username": username, "secret": apisecret} data = urllib.urlencode({ "title": title, "label": label, - "msg": msg + "msg": msg.encode(sickbeard.SYS_ENCODING) }) + # send the request to notifo try: data = urllib.urlopen(apiurl, data) result = json.load(data) - except IOError: + + except ValueError, e: + logger.log(u"Unable to decode JSON: "+data, logger.ERROR) + return False + + except IOError, e: + logger.log(u"Error trying to communicate with notifo: "+ex(e), logger.ERROR) return False data.close() + # see if it worked if result["status"] != "success" or result["response_message"] != "OK": return False else: @@ -59,14 +83,37 @@ class NotifoNotifier: def notify_snatch(self, ep_name, title="Snatched:"): + """ + Send a notification that an episode was snatched + + ep_name: The name of the episode that was snatched + title: The title of the notification (optional) + """ if sickbeard.NOTIFO_NOTIFY_ONSNATCH: self._notifyNotifo(title, ep_name) def notify_download(self, ep_name, title="Completed:"): + """ + Send a notification that an episode was downloaded + + ep_name: The name of the episode that was downloaded + title: The title of the notification (optional) + """ if sickbeard.NOTIFO_NOTIFY_ONDOWNLOAD: self._notifyNotifo(title, ep_name) - def _notifyNotifo(self, title, message=None, username=None, apisecret=None, force=False): + def _notifyNotifo(self, title, message, username=None, apisecret=None, force=False): + """ + Send a notifo notification based on the SB settings. + + title: The title to send + message: The message to send + username: The username to send it to (optional, default to the username in the config) + apisecret: The API key to use (optional, defaults to the api key in the config) + force: If true then the notification will be sent even if it is disabled in the config (optional) + + Returns: True if the message succeeded, false otherwise + """ if not sickbeard.USE_NOTIFO and not force: logger.log("Notification for Notifo not enabled, skipping this notification", logger.DEBUG) return False diff --git a/sickbeard/notifiers/plex.py b/sickbeard/notifiers/plex.py index 2ca071e6546ea989fa24fb0bcf71e67f82bac739..d282667359f4af0f1b76f612beaeac9058723c46 100644 --- a/sickbeard/notifiers/plex.py +++ b/sickbeard/notifiers/plex.py @@ -34,10 +34,10 @@ class PLEXNotifier(XBMCNotifier): def notify_download(self, ep_name): if sickbeard.PLEX_NOTIFY_ONDOWNLOAD: self._notifyXBMC(ep_name, common.notifyStrings[common.NOTIFY_DOWNLOAD]) - - def test_notify(self, host, username, password): - return self._notifyXBMC("Testing Plex notifications from Sick Beard", "Test Notification", host, username, password, force=True) + def test_notify(self, host, username, password): + return self._update_library() + def update_library(self): if sickbeard.PLEX_UPDATE_LIBRARY: self._update_library() diff --git a/sickbeard/notifiers/prowl.py b/sickbeard/notifiers/prowl.py index 01e5447de4d87f74703653679582e02c916046e8..709ea95ca5c3a297242ed2238cffc5152d461d76 100644 --- a/sickbeard/notifiers/prowl.py +++ b/sickbeard/notifiers/prowl.py @@ -16,9 +16,17 @@ # You should have received a copy of the GNU General Public License # along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. -from httplib import HTTPSConnection +from httplib import HTTPSConnection, HTTPException from urllib import urlencode +try: + # this only exists in 2.6 + from ssl import SSLError +except ImportError: + # make a fake one since I don't know what it is supposed to be in 2.5 + class SSLError(Exception): + pass + import sickbeard from sickbeard import logger, common @@ -64,10 +72,14 @@ class ProwlNotifier: 'description': message.encode('utf-8'), 'priority': prowl_priority } - http_handler.request("POST", - "/publicapi/add", - headers = {'Content-type': "application/x-www-form-urlencoded"}, - body = urlencode(data)) + try: + http_handler.request("POST", + "/publicapi/add", + headers = {'Content-type': "application/x-www-form-urlencoded"}, + body = urlencode(data)) + except (SSLError, HTTPException): + logger.log(u"Prowl notification failed.", logger.ERROR) + return False response = http_handler.getresponse() request_status = response.status @@ -81,4 +93,4 @@ class ProwlNotifier: logger.log(u"Prowl notification failed.", logger.ERROR) return False -notifier = ProwlNotifier \ No newline at end of file +notifier = ProwlNotifier diff --git a/sickbeard/notifiers/pushover.py b/sickbeard/notifiers/pushover.py new file mode 100644 index 0000000000000000000000000000000000000000..5814688f58e7b3883b4dd3160991e03feda8c945 --- /dev/null +++ b/sickbeard/notifiers/pushover.py @@ -0,0 +1,143 @@ +# Author: Marvin Pinto <me@marvinp.ca> +# Author: Dennis Lutter <lad1337@gmail.com> +# Author: Aaron Bieber <deftly@gmail.com> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +import urllib, urllib2 +import time + +import sickbeard + +from sickbeard import logger +from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD +from sickbeard.exceptions import ex + +API_URL = "https://api.pushover.net/1/messages.json" +API_KEY = "OKCXmkvHN1syU2e8xvpefTnyvVWGv5" + +class PushoverNotifier: + + def test_notify(self, userKey=None): + return self._sendPushover("This is a test notification from SickBeard", 'Test', userKey ) + + def _sendPushover(self, msg, title, userKey=None ): + """ + Sends a pushover notification to the address provided + + msg: The message to send (unicode) + title: The title of the message + userKey: The pushover user id to send the message to (or to subscribe with) + + returns: True if the message succeeded, False otherwise + """ + + if not userKey: + userKey = sickbeard.PUSHOVER_USERKEY + + # build up the URL and parameters + msg = msg.strip() + curUrl = API_URL + + data = urllib.urlencode({ + 'token': API_KEY, + 'title': title, + 'user': userKey, + 'message': msg.encode('utf-8'), + 'timestamp': int(time.time()) + }) + + + # send the request to pushover + try: + req = urllib2.Request(curUrl) + handle = urllib2.urlopen(req, data) + handle.close() + + except urllib2.URLError, e: + # if we get an error back that doesn't have an error code then who knows what's really happening + if not hasattr(e, 'code'): + logger.log("Pushover notification failed." + ex(e), logger.ERROR) + return False + else: + logger.log("Pushover notification failed. Error code: " + str(e.code), logger.WARNING) + + # HTTP status 404 if the provided email address isn't a Pushover user. + if e.code == 404: + logger.log("Username is wrong/not a pushover email. Pushover will send an email to it", logger.WARNING) + return False + + # For HTTP status code 401's, it is because you are passing in either an invalid token, or the user has not added your service. + elif e.code == 401: + + # If the user has already added your service, we'll return an HTTP status code of 401. + if subscribe: + logger.log("Already subscribed to service", logger.ERROR) + # i dont know if this is true or false ... its neither but i also dont know how we got here in the first place + return False + + #HTTP status 401 if the user doesn't have the service added + else: + subscribeNote = self._sendPushover(msg, title, userKey ) + if subscribeNote: + logger.log("Subscription send", logger.DEBUG) + return True + else: + logger.log("Subscription could not be send", logger.ERROR) + return False + + # If you receive an HTTP status code of 400, it is because you failed to send the proper parameters + elif e.code == 400: + logger.log("Wrong data sent to pushover", logger.ERROR) + return False + + logger.log("Pushover notification successful.", logger.DEBUG) + return True + + def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]): + if sickbeard.PUSHOVER_NOTIFY_ONSNATCH: + self._notifyPushover(title, ep_name) + + + def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]): + if sickbeard.PUSHOVER_NOTIFY_ONDOWNLOAD: + self._notifyPushover(title, ep_name) + + def _notifyPushover(self, title, message, userKey=None ): + """ + Sends a pushover notification based on the provided info or SB config + + title: The title of the notification to send + message: The message string to send + userKey: The userKey to send the notification to + """ + + if not sickbeard.USE_PUSHOVER and not force: + logger.log("Notification for Pushover not enabled, skipping this notification", logger.DEBUG) + return False + + # if no userKey was given then use the one from the config + if not userKey: + userKey = sickbeard.PUSHOVER_USERKEY + + logger.log("Sending notification for " + message, logger.DEBUG) + + # self._sendPushover(message, title, userKey) + self._sendPushover(message, title) + return True + +notifier = PushoverNotifier diff --git a/sickbeard/notifiers/pytivo.py b/sickbeard/notifiers/pytivo.py new file mode 100644 index 0000000000000000000000000000000000000000..3f4aa30b482d62c4c8e58ced9db45a410fd0d319 --- /dev/null +++ b/sickbeard/notifiers/pytivo.py @@ -0,0 +1,99 @@ +# Author: Nic Wolfe <nic@wolfeden.ca> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +import os +import sickbeard + +from urllib import urlencode +from urllib2 import Request, urlopen, URLError + +from sickbeard import logger +from sickbeard import encodingKludge as ek + +class pyTivoNotifier: + + def notify_snatch(self, ep_name): + pass + + def notify_download(self, ep_name): + pass + + def update_library(self, ep_obj): + + # Values from config + + if not sickbeard.USE_PYTIVO: + return False + + host = sickbeard.PYTIVO_HOST + shareName = sickbeard.PYTIVO_SHARE_NAME + tsn = sickbeard.PYTIVO_TIVO_NAME + + # There are two more values required, the container and file. + # + # container: The share name, show name and season + # + # file: The file name + # + # Some slicing and dicing of variables is required to get at these values. + # + # There might be better ways to arrive at the values, but this is the best I have been able to + # come up with. + # + + + # Calculated values + + showPath = ep_obj.show.location + showName = ep_obj.show.name + rootShowAndSeason = ek.ek(os.path.dirname, ep_obj.location) + absPath = ep_obj.location + + # Some show names have colons in them which are illegal in a path location, so strip them out. + # (Are there other characters?) + showName = showName.replace(":","") + + root = showPath.replace(showName, "") + showAndSeason = rootShowAndSeason.replace(root, "") + + container = shareName + "/" + showAndSeason + file = "/" + absPath.replace(root, "") + + # Finally create the url and make request + requestUrl = "http://" + host + "/TiVoConnect?" + urlencode( {'Command':'Push', 'Container':container, 'File':file, 'tsn':tsn} ) + + logger.log(u"pyTivo notification: Requesting " + requestUrl) + + request = Request( requestUrl ) + + try: + response = urlopen(request) #@UnusedVariable + except URLError, e: + if hasattr(e, 'reason'): + logger.log(u"pyTivo notification: Error, failed to reach a server") + logger.log(u"'Error reason: " + e.reason) + return False + elif hasattr(e, 'code'): + logger.log(u"pyTivo notification: Error, the server couldn't fulfill the request") + logger.log(u"Error code: " + e.code) + return False + else: + logger.log(u"pyTivo notification: Successfully requested transfer of file") + return True + +notifier = pyTivoNotifier diff --git a/sickbeard/notifiers/trakt.py b/sickbeard/notifiers/trakt.py new file mode 100644 index 0000000000000000000000000000000000000000..d5bcb6515071b12bc900690bea5748b66d22b53f --- /dev/null +++ b/sickbeard/notifiers/trakt.py @@ -0,0 +1,155 @@ +# Author: Dieter Blomme <dieterblomme@gmail.com> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + + +import urllib2 + +from hashlib import sha1 + +try: + import json +except ImportError: + from lib import simplejson as json + +import sickbeard + +from sickbeard import logger + +class TraktNotifier: + """ + A "notifier" for trakt.tv which keeps track of what has and hasn't been added to your library. + """ + + def notify_snatch(self, ep_name): + pass + + def notify_download(self, ep_name): + pass + + def update_library(self, ep_obj): + """ + Sends a request to trakt indicating that the given episode is part of our library. + + ep_obj: The TVEpisode object to add to trakt + """ + + if sickbeard.USE_TRAKT: + method = "show/episode/library/" + method += "%API%" + + # URL parameters + data = { + 'tvdb_id': ep_obj.show.tvdbid, + 'title': ep_obj.show.name, + 'year': ep_obj.show.startyear, + 'episodes': [ { + 'season': ep_obj.season, + 'episode': ep_obj.episode + } ] + } + + if data is not None: + self._notifyTrakt(method, None, None, None, data) + + def test_notify(self, api, username, password): + """ + Sends a test notification to trakt with the given authentication info and returns a boolean + representing success. + + api: The api string to use + username: The username to use + password: The password to use + + Returns: True if the request succeeded, False otherwise + """ + + method = "account/test/" + method += "%API%" + return self._notifyTrakt(method, api, username, password, {}) + + def _username(self): + return sickbeard.TRAKT_USERNAME + + def _password(self): + return sickbeard.TRAKT_PASSWORD + + def _api(self): + return sickbeard.TRAKT_API + + def _use_me(self): + return sickbeard.USE_TRAKT + + def _notifyTrakt(self, method, api, username, password, data = {}): + """ + A generic method for communicating with trakt. Uses the method and data provided along + with the auth info to send the command. + + method: The URL to use at trakt, relative, no leading slash. + api: The API string to provide to trakt + username: The username to use when logging in + password: The unencrypted password to use when logging in + + Returns: A boolean representing success + """ + logger.log("trakt_notifier: Call method " + method, logger.DEBUG) + + # if the API isn't given then use the config API + if not api: + api = self._api() + + # if the username isn't given then use the config username + if not username: + username = self._username() + + # if the password isn't given then use the config password + if not password: + password = self._password() + password = sha1(password).hexdigest() + + # replace the API string with what we found + method = method.replace("%API%", api) + + data["username"] = username + data["password"] = password + + # take the URL params and make a json object out of them + encoded_data = json.dumps(data); + + # request the URL from trakt and parse the result as json + try: + logger.log("trakt_notifier: Calling method http://api.trakt.tv/" + method + ", with data" + encoded_data, logger.DEBUG) + stream = urllib2.urlopen("http://api.trakt.tv/" + method, encoded_data) + resp = stream.read() + + resp = json.loads(resp) + + if ("error" in resp): + raise Exception(resp["error"]) + + except (IOError): + logger.log("trakt_notifier: Failed calling method", logger.ERROR) + return False + + if (resp["status"] == "success"): + logger.log("trakt_notifier: Succeeded calling method. Result: " + resp["message"], logger.DEBUG) + return True + + logger.log("trakt_notifier: Failed calling method", logger.ERROR) + return False + +notifier = TraktNotifier diff --git a/sickbeard/notifiers/xbmc.py b/sickbeard/notifiers/xbmc.py index 6adc3d861282df07d538b5d06128574db21f646c..6d2e74fd0bd61a4b78c1b89e37e8f44d6e9fdd63 100644 --- a/sickbeard/notifiers/xbmc.py +++ b/sickbeard/notifiers/xbmc.py @@ -103,7 +103,7 @@ class XBMCNotifier: logger.log(u"Contacting XBMC via url: " + url, logger.DEBUG) handle = urllib2.urlopen(req) - response = handle.read() + response = handle.read().decode(sickbeard.SYS_ENCODING) logger.log(u"response: " + response, logger.DEBUG) except IOError, e: logger.log(u"Warning: Couldn't contact XBMC HTTP server at " + fixStupidEncodings(host) + ": " + ex(e)) @@ -141,7 +141,7 @@ class XBMCNotifier: def _update_library(self, host, showName=None): - if not sickbeard.USE_XBMC: + if not self._use_me(): logger.log("Notifications for XBMC not enabled, skipping library update", logger.DEBUG) return False @@ -191,7 +191,7 @@ class XBMCNotifier: for path in paths: # Don't need it double-encoded, gawd this is dumb - unEncPath = urllib.unquote(path.text) + unEncPath = urllib.unquote(path.text).decode(sickbeard.SYS_ENCODING) logger.log(u"XBMC Updating " + showName + " on " + host + " at " + unEncPath, logger.DEBUG) updateCommand = {'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video, %s)' % (unEncPath)} request = self._sendToXBMC(updateCommand, host) diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index 687f01a550d5cc175081b5a7809d7fd4ceded810..7539779df6faa901867ef4106663f6374067a91b 100755 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -45,6 +45,9 @@ from sickbeard.name_parser.parser import NameParser, InvalidNameException from lib.tvdb_api import tvdb_api, tvdb_exceptions class PostProcessor(object): + """ + A class which will process a media file according to the post processing settings in the config. + """ EXISTS_LARGER = 1 EXISTS_SAME = 2 @@ -52,6 +55,12 @@ class PostProcessor(object): DOESNT_EXIST = 4 def __init__(self, file_path, nzb_name = None): + """ + Creates a new post processor with the given file path and optionally an NZB name. + + file_path: The path to the file to be processed + nzb_name: The name of the NZB which resulted in this file being downloaded (optional) + """ # absolute path to the folder that is being processed self.folder_path = ek.ek(os.path.dirname, ek.ek(os.path.abspath, file_path)) @@ -74,10 +83,28 @@ class PostProcessor(object): self.log = '' def _log(self, message, level=logger.MESSAGE): + """ + A wrapper for the internal logger which also keeps track of messages and saves them to a string for later. + + message: The string to log (unicode) + level: The log level to use (optional) + """ logger.log(message, level) self.log += message + '\n' def _checkForExistingFile(self, existing_file): + """ + Checks if a file exists already and if it does whether it's bigger or smaller than + the file we are post processing + + existing_file: The file to compare to + + Returns: + DOESNT_EXIST if the file doesn't exist + EXISTS_LARGER if the file exists and is larger than the file we are post processing + EXISTS_SMALLER if the file exists and is smaller than the file we are post processing + EXISTS_SAME if the file exists and is the same size as the file we are post processing + """ if not existing_file: self._log(u"There is no existing file so there's no worries about replacing it", logger.DEBUG) @@ -104,6 +131,13 @@ class PostProcessor(object): return PostProcessor.DOESNT_EXIST def _list_associated_files(self, file_path): + """ + For a given file path searches for files with the same name but different extension and returns them. + + file_path: The file to check for associated files + + Returns: A list containing all files which are associated to the given file + """ if not file_path: return [] @@ -125,10 +159,17 @@ class PostProcessor(object): return file_path_list def _delete(self, file_path, associated_files=False): + """ + Deletes the file and optionall all associated files. + + file_path: The file to delete + associated_files: True to delete all files which differ only by extension, False to leave them + """ if not file_path: return + # figure out which files we want to delete if associated_files: file_list = self._list_associated_files(file_path) else: @@ -138,6 +179,7 @@ class PostProcessor(object): self._log(u"There were no files associated with "+file_path+", not deleting anything", logger.DEBUG) return + # delete the file and any other files which we want to delete for cur_file in file_list: self._log(u"Deleting file "+cur_file, logger.DEBUG) if ek.ek(os.path.isfile, cur_file): @@ -145,8 +187,11 @@ class PostProcessor(object): def _combined_file_operation (self, file_path, new_path, new_base_name, associated_files=False, action=None): """ - file_path: The full path of the media file to copy - new_path: Destination path where we want to copy the file to + Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, + and optionally move associated files too. + + file_path: The full path of the media file to act on + new_path: Destination path where we want to move/copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) @@ -228,6 +273,14 @@ class PostProcessor(object): self._combined_file_operation(file_path, new_path, new_base_name, associated_files, action=_int_copy) def _find_ep_destination_folder(self, ep_obj): + """ + Finds the final folder where the episode should go. If season folders are enabled + and an existing season folder can be found then it is used, otherwise a new one + is created in accordance with the config settings. If season folders aren't enabled + then this function should simply return the show dir. + + ep_obj: The TVEpisode object to figure out the location for + """ # if we're supposed to put it in a season folder then figure out what folder to use season_folder = '' @@ -271,10 +324,12 @@ class PostProcessor(object): to_return = (None, None, []) + # if we don't have either of these then there's nothing to use to search the history for anyway if not self.nzb_name and not self.folder_name: self.in_history = False return to_return + # make a list of possible names to use in the search names = [] if self.nzb_name: names.append(self.nzb_name) @@ -285,6 +340,7 @@ class PostProcessor(object): myDB = db.DBConnection() + # search the database for a possible match and return immediately if we find one for curName in names: sql_results = myDB.select("SELECT * FROM history WHERE resource LIKE ?", [re.sub("[\.\-\ ]", "_", curName)]) @@ -306,6 +362,8 @@ class PostProcessor(object): """ Takes a name and tries to figure out a show, season, and episode from it. + name: A string which we want to analyze to determine show info from (unicode) + Returns a (tvdb_id, season, [episodes]) tuple. The first two may be None and episodes may be [] if none were found. """ @@ -486,6 +544,16 @@ class PostProcessor(object): return (tvdb_id, season, episodes) def _get_ep_obj(self, tvdb_id, season, episodes): + """ + Retrieve the TVEpisode object requested. + + tvdb_id: The TVDBID of the show (int) + season: The season of the episode (int) + episodes: A list of episodes to find (list of ints) + + If the episode(s) can be found then a TVEpisode object with the correct related eps will + be instantiated and returned. If the episode can't be found then None will be returned. + """ show_obj = None @@ -496,6 +564,7 @@ class PostProcessor(object): except exceptions.MultipleShowObjectsException: raise #TODO: later I'll just log this, for now I want to know about it ASAP + # if we can't find the show then there's nothing we can really do if not show_obj: self._log(u"This show isn't in your list, you need to add it to SB before post-processing an episode", logger.ERROR) raise exceptions.PostProcessingFailed() @@ -513,6 +582,7 @@ class PostProcessor(object): self._log(u"Unable to create episode: "+ex(e), logger.DEBUG) raise exceptions.PostProcessingFailed() + # associate all the episodes together under a single root episode if root_ep == None: root_ep = curEp root_ep.relatedEps = [] @@ -522,22 +592,34 @@ class PostProcessor(object): return root_ep def _get_quality(self, ep_obj): + """ + Determines the quality of the file that is being post processed, first by checking if it is directly + available in the TVEpisode's status or otherwise by parsing through the data available. + + ep_obj: The TVEpisode object related to the file we are post processing + + Returns: A quality value found in common.Quality + """ ep_quality = common.Quality.UNKNOWN - # make sure the quality is set right before we continue + # if there is a quality available in the status then we don't need to bother guessing from the filename if ep_obj.status in common.Quality.SNATCHED + common.Quality.SNATCHED_PROPER: oldStatus, ep_quality = common.Quality.splitCompositeStatus(ep_obj.status) #@UnusedVariable if ep_quality != common.Quality.UNKNOWN: self._log(u"The old status had a quality in it, using that: "+common.Quality.qualityStrings[ep_quality], logger.DEBUG) return ep_quality + # nzb name is the most reliable if it exists, followed by folder name and lastly file name name_list = [self.nzb_name, self.folder_name, self.file_name] # search all possible names for our new quality, in case the file or dir doesn't have it for cur_name in name_list: + + # some stuff might be None at this point still if not cur_name: continue + ep_quality = common.Quality.nameQuality(cur_name) self._log(u"Looking up quality for name "+cur_name+u", got "+common.Quality.qualityStrings[ep_quality], logger.DEBUG) @@ -556,8 +638,17 @@ class PostProcessor(object): return ep_quality def _run_extra_scripts(self, ep_obj): + """ + Executes any extra scripts defined in the config. + + ep_obj: The object to use when calling the extra script + """ for curScriptName in sickbeard.EXTRA_SCRIPTS: + + # generate a safe command line string to execute the script and provide all the parameters script_cmd = shlex.split(curScriptName) + [ep_obj.location, self.file_path, str(ep_obj.show.tvdbid), str(ep_obj.season), str(ep_obj.episode), str(ep_obj.airdate)] + + # use subprocess to run the command and capture output self._log(u"Executing command "+str(script_cmd)) self._log(u"Absolute path to script: "+ek.ek(os.path.abspath, script_cmd[0]), logger.DEBUG) try: @@ -568,6 +659,15 @@ class PostProcessor(object): self._log(u"Unable to run extra_script: "+ex(e)) def _is_priority(self, ep_obj, new_ep_quality): + """ + Determines if the episode is a priority download or not (if it is expected). Episodes which are expected + (snatched) or larger than the existing episode are priority, others are not. + + ep_obj: The TVEpisode object in question + new_ep_quality: The quality of the episode that is being processed + + Returns: True if the episode is priority, False otherwise. + """ # if SB downloaded this on purpose then this is a priority download if self.in_history or ep_obj.status in common.Quality.SNATCHED + common.Quality.SNATCHED_PROPER: @@ -594,6 +694,9 @@ class PostProcessor(object): self._log(u"Processing "+self.file_path+" ("+str(self.nzb_name)+")") + if os.path.isdir( self.file_path ): + self._log(u"File "+self.file_path+" seems to be a directory") + return False # reset per-file stuff self.in_history = False @@ -712,11 +815,14 @@ class PostProcessor(object): notifiers.plex_notifier.update_library() # do the library update for synoindex - notifiers.synoindex_notifier.update_library(ep_obj) - - # run extra_scripts + notifiers.synoindex_notifier.update_library(ep_obj) + + # do the library update for trakt + notifiers.trakt_notifier.update_library(ep_obj) + + # do the library update for pyTivo + notifiers.pytivo_notifier.update_library(ep_obj) + self._run_extra_scripts(ep_obj) return True - - # e diff --git a/sickbeard/processTV.py b/sickbeard/processTV.py index 95425f2c6a6d2607974fdfcf7f7380ac8d01e29c..57c41569d90da55df1320343479633feaaa47267 100644 --- a/sickbeard/processTV.py +++ b/sickbeard/processTV.py @@ -35,6 +35,13 @@ def logHelper (logMessage, logLevel=logger.MESSAGE): return logMessage + u"\n" def processDir (dirName, nzbName=None, recurse=False): + """ + Scans through the files in dirName and processes whatever media files it finds + + dirName: The folder name to look in + nzbName: The NZB name which resulted in this folder being downloaded + recurse: Boolean for whether we should descend into subfolders or not + """ returnStr = '' diff --git a/sickbeard/providers/__init__.py b/sickbeard/providers/__init__.py old mode 100644 new mode 100755 index 7f01e092f6f76a472ba69270011663951770b36e..71991a7932d32711a72404f06592c512345a216a --- a/sickbeard/providers/__init__.py +++ b/sickbeard/providers/__init__.py @@ -19,10 +19,11 @@ __all__ = ['ezrss', 'tvtorrents', 'nzbmatrix', - 'nzbs_org', + 'nzbs_org_old', 'nzbsrus', 'womble', 'newzbin', + 'btn', ] import sickbeard @@ -96,7 +97,7 @@ def makeNewznabProvider(configString): return newProvider def getDefaultNewznabProviders(): - return 'Sick Beard Index|http://momo.sickbeard.com/|0|0' + return 'Sick Beard Index|http://momo.sickbeard.com/|0|0!!!NZBs.org|http://beta.nzbs.org/||0' def getProviderModule(name): @@ -105,7 +106,7 @@ def getProviderModule(name): if name in __all__ and prefix+name in sys.modules: return sys.modules[prefix+name] else: - return None + raise Exception("Can't find "+prefix+name+" in "+repr(sys.modules)) def getProviderClass(id): diff --git a/sickbeard/providers/btn.py b/sickbeard/providers/btn.py new file mode 100644 index 0000000000000000000000000000000000000000..c332506536c1526b3b19521686e8d07448559674 --- /dev/null +++ b/sickbeard/providers/btn.py @@ -0,0 +1,72 @@ +# Author: Nic Wolfe <nic@wolfeden.ca> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +import sickbeard +import generic + +from sickbeard import logger +from sickbeard import tvcache + +class BTNProvider(generic.TorrentProvider): + + def __init__(self): + + generic.TorrentProvider.__init__(self, "BTN") + + self.supportsBacklog = False + + self.cache = BTNCache(self) + + self.url = 'http://broadcasthe.net/' + + def isEnabled(self): + return sickbeard.BTN + + def imageName(self): + return 'btn.gif' + +class BTNCache(tvcache.TVCache): + + def __init__(self, provider): + + tvcache.TVCache.__init__(self, provider) + + # only poll BTN every 15 minutes max + self.minTime = 15 + + def _getRSSData(self): + url = 'https://broadcasthe.net/feeds.php?feed=torrents_all&user='+ sickbeard.BTN_USER_ID +'&auth='+ sickbeard.BTN_AUTH_TOKEN +'&passkey='+ sickbeard.BTN_PASSKEY +'&authkey='+ sickbeard.BTN_AUTHKEY + logger.log(u"BTN cache update URL: "+ url, logger.DEBUG) + + data = self.provider.getURL(url) + + return data + + def _parseItem(self, item): + + (title, url) = self.provider._get_title_and_url(item) + + if not title or not url: + logger.log(u"The XML returned from the BTN RSS feed is incomplete, this result is unusable", logger.ERROR) + return + + logger.log(u"Adding item from RSS to cache: "+title, logger.DEBUG) + + self._addCacheEntry(title, url) + +provider = BTNProvider() \ No newline at end of file diff --git a/sickbeard/providers/ezrss.py b/sickbeard/providers/ezrss.py index 9a645181357c4ada2ed16d66b3f4a97d272a53f4..3345607377761c4dda3dfb58e83e10a3159fe740 100644 --- a/sickbeard/providers/ezrss.py +++ b/sickbeard/providers/ezrss.py @@ -18,8 +18,7 @@ import urllib import re - -import xml.etree.cElementTree as etree +from xml.dom.minidom import parseString import sickbeard import generic @@ -27,7 +26,7 @@ import generic from sickbeard.common import Quality from sickbeard import logger from sickbeard import tvcache -from sickbeard.helpers import sanitizeSceneName +from sickbeard.helpers import sanitizeSceneName, get_xml_text from sickbeard.exceptions import ex class EZRSSProvider(generic.TorrentProvider): @@ -41,8 +40,6 @@ class EZRSSProvider(generic.TorrentProvider): self.cache = EZRSSCache(self) self.url = 'https://www.ezrss.it/' - - self.ezrss_ns = 'http://xmlns.ezrss.it/0.1/' def isEnabled(self): return sickbeard.EZRSS @@ -52,8 +49,12 @@ class EZRSSProvider(generic.TorrentProvider): def getQuality(self, item): - filename = item.findtext('{%s}torrent/{%s}fileName' %(self.ezrss_ns,self.ezrss_ns)) + torrent_node = item.getElementsByTagName('torrent')[0] + filename_node = torrent_node.getElementsByTagName('fileName')[0] + filename = get_xml_text(filename_node) + quality = Quality.nameQuality(filename) + return quality def findSeasonResults(self, show, season): @@ -115,8 +116,8 @@ class EZRSSProvider(generic.TorrentProvider): return [] try: - responseSoup = etree.ElementTree(etree.XML(data)) - items = responseSoup.getiterator('item') + parsedXML = parseString(data) + items = parsedXML.getElementsByTagName('item') except Exception, e: logger.log(u"Error trying to load EZRSS RSS feed: "+ex(e), logger.ERROR) logger.log(u"RSS data: "+data, logger.DEBUG) @@ -137,9 +138,11 @@ class EZRSSProvider(generic.TorrentProvider): return results def _get_title_and_url(self, item): - title = item.findtext('title') - url = item.findtext('link').replace('&','&') - filename = item.findtext('{%s}torrent/{%s}fileName' %(self.ezrss_ns,self.ezrss_ns)) + (title, url) = generic.TorrentProvider._get_title_and_url(self, item) + + torrent_node = item.getElementsByTagName('torrent')[0] + filename_node = torrent_node.getElementsByTagName('fileName')[0] + filename = get_xml_text(filename_node) new_title = self._extract_name_from_filename(filename) if new_title: @@ -178,14 +181,7 @@ class EZRSSCache(tvcache.TVCache): def _parseItem(self, item): - title = item.findtext('title') - url = item.findtext('link') - filename = item.findtext('{%s}torrent/{%s}fileName' %(self.provider.ezrss_ns,self.provider.ezrss_ns)) - - new_title = self.provider._extract_name_from_filename(filename) - if new_title: - title = new_title - logger.log(u"Extracted the name "+title+" from the torrent link", logger.DEBUG) + (title, url) = self.provider._get_title_and_url(item) if not title or not url: logger.log(u"The XML returned from the EZRSS RSS feed is incomplete, this result is unusable", logger.ERROR) diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index ba28542d8d7c7671d32cdc2245d44b8793de989c..6bd7be0520cf0f115d03754f8fd73f312bbd1349 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -180,7 +180,14 @@ class GenericProvider: return self.cache.findNeededEpisodes() def getQuality(self, item): - title = item.findtext('title') + """ + Figures out the quality of the given RSS item node + + item: An xml.dom.minidom.Node representing the <item> tag of the RSS feed + + Returns a Quality value obtained from the node's data + """ + (title, url) = self._get_title_and_url(item) #@UnusedVariable quality = Quality.nameQuality(title) return quality @@ -194,10 +201,20 @@ class GenericProvider: return [] def _get_title_and_url(self, item): - title = item.findtext('title') - url = item.findtext('link') - if url: - url = url.replace('&','&') + """ + Retrieves the title and URL data from the item XML node + + item: An xml.dom.minidom.Node representing the <item> tag of the RSS feed + + Returns: A tuple containing two strings representing title and URL respectively + """ + title = helpers.get_xml_text(item.getElementsByTagName('title')[0]) + try: + url = helpers.get_xml_text(item.getElementsByTagName('link')[0]) + if url: + url = url.replace('&','&') + except IndexError: + url = None return (title, url) diff --git a/sickbeard/providers/newzbin.py b/sickbeard/providers/newzbin.py index e995204fdf108b6138b89f23a4645a7bd706b674..c0b2360a666e7450b4919a04f0c7340a3d9f966c 100644 --- a/sickbeard/providers/newzbin.py +++ b/sickbeard/providers/newzbin.py @@ -22,7 +22,7 @@ import sys import time import urllib -import xml.etree.cElementTree as etree +from xml.dom.minidom import parseString from datetime import datetime, timedelta import sickbeard @@ -33,6 +33,7 @@ from sickbeard import classes, logger, helpers, exceptions, show_name_helpers from sickbeard import tvcache from sickbeard.common import Quality from sickbeard.exceptions import ex +from lib.dateutil.parser import parse as parseDate class NewzbinDownloader(urllib.FancyURLopener): @@ -72,28 +73,24 @@ class NewzbinProvider(generic.NZBProvider): self.cache = NewzbinCache(self) - self.url = 'https://www.newzbin.com/' - - self.NEWZBIN_NS = 'http://www.newzbin.com/DTD/2007/feeds/report/' + self.url = 'https://www.newzbin2.es/' self.NEWZBIN_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S %Z' - def _report(self, name): - return '{'+self.NEWZBIN_NS+'}'+name - def isEnabled(self): return sickbeard.NEWZBIN def getQuality(self, item): - attributes = item.find(self._report('attributes')) + attributes = item.getElementsByTagName('report:attributes')[0] attr_dict = {} - for attribute in attributes.getiterator(self._report('attribute')): - cur_attr = attribute.attrib['type'] + for attribute in attributes.getElementsByTagName('report:attribute'): + cur_attr = attribute.getAttribute('type') + cur_attr_value = helpers.get_xml_text(attribute) if cur_attr not in attr_dict: - attr_dict[cur_attr] = [attribute.text] + attr_dict[cur_attr] = [cur_attr_value] else: - attr_dict[cur_attr].append(attribute.text) + attr_dict[cur_attr].append(cur_attr_value) logger.log("Finding quality of item based on attributes "+str(attr_dict), logger.DEBUG) @@ -275,21 +272,26 @@ class NewzbinProvider(generic.NZBProvider): item_list = [] try: - responseSoup = etree.ElementTree(etree.XML(data)) - items = responseSoup.getiterator('item') + parsedXML = parseString(data) + items = parsedXML.getElementsByTagName('item') except Exception, e: logger.log("Error trying to load Newzbin RSS feed: "+ex(e), logger.ERROR) return [] for cur_item in items: - title = cur_item.findtext('title') - if title == 'Feed Error': + title = helpers.get_xml_text(cur_item.getElementsByTagName('title')[0]) + if title == 'Feeds Error': raise exceptions.AuthException("The feed wouldn't load, probably because of invalid auth info") if sickbeard.USENET_RETENTION is not None: try: - post_date = datetime.strptime(cur_item.findtext('{http://www.newzbin.com/DTD/2007/feeds/report/}postdate'), self.NEWZBIN_DATE_FORMAT) + dateString = helpers.get_xml_text(cur_item.getElementsByTagName('report:postdate')[0]) + # use the parse (imported as parseDate) function from the dateutil lib + # and we have to remove the timezone info from it because the retention_date will not have one + # and a comparison of them is not possible + post_date = parseDate(dateString).replace(tzinfo=None) retention_date = datetime.now() - timedelta(days=sickbeard.USENET_RETENTION) if post_date < retention_date: + logger.log(u"Date "+str(post_date)+" is out of retention range, skipping", logger.DEBUG) continue except Exception, e: logger.log("Error parsing date from Newzbin RSS feed: " + str(e), logger.ERROR) @@ -334,6 +336,10 @@ class NewzbinProvider(generic.NZBProvider): return data + def _checkAuth(self): + if sickbeard.NEWZBIN_USERNAME in (None, "") or sickbeard.NEWZBIN_PASSWORD in (None, ""): + raise exceptions.AuthException("Newzbin authentication details are empty, check your config") + class NewzbinCache(tvcache.TVCache): def __init__(self, provider): @@ -341,7 +347,7 @@ class NewzbinCache(tvcache.TVCache): tvcache.TVCache.__init__(self, provider) # only poll Newzbin every 10 mins max - self.minTime = 10 + self.minTime = 1 def _getRSSData(self): @@ -351,8 +357,7 @@ class NewzbinCache(tvcache.TVCache): def _parseItem(self, item): - title = item.findtext('title') - url = item.findtext('link') + (title, url) = self.provider._get_title_and_url(item) if title == 'Feeds Error': logger.log("There's an error in the feed, probably bad auth info", logger.DEBUG) diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index 020f18e6088e3b9f61fd483cae65cef36925a296..d6f0243179c5976cea547e53f896fa8a976f0992 100644 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -23,7 +23,7 @@ import datetime import re import os -import xml.etree.cElementTree as etree +from xml.dom.minidom import parseString import sickbeard import generic @@ -150,7 +150,27 @@ class NewznabProvider(generic.NZBProvider): def _doGeneralSearch(self, search_string): return self._doSearch({'q': search_string}) - #def _doSearch(self, show, season=None, episode=None, search=None): + def _checkAuthFromData(self, data): + + try: + parsedXML = parseString(data) + except Exception: + return False + + if parsedXML.documentElement.tagName == 'error': + code = parsedXML.documentElement.getAttribute('code') + if code == '100': + raise exceptions.AuthException("Your API key for "+self.name+" is incorrect, check your config.") + elif code == '101': + raise exceptions.AuthException("Your account on "+self.name+" has been suspended, contact the administrator.") + elif code == '102': + raise exceptions.AuthException("Your account isn't allowed to use the API on "+self.name+", contact the administrator") + else: + logger.log(u"Unknown error given from "+self.name+": "+parsedXML.documentElement.getAttribute('description'), logger.ERROR) + return False + + return True + def _doSearch(self, search_params, show=None): params = {"t": "tvsearch", @@ -158,6 +178,10 @@ class NewznabProvider(generic.NZBProvider): "limit": 100, "cat": '5030,5040'} + # hack this in for now + if self.getID() == 'nzbs_org': + params['cat'] += ',5070,5090' + if search_params: params.update(search_params) @@ -178,41 +202,29 @@ class NewznabProvider(generic.NZBProvider): data = '<?xml version="1.0" encoding="ISO-8859-1" ?>' + data try: - responseSoup = etree.ElementTree(etree.XML(data)) - items = responseSoup.getiterator('item') + parsedXML = parseString(data) + items = parsedXML.getElementsByTagName('item') except Exception, e: logger.log(u"Error trying to load "+self.name+" RSS feed: "+ex(e), logger.ERROR) logger.log(u"RSS data: "+data, logger.DEBUG) return [] - if responseSoup.getroot().tag == 'error': - code = responseSoup.getroot().get('code') - if code == '100': - raise exceptions.AuthException("Your API key for "+self.name+" is incorrect, check your config.") - elif code == '101': - raise exceptions.AuthException("Your account on "+self.name+" has been suspended, contact the administrator.") - elif code == '102': - raise exceptions.AuthException("Your account isn't allowed to use the API on "+self.name+", contact the administrator") - else: - logger.log(u"Unknown error given from "+self.name+": "+responseSoup.getroot().get('description'), logger.ERROR) - return [] + if not self._checkAuthFromData(data): + return [] - if responseSoup.getroot().tag != 'rss': + if parsedXML.documentElement.tagName != 'rss': logger.log(u"Resulting XML from "+self.name+" isn't RSS, not parsing it", logger.ERROR) return [] results = [] for curItem in items: - title = curItem.findtext('title') - url = curItem.findtext('link') + (title, url) = self._get_title_and_url(curItem) if not title or not url: logger.log(u"The XML returned from the "+self.name+" RSS feed is incomplete, this result is unusable: "+data, logger.ERROR) continue - url = url.replace('&','&') - results.append(curItem) return results @@ -251,6 +263,10 @@ class NewznabCache(tvcache.TVCache): "age": sickbeard.USENET_RETENTION, "cat": '5040,5030'} + # hack this in for now + if self.provider.getID() == 'nzbs_org': + params['cat'] += ',5070,5090' + if self.provider.key: params['apikey'] = self.provider.key @@ -268,21 +284,4 @@ class NewznabCache(tvcache.TVCache): def _checkAuth(self, data): - try: - responseSoup = etree.ElementTree(etree.XML(data)) - except Exception: - return True - - if responseSoup.getroot().tag == 'error': - code = responseSoup.getroot().get('code') - if code == '100': - raise exceptions.AuthException("Your API key for "+self.provider.name+" is incorrect, check your config.") - elif code == '101': - raise exceptions.AuthException("Your account on "+self.provider.name+" has been suspended, contact the administrator.") - elif code == '102': - raise exceptions.AuthException("Your account isn't allowed to use the API on "+self.provider.name+", contact the administrator") - else: - logger.log(u"Unknown error given from "+self.provider.name+": "+responseSoup.getroot().get('description'), logger.ERROR) - return False - - return True + return self.provider._checkAuthFromData(data) diff --git a/sickbeard/providers/nzbmatrix.py b/sickbeard/providers/nzbmatrix.py index 316f6cad48f1e146476e718fdafc0f41ab3ed723..daa02df650abbe80b8a992892b6ce6807a5a1e04 100644 --- a/sickbeard/providers/nzbmatrix.py +++ b/sickbeard/providers/nzbmatrix.py @@ -21,12 +21,12 @@ import time import urllib import datetime -import xml.etree.cElementTree as etree +from xml.dom.minidom import parseString import sickbeard import generic -from sickbeard import classes, logger, show_name_helpers +from sickbeard import classes, logger, show_name_helpers, helpers from sickbeard import tvcache from sickbeard.exceptions import ex @@ -65,7 +65,7 @@ class NZBMatrixProvider(generic.NZBProvider): term = "\""+term+"\"" params = {"term": term, - "age": sickbeard.USENET_RETENTION, + "maxage": sickbeard.USENET_RETENTION, "page": "download", "username": sickbeard.NZBMATRIX_USERNAME, "apikey": sickbeard.NZBMATRIX_APIKEY, @@ -74,11 +74,15 @@ class NZBMatrixProvider(generic.NZBProvider): "ssl": 1, "scenename": 1} + # don't allow it to be missing + if not params['maxage']: + params['maxage'] = '0' + # if the show is a documentary use those cats on nzbmatrix if show and show.genre and 'documentary' in show.genre.lower(): params['subcat'] = params['subcat'] + ',53,9' - searchURL = "http://rss.nzbmatrix.com/rss.php?" + urllib.urlencode(params) + searchURL = "https://rss.nzbmatrix.com/rss.php?" + urllib.urlencode(params) logger.log(u"Search string: " + searchURL, logger.DEBUG) @@ -91,8 +95,8 @@ class NZBMatrixProvider(generic.NZBProvider): return [] try: - responseSoup = etree.ElementTree(etree.XML(searchResult)) - items = responseSoup.getiterator('item') + parsedXML = parseString(searchResult) + items = parsedXML.getElementsByTagName('item') except Exception, e: logger.log(u"Error trying to load NZBMatrix RSS feed: "+ex(e), logger.ERROR) return [] @@ -100,8 +104,7 @@ class NZBMatrixProvider(generic.NZBProvider): results = [] for curItem in items: - title = curItem.findtext('title') - url = curItem.findtext('link') + (title, url) = self._get_title_and_url(curItem) if title == 'Error: No Results Found For Your Search': continue @@ -121,10 +124,11 @@ class NZBMatrixProvider(generic.NZBProvider): for curResult in self._doSearch("(PROPER,REPACK)"): - title = curResult.findtext('title') - url = curResult.findtext('link').replace('&','&') + (title, url) = self._get_title_and_url(curResult) + + description_node = curResult.getElementsByTagName('description')[0] + descriptionStr = helpers.get_xml_text(description_node) - descriptionStr = curResult.findtext('description') dateStr = re.search('<b>Added:</b> (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d)', descriptionStr).group(1) if not dateStr: logger.log(u"Unable to figure out the date for entry "+title+", skipping it") @@ -150,16 +154,21 @@ class NZBMatrixCache(tvcache.TVCache): def _getRSSData(self): # get all records since the last timestamp - url = "http://rss.nzbmatrix.com/rss.php?" + url = "https://rss.nzbmatrix.com/rss.php?" urlArgs = {'page': 'download', 'username': sickbeard.NZBMATRIX_USERNAME, 'apikey': sickbeard.NZBMATRIX_APIKEY, + 'maxage': sickbeard.USENET_RETENTION, 'english': 1, 'ssl': 1, 'scenename': 1, 'subcat': '6,41'} + # don't allow it to be missing + if not urlArgs['maxage']: + urlArgs['maxage'] = '0' + url += urllib.urlencode(urlArgs) logger.log(u"NZBMatrix cache update URL: "+ url, logger.DEBUG) diff --git a/sickbeard/providers/nzbs_org.py b/sickbeard/providers/nzbs_org_old.py similarity index 84% rename from sickbeard/providers/nzbs_org.py rename to sickbeard/providers/nzbs_org_old.py index 45e033891d9b63b304c8d597c3be0afc458e725f..d7f5eb10a9919287e2138de6f4dc59b34b2c83c3 100644 --- a/sickbeard/providers/nzbs_org.py +++ b/sickbeard/providers/nzbs_org_old.py @@ -23,12 +23,12 @@ import re import time import urllib -import xml.etree.cElementTree as etree +from xml.dom.minidom import parseString import sickbeard import generic -from sickbeard import classes, show_name_helpers +from sickbeard import classes, show_name_helpers, helpers from sickbeard import exceptions, logger from sickbeard import tvcache @@ -38,7 +38,7 @@ class NZBsProvider(generic.NZBProvider): def __init__(self): - generic.NZBProvider.__init__(self, "NZBs.org") + generic.NZBProvider.__init__(self, "NZBs.org Old") self.supportsBacklog = True @@ -85,8 +85,8 @@ class NZBsProvider(generic.NZBProvider): return [] try: - responseSoup = etree.ElementTree(etree.XML(data)) - items = responseSoup.getiterator('item') + parsedXML = parseString(data) + items = parsedXML.getElementsByTagName('item') except Exception, e: logger.log(u"Error trying to load NZBs.org RSS feed: "+ex(e), logger.ERROR) return [] @@ -94,15 +94,12 @@ class NZBsProvider(generic.NZBProvider): results = [] for curItem in items: - title = curItem.findtext('title') - url = curItem.findtext('link') + (title, url) = self._get_title_and_url(curItem) if not title or not url: logger.log(u"The XML returned from the NZBs.org RSS feed is incomplete, this result is unusable: "+data, logger.ERROR) continue - url = url.replace('&','&') - if "&i=" not in url and "&h=" not in url: raise exceptions.AuthException("The NZBs.org result URL has no auth info which means your UID/hash are incorrect, check your config") @@ -118,14 +115,19 @@ class NZBsProvider(generic.NZBProvider): for curResult in self._doSearch(curString): - match = re.search('(\w{3}, \d{1,2} \w{3} \d{4} \d\d:\d\d:\d\d) [\+\-]\d{4}', curResult.findtext('pubDate')) + (title, url) = self._get_title_and_url(curResult) + + pubDate_node = curResult.getElementsByTagName('pubDate')[0] + pubDate = helpers.get_xml_text(pubDate_node) + + match = re.search('(\w{3}, \d{1,2} \w{3} \d{4} \d\d:\d\d:\d\d) [\+\-]\d{4}', pubDate) if not match: continue resultDate = datetime.datetime.strptime(match.group(1), "%a, %d %b %Y %H:%M:%S") if date == None or resultDate > date: - results.append(classes.Proper(curResult.findtext('title'), curResult.findtext('link'), resultDate)) + results.append(classes.Proper(title, url, resultDate)) return results diff --git a/sickbeard/providers/tvtorrents.py b/sickbeard/providers/tvtorrents.py index fa5e24a2d0106e39588b518681367c591ae897b6..853cf6016b57fdd96f20704a07017312e5fd6dd3 100644 --- a/sickbeard/providers/tvtorrents.py +++ b/sickbeard/providers/tvtorrents.py @@ -16,11 +16,12 @@ # You should have received a copy of the GNU General Public License # along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. -import xml.etree.cElementTree as etree +from xml.dom.minidom import parseString import sickbeard import generic +from sickbeard import helpers from sickbeard import logger from sickbeard import tvcache @@ -61,21 +62,23 @@ class TvTorrentsCache(tvcache.TVCache): data = self.provider.getURL(url) - xml_content = etree.fromstring(data) - description = xml_content.findtext('channel/description') + parsedXML = parseString(data) + channel = parsedXML.getElementsByTagName('channel')[0] + description = channel.getElementsByTagName('description')[0] - if "User can't be found" in description: + description_text = helpers.get_xml_text(description) + + if "User can't be found" in description_text: logger.log(u"TvTorrents invalid digest, check your config", logger.ERROR) - if "Invalid Hash" in description: + if "Invalid Hash" in description_text: logger.log(u"TvTorrents invalid hash, check your config", logger.ERROR) return data def _parseItem(self, item): - title = item.findtext('title') - url = item.findtext('link') + (title, url) = self.provider._get_title_and_url(item) if not title or not url: logger.log(u"The XML returned from the TvTorrents RSS feed is incomplete, this result is unusable", logger.ERROR) diff --git a/sickbeard/providers/womble.py b/sickbeard/providers/womble.py index 0591b58fdc8c65cca2ca35c90ab51c82af156565..13b433422aa46221bbafea28f5ac0d6dc5cd1eb2 100644 --- a/sickbeard/providers/womble.py +++ b/sickbeard/providers/womble.py @@ -16,8 +16,6 @@ # You should have received a copy of the GNU General Public License # along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. - - import sickbeard from sickbeard import logger diff --git a/sickbeard/sab.py b/sickbeard/sab.py index 80515ed9038ffb7af286c686c2d7b774035cc0c6..880e222d30c5018ceb1b816e04d87e1feffebde1 100644 --- a/sickbeard/sab.py +++ b/sickbeard/sab.py @@ -25,15 +25,24 @@ import sickbeard from lib import MultipartPostHandler import urllib2, cookielib +try: + import json +except ImportError: + from lib import simplejson as json from sickbeard.common import USER_AGENT from sickbeard import logger from sickbeard.exceptions import ex def sendNZB(nzb): + """ + Sends an NZB to SABnzbd via the API. + + nzb: The NZBSearchResult object to send to SAB + """ + # set up a dict with the URL params in it params = {} - if sickbeard.SAB_USERNAME != None: params['ma_username'] = sickbeard.SAB_USERNAME if sickbeard.SAB_PASSWORD != None: @@ -54,7 +63,7 @@ def sendNZB(nzb): if nzb.provider.getID() == 'newzbin': id = nzb.provider.getIDFromURL(nzb.url) if not id: - logger.log("Unable to send NZB to sab, can't find ID in URL "+str(nzb.url), logger.ERROR) + logger.log("Unable to send NZB to sab, can't find ID in URL " + str(nzb.url), logger.ERROR) return False params['mode'] = 'addid' params['name'] = id @@ -65,23 +74,23 @@ def sendNZB(nzb): # if we get a raw data result we want to upload it to SAB elif nzb.resultType == "nzbdata": params['mode'] = 'addfile' - multiPartParams = {"nzbfile": (nzb.name+".nzb", nzb.extraInfo[0])} + multiPartParams = {"nzbfile": (nzb.name + ".nzb", nzb.extraInfo[0])} url = sickbeard.SAB_HOST + "api?" + urllib.urlencode(params) logger.log(u"Sending NZB to SABnzbd") - logger.log(u"URL: " + url, logger.DEBUG) try: - + # if we have the URL to an NZB then we've built up the SAB API URL already so just call it if nzb.resultType == "nzb": - f = urllib.urlopen(url) + f = urllib.urlopen(url) + + # if we are uploading the NZB data to SAB then we need to build a little POST form and send it elif nzb.resultType == "nzbdata": cookies = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler.MultipartPostHandler) - req = urllib2.Request(url, multiPartParams, headers={'User-Agent': USER_AGENT}) @@ -89,31 +98,36 @@ def sendNZB(nzb): f = opener.open(req) except (EOFError, IOError), e: - logger.log(u"Unable to connect to SAB: "+ex(e), logger.ERROR) + logger.log(u"Unable to connect to SAB: " + ex(e), logger.ERROR) return False except httplib.InvalidURL, e: - logger.log(u"Invalid SAB host, check your config: "+ex(e), logger.ERROR) + logger.log(u"Invalid SAB host, check your config: " + ex(e), logger.ERROR) return False + # this means we couldn't open the connection or something just as bad if f == None: logger.log(u"No data returned from SABnzbd, NZB not sent", logger.ERROR) return False + # if we opened the URL connection then read the result from SAB try: result = f.readlines() except Exception, e: logger.log(u"Error trying to get result from SAB, NZB not sent: " + ex(e), logger.ERROR) return False + # SAB shouldn't return a blank result, this most likely (but not always) means that it timed out and didn't recieve the NZB if len(result) == 0: logger.log(u"No data returned from SABnzbd, NZB not sent", logger.ERROR) return False + # massage the result a little bit sabText = result[0].strip() logger.log(u"Result text from SAB: " + sabText, logger.DEBUG) + # do some crude parsing of the result text to determine what SAB said if sabText == "ok": logger.log(u"NZB sent to SAB successfully", logger.DEBUG) return True @@ -123,3 +137,93 @@ def sendNZB(nzb): else: logger.log(u"Unknown failure sending NZB to sab. Return text is: " + sabText, logger.ERROR) return False + +def _checkSabResponse(f): + try: + result = f.readlines() + except Exception, e: + logger.log(u"Error trying to get result from SAB" + ex(e), logger.ERROR) + return False, "Error from SAB" + + if len(result) == 0: + logger.log(u"No data returned from SABnzbd, NZB not sent", logger.ERROR) + return False, "No data from SAB" + + sabText = result[0].strip() + sabJson = {} + try: + sabJson = json.loads(sabText) + except ValueError, e: + pass + + if sabText == "Missing authentication": + logger.log(u"Incorrect username/password sent to SAB", logger.ERROR) + return False, "Incorrect username/password sent to SAB" + elif 'error' in sabJson: + logger.log(sabJson['error'], logger.ERROR) + return False, sabJson['error'] + else: + return True, sabText + +def _sabURLOpenSimple(url): + try: + f = urllib.urlopen(url) + except (EOFError, IOError), e: + logger.log(u"Unable to connect to SAB: " + ex(e), logger.ERROR) + return False, "Unable to connect" + except httplib.InvalidURL, e: + logger.log(u"Invalid SAB host, check your config: " + ex(e), logger.ERROR) + return False, "Invalid SAB host" + if f == None: + logger.log(u"No data returned from SABnzbd", logger.ERROR) + return False, "No data returned from SABnzbd" + else: + return True, f + +def getSabAccesMethod(host=None, username=None, password=None, apikey=None): + url = host + "api?mode=auth" + + result, f = _sabURLOpenSimple(url) + if not result: + return False, f + + result, sabText = _checkSabResponse(f) + if not result: + return False, sabText + + return True, sabText + +def testAuthentication(host=None, username=None, password=None, apikey=None): + """ + Sends a simple API request to SAB to determine if the given connection information is connect + + host: The host where SAB is running (incl port) + username: The username to use for the HTTP request + password: The password to use for the HTTP request + apikey: The API key to provide to SAB + + Returns: A tuple containing the success boolean and a message + """ + + # build up the URL parameters + params = {} + params['mode'] = 'queue' + params['output'] = 'json' + params['ma_username'] = username + params['ma_password'] = password + params['apikey'] = apikey + url = host + "api?" + urllib.urlencode(params) + + # send the test request + logger.log(u"SABnzbd test URL: " + url, logger.DEBUG) + result, f = _sabURLOpenSimple(url) + if not result: + return False, f + + # check the result and determine if it's good or not + result, sabText = _checkSabResponse(f) + if not result: + return False, sabText + + return True, "Success" + diff --git a/sickbeard/search.py b/sickbeard/search.py index 79879224a867089f96877fb45bc7690b7f44d4e3..52b1e12352a27ab00baf5dac25b8cf2c44f101f5 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -85,7 +85,7 @@ def _downloadResult(result): return False if newResult: - ui.notifications.message('Episode <b>%s</b> snatched from <b>%s</b>' % (result.name, resProvider.name)) + ui.notifications.message('Episode snatched','<b>%s</b> snatched from <b>%s</b>' % (result.name, resProvider.name)) return newResult diff --git a/sickbeard/show_name_helpers.py b/sickbeard/show_name_helpers.py index dc244dad15f98ce5b31b9fcc0bc895c56beeca03..ed2c0a35c8306d4ca7845246f1aafdf7706a9b76 100644 --- a/sickbeard/show_name_helpers.py +++ b/sickbeard/show_name_helpers.py @@ -206,6 +206,8 @@ def isGoodResult(name, show, log=True): for curName in set(showNames): escaped_name = re.sub('\\\\[\\s.-]', '\W+', re.escape(curName)) + if show.startyear: + escaped_name += "(?:\W+"+str(show.startyear)+")?" curRegex = '^' + escaped_name + '\W+(?:(?:S\d[\dE._ -])|(?:\d\d?x)|(?:\d{4}\W\d\d\W\d\d)|(?:(?:part|pt)[\._ -]?(\d|[ivx]))|Season\W+\d+\W+|E\d+\W+)' if log: logger.log(u"Checking if show "+name+" matches " + curRegex, logger.DEBUG) diff --git a/sickbeard/tv.py b/sickbeard/tv.py index e75ca2ad5103c7a6f58002520155e195c9665400..bcf2b45e1c272c37493978c6fbb182a3c0f5d30f 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -231,10 +231,16 @@ class TVShow(object): for curResult in sqlResults: + deleteEp = False + curSeason = int(curResult["season"]) curEpisode = int(curResult["episode"]) if curSeason not in cachedSeasons: - cachedSeasons[curSeason] = cachedShow[curSeason] + try: + cachedSeasons[curSeason] = cachedShow[curSeason] + except tvdb_exceptions.tvdb_seasonnotfound, e: + logger.log(u"Error when trying to load the episode from TVDB: "+e.message, logger.WARNING) + deleteEp = True if not curSeason in scannedEps: scannedEps[curSeason] = {} @@ -243,6 +249,11 @@ class TVShow(object): try: curEp = self.getEpisode(curSeason, curEpisode) + + # if we found out that the ep is no longer on TVDB then delete it from our database too + if deleteEp: + curEp.deleteEpisode() + curEp.loadFromDB(curSeason, curEpisode) curEp.loadFromTVDB(tvapi=t, cachedSeason=cachedSeasons[curSeason]) scannedEps[curSeason][curEpisode] = True @@ -1258,7 +1269,7 @@ class TVEpisode(object): def createMetaFiles(self, force=False): - if not os.path.isdir(self.show._location): + if not ek.ek(os.path.isdir, self.show._location): logger.log(str(self.show.tvdbid) + ": The show dir is missing, not bothering to try to create metadata") return diff --git a/sickbeard/tvcache.py b/sickbeard/tvcache.py index 75a154838fc51db73b90ec536a0a54e30b7dae23..3f5bba7967c45bb08df3088deb228ce08377d037 100644 --- a/sickbeard/tvcache.py +++ b/sickbeard/tvcache.py @@ -30,7 +30,8 @@ from sickbeard import helpers, exceptions, show_name_helpers from sickbeard import name_cache from sickbeard.exceptions import ex -import xml.etree.cElementTree as etree +#import xml.etree.cElementTree as etree +import xml.dom.minidom from lib.tvdb_api import tvdb_api, tvdb_exceptions @@ -111,14 +112,14 @@ class TVCache(): raise exceptions.AuthException("Your authentication info for "+self.provider.name+" is incorrect, check your config") try: - responseSoup = etree.ElementTree(etree.XML(data)) - items = responseSoup.getiterator('item') + parsedXML = xml.dom.minidom.parseString(data) + items = parsedXML.getElementsByTagName('item') except Exception, e: logger.log(u"Error trying to load "+self.provider.name+" RSS feed: "+ex(e), logger.ERROR) logger.log(u"Feed contents: "+repr(data), logger.DEBUG) return [] - if responseSoup.getroot().tag != 'rss': + if parsedXML.documentElement.tagName != 'rss': logger.log(u"Resulting XML from "+self.provider.name+" isn't RSS, not parsing it", logger.ERROR) return [] @@ -131,8 +132,8 @@ class TVCache(): def _parseItem(self, item): - title = item.findtext('title') - url = item.findtext('link') + title = helpers.get_xml_text(item.getElementsByTagName('title')[0]) + url = helpers.get_xml_text(item.getElementsByTagName('link')[0]) self._checkItemAuth(title, url) diff --git a/sickbeard/versionChecker.py b/sickbeard/versionChecker.py index 472d1b1b4981a9cd8ddde8a54c7a6089918d0ae2..7f81b6809f8718dd633471a0fc0377683e2f8b37 100644 --- a/sickbeard/versionChecker.py +++ b/sickbeard/versionChecker.py @@ -28,7 +28,7 @@ import urllib, urllib2 import zipfile, tarfile from urllib2 import URLError -from lib.pygithub import github +import gh_api as github class CheckVersion(): """ @@ -111,28 +111,31 @@ class WindowsUpdateManager(UpdateManager): self._newest_version = None self.gc_url = 'http://code.google.com/p/sickbeard/downloads/list' + self.version_url = 'https://raw.github.com/midgetspy/Sick-Beard/windows_binaries/updates.txt' def _find_installed_version(self): return int(sickbeard.version.SICKBEARD_VERSION[6:]) def _find_newest_version(self, whole_link=False): """ - Checks google code for the newest Windows binary build. Returns either the + Checks git for the newest Windows binary build. Returns either the build number or the entire build URL depending on whole_link's value. whole_link: If True, returns the entire URL to the release. If False, it returns only the build number. default: False """ - regex = "http://sickbeard.googlecode.com/files/SickBeard\-win32\-alpha\-build(\d+)(?:\.\d+)?\.zip" + regex = ".*SickBeard\-win32\-alpha\-build(\d+)(?:\.\d+)?\.zip" - svnFile = urllib.urlopen(self.gc_url) + svnFile = urllib.urlopen(self.version_url) for curLine in svnFile.readlines(): - match = re.search(regex, curLine) + logger.log(u"checking line "+curLine, logger.DEBUG) + match = re.match(regex, curLine) if match: + logger.log(u"found a match", logger.DEBUG) if whole_link: - return match.group(0) + return curLine.strip() else: return int(match.group(1)) @@ -142,7 +145,9 @@ class WindowsUpdateManager(UpdateManager): self._cur_version = self._find_installed_version() self._newest_version = self._find_newest_version() - if self._newest_version > self._cur_version: + logger.log(u"newest version: "+repr(self._newest_version), logger.DEBUG) + + if self._newest_version and self._newest_version > self._cur_version: return True def set_newest_text(self): @@ -154,6 +159,8 @@ class WindowsUpdateManager(UpdateManager): new_link = self._find_newest_version(True) + logger.log(u"new_link: " + repr(new_link), logger.DEBUG) + if not new_link: logger.log(u"Unable to find a new version link on google code, not updating") return False @@ -290,13 +297,13 @@ class GitUpdateManager(UpdateManager): gh = github.GitHub() # find newest commit - for curCommit in gh.commits.forBranch('midgetspy', 'Sick-Beard', version.SICKBEARD_VERSION): + for curCommit in gh.commits('midgetspy', 'Sick-Beard', version.SICKBEARD_VERSION): if not self._newest_commit_hash: - self._newest_commit_hash = curCommit.id + self._newest_commit_hash = curCommit['sha'] if not self._cur_commit_hash: break - if curCommit.id == self._cur_commit_hash: + if curCommit['sha'] == self._cur_commit_hash: break self._num_commits_behind += 1 @@ -306,7 +313,7 @@ class GitUpdateManager(UpdateManager): def set_newest_text(self): # if we're up to date then don't set this - if self._num_commits_behind == 35: + if self._num_commits_behind == 100: message = "or else you're ahead of master" elif self._num_commits_behind > 0: @@ -424,7 +431,7 @@ class SourceUpdateManager(GitUpdateManager): Downloads the latest source tarball from github and installs it over the existing version. """ - tar_download_url = 'http://github.com/midgetspy/Sick-Beard/tarball/'+version.SICKBEARD_VERSION + tar_download_url = 'https://github.com/midgetspy/Sick-Beard/tarball/'+version.SICKBEARD_VERSION sb_update_dir = os.path.join(sickbeard.PROG_DIR, 'sb-update') version_path = os.path.join(sickbeard.PROG_DIR, 'version.txt') diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py new file mode 100644 index 0000000000000000000000000000000000000000..5154cd85d3e615d4c4927b92b25c92a9b9cfc24f --- /dev/null +++ b/sickbeard/webapi.py @@ -0,0 +1,2412 @@ +# Author: Dennis Lutter <lad1337@gmail.com> +# Author: Jonathon Saine <thezoggy@gmail.com> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import with_statement + +import os +import time +import urllib +import datetime +import threading +import re +import traceback + +import cherrypy +import sickbeard +import webserve +from sickbeard import db, logger, exceptions, history, ui, helpers +from sickbeard.exceptions import ex +from sickbeard import encodingKludge as ek +from sickbeard import search_queue +from sickbeard.common import SNATCHED, SNATCHED_PROPER, DOWNLOADED, SKIPPED, UNAIRED, IGNORED, ARCHIVED, WANTED, UNKNOWN +from common import ANY, Quality, qualityPresetStrings, statusStrings +from sickbeard import image_cache +from lib.tvdb_api import tvdb_api, tvdb_exceptions +try: + import json +except ImportError: + from lib import simplejson as json + +import xml.etree.cElementTree as etree + +dateFormat = "%Y-%m-%d" +dateTimeFormat = "%Y-%m-%d %H:%M" + + +RESULT_SUCCESS = 10 # only use inside the run methods +RESULT_FAILURE = 20 # only use inside the run methods +RESULT_TIMEOUT = 30 # not used yet :( +RESULT_ERROR = 40 # only use outside of the run methods ! +RESULT_FATAL = 50 # only use in Api.default() ! this is the "we encountered an internal error" error +RESULT_DENIED = 60 # only use in Api.default() ! this is the acces denied error +result_type_map = {RESULT_SUCCESS: "success", + RESULT_FAILURE: "failure", + RESULT_TIMEOUT: "timeout", + RESULT_ERROR: "error", + RESULT_FATAL: "fatal", + RESULT_DENIED: "denied", + } +# basically everything except RESULT_SUCCESS / success is bad + + +class Api: + """ api class that returns json results """ + version = 0.2 + intent = 4 + + @cherrypy.expose + def default(self, *args, **kwargs): + + self.apiKey = sickbeard.API_KEY + access, accessMsg, args, kwargs = self._grand_access(self.apiKey, args, kwargs) + + # set the output callback + # default json + outputCallbackDict = {'default': self._out_as_json, + 'image': lambda x: x['image'], + } + + # do we have acces ? + if access: + logger.log(accessMsg, logger.DEBUG) + else: + logger.log(accessMsg, logger.WARNING) + return outputCallbackDict['default'](_responds(RESULT_DENIED, msg=accessMsg)) + + # set the original call_dispatcher as the local _call_dispatcher + _call_dispatcher = call_dispatcher + # if profile was set wrap "_call_dispatcher" in the profile function + if 'profile' in kwargs: + from lib.profilehooks import profile + _call_dispatcher = profile(_call_dispatcher, immediate=True) + del kwargs["profile"] + + # if debug was set call the "_call_dispatcher" + if 'debug' in kwargs: + outDict = _call_dispatcher(args, kwargs) # this way we can debug the cherry.py traceback in the browser + del kwargs["debug"] + else:# if debug was not set we wrap the "call_dispatcher" in a try block to assure a json output + try: + outDict = _call_dispatcher(args, kwargs) + except Exception, e: # real internal error oohhh nooo :( + logger.log(u"API :: " + ex(e), logger.ERROR) + errorData = {"error_msg": ex(e), + "args": args, + "kwargs": kwargs} + outDict = _responds(RESULT_FATAL, errorData, "SickBeard encountered an internal error! Please report to the Devs") + + if 'outputType' in outDict: + outputCallback = outputCallbackDict[outDict['outputType']] + else: + outputCallback = outputCallbackDict['default'] + + return outputCallback(outDict) + + @cherrypy.expose + def builder(self): + """ expose the api-builder template """ + t = webserve.PageTemplate(file="apiBuilder.tmpl") + + def titler(x): + if not x: + return x + if x.lower().startswith('a '): + x = x[2:] + elif x.lower().startswith('the '): + x = x[4:] + return x + + t.sortedShowList = sorted(sickbeard.showList, lambda x, y: cmp(titler(x.name), titler(y.name))) + + myDB = db.DBConnection(row_type="dict") + seasonSQLResults = {} + episodeSQLResults = {} + + for curShow in t.sortedShowList: + seasonSQLResults[curShow.tvdbid] = myDB.select("SELECT DISTINCT season FROM tv_episodes WHERE showid = ? ORDER BY season DESC", [curShow.tvdbid]) + + for curShow in t.sortedShowList: + episodeSQLResults[curShow.tvdbid] = myDB.select("SELECT DISTINCT season,episode FROM tv_episodes WHERE showid = ? ORDER BY season DESC, episode DESC", [curShow.tvdbid]) + + t.seasonSQLResults = seasonSQLResults + t.episodeSQLResults = episodeSQLResults + + myDB.connection.close() + if len(sickbeard.API_KEY) == 32: + t.apikey = sickbeard.API_KEY + else: + t.apikey = "api key not generated" + + return webserve._munge(t) + + def _out_as_json(self, dict): + """ set cherrypy response to json """ + response = cherrypy.response + response.headers['Content-Type'] = 'application/json;charset=UTF-8' + try: + out = json.dumps(dict, indent=self.intent, sort_keys=True) + except Exception, e: # if we fail to generate the output fake a error + logger.log(u"API :: " + traceback.format_exc(), logger.DEBUG) + out = '{"result":"' + result_type_map[RESULT_ERROR] + '", "message": "error while composing output: "' + ex(e) + '"}' + return out + + def _grand_access(self, realKey, args, kwargs): + """ validate api key and log result """ + remoteIp = cherrypy.request.remote.ip + apiKey = kwargs.get("apikey", None) + if not apiKey: + if args: # if we have keyless vars we assume first one is the api key, always ! + apiKey = args[0] + args = args[1:] # remove the apikey from the args tuple + else: + del kwargs["apikey"] + + if sickbeard.USE_API != True: + msg = u"API :: " + remoteIp + " - SB API Disabled. ACCESS DENIED" + return False, msg, args, kwargs + elif apiKey == realKey: + msg = u"API :: " + remoteIp + " - gave correct API KEY. ACCESS GRANTED" + return True, msg, args, kwargs + elif not apiKey: + msg = u"API :: " + remoteIp + " - gave NO API KEY. ACCESS DENIED" + return False, msg, args, kwargs + else: + msg = u"API :: " + remoteIp + " - gave WRONG API KEY " + apiKey + ". ACCESS DENIED" + return False, msg, args, kwargs + + +def call_dispatcher(args, kwargs): + """ calls the appropriate CMD class + looks for a cmd in args and kwargs + or calls the TVDBShorthandWrapper when the first args element is a number + or returns an error that there is no such cmd + """ + logger.log(u"API :: all args: '" + str(args) + "'", logger.DEBUG) + logger.log(u"API :: all kwargs: '" + str(kwargs) + "'", logger.DEBUG) + #logger.log(u"API :: dateFormat: '" + str(dateFormat) + "'", logger.DEBUG) + + cmds = None + if args: + cmds = args[0] + args = args[1:] + + if "cmd" in kwargs: + cmds = kwargs["cmd"] + del kwargs["cmd"] + + outDict = {} + if cmds != None: + cmds = cmds.split("|") + multiCmds = bool(len(cmds) > 1) + for cmd in cmds: + curArgs, curKwargs = filter_params(cmd, args, kwargs) + cmdIndex = None + if len(cmd.split("_")) > 1: # was a index used for this cmd ? + cmd, cmdIndex = cmd.split("_") # this gives us the clear cmd and the index + + logger.log(u"API :: " + cmd + ": curKwargs " + str(curKwargs), logger.DEBUG) + if not (multiCmds and cmd in ('show.getposter', 'show.getbanner')): # skip these cmd while chaining + try: + if cmd in _functionMaper: + curOutDict = _functionMaper.get(cmd)(curArgs, curKwargs).run() # get the cmd class, init it and run() + elif _is_int(cmd): + curOutDict = TVDBShorthandWrapper(curArgs, curKwargs, cmd).run() + else: + curOutDict = _responds(RESULT_ERROR, "No such cmd: '" + cmd + "'") + except ApiError, e: # Api errors that we raised, they are harmless + curOutDict = _responds(RESULT_ERROR, msg=ex(e)) + else: # if someone chained one of the forbiden cmds they will get an error for this one cmd + curOutDict = _responds(RESULT_ERROR, msg="The cmd '" + cmd + "' is not supported while chaining") + + if multiCmds: + # note: if multiple same cmds are issued but one has not an index defined it will override all others + # or the other way around, this depends on the order of the cmds + # this is not a bug + if cmdIndex is None: # do we need a index dict for this cmd ? + outDict[cmd] = curOutDict + else: + if not cmd in outDict: + outDict[cmd] = {} + outDict[cmd][cmdIndex] = curOutDict + else: + outDict = curOutDict + + if multiCmds: # if we had multiple cmds we have to wrap it in a response dict + outDict = _responds(RESULT_SUCCESS, outDict) + else: # index / no cmd given + outDict = CMD_SickBeard(args, kwargs).run() + + return outDict + + +def filter_params(cmd, args, kwargs): + """ return only params kwargs that are for cmd + and rename them to a clean version (remove "<cmd>_") + args are shared across all cmds + + all args and kwarks are lowerd + + cmd are separated by "|" e.g. &cmd=shows|future + kwargs are namespaced with "." e.g. show.tvdbid=101501 + if a karg has no namespace asing it anyways (global) + + full e.g. + /api?apikey=1234&cmd=show.seasonlist_asd|show.seasonlist_2&show.seasonlist_asd.tvdbid=101501&show.seasonlist_2.tvdbid=79488&sort=asc + + two calls of show.seasonlist + one has the index "asd" the other one "2" + the "tvdbid" kwargs / params have the indexed cmd as a namspace + and the kwarg / param "sort" is a used as a global + """ + curArgs = [] + for arg in args: + curArgs.append(arg.lower()) + curArgs = tuple(curArgs) + + curKwargs = {} + for kwarg in kwargs: + if kwarg.find(cmd + ".") == 0: + cleanKey = kwarg.rpartition(".")[2] + curKwargs[cleanKey] = kwargs[kwarg].lower() + elif not "." in kwarg: # the kwarg was not namespaced therefore a "global" + curKwargs[kwarg] = kwargs[kwarg] + return curArgs, curKwargs + + +class ApiCall(object): + _help = {"desc": "No help message available. Please tell the devs that a help msg is missing for this cmd"} + + def __init__(self, args, kwargs): + # missing + try: + if self._missing: + self.run = self.return_missing + except AttributeError: + pass + # help + if 'help' in kwargs: + self.run = self.return_help + + def run(self): + # override with real output function in subclass + return {} + + def return_help(self): + try: + if self._requiredParams: + pass + except AttributeError: + self._requiredParams = [] + try: + if self._optionalParams: + pass + except AttributeError: + self._optionalParams = [] + + for paramDict, type in [(self._requiredParams, "requiredParameters"), + (self._optionalParams, "optionalParameters")]: + + if type in self._help: + for paramName in paramDict: + if not paramName in self._help[type]: + self._help[type][paramName] = {} + if paramDict[paramName]["allowedValues"]: + self._help[type][paramName]["allowedValues"] = paramDict[paramName]["allowedValues"] + else: + self._help[type][paramName]["allowedValues"] = "see desc" + self._help[type][paramName]["defaultValue"] = paramDict[paramName]["defaultValue"] + + elif paramDict: + for paramName in paramDict: + self._help[type] = {} + self._help[type][paramName] = paramDict[paramName] + else: + self._help[type] = {} + msg = "No description available" + if "desc" in self._help: + msg = self._help["desc"] + del self._help["desc"] + return _responds(RESULT_SUCCESS, self._help, msg) + + def return_missing(self): + if len(self._missing) == 1: + msg = "The required parameter: '" + self._missing[0] + "' was not set" + else: + msg = "The required parameters: '" + "','".join(self._missing) + "' where not set" + return _responds(RESULT_ERROR, msg=msg) + + def check_params(self, args, kwargs, key, default, required, type, allowedValues): + # TODO: explain this + """ function to check passed params for the shorthand wrapper + and to detect missing/required param + """ + missing = True + orgDefault = default + + if type == "bool": + allowedValues = [0, 1] + + if args: + default = args[0] + missing = False + args = args[1:] + if kwargs.get(key): + default = kwargs.get(key) + missing = False + if required: + try: + self._missing + self._requiredParams.append(key) + except AttributeError: + self._missing = [] + self._requiredParams = {} + self._requiredParams[key] = {"allowedValues": allowedValues, + "defaultValue": orgDefault} + if missing and key not in self._missing: + self._missing.append(key) + else: + try: + self._optionalParams[key] = {"allowedValues": allowedValues, + "defaultValue": orgDefault} + except AttributeError: + self._optionalParams = {} + self._optionalParams[key] = {"allowedValues": allowedValues, + "defaultValue": orgDefault} + + if default: + default = self._check_param_type(default, key, type) + if type == "bool": + type = [] + self._check_param_value(default, key, allowedValues) + + return default, args + + def _check_param_type(self, value, name, type): + """ checks if value can be converted / parsed to type + will raise an error on failure + or will convert it to type and return new converted value + can check for: + - int: will be converted into int + - bool: will be converted to False / True + - list: will always return a list + - string: will do nothing for now + - ignore: will ignore it, just like "string" + """ + error = False + if type == "int": + if _is_int(value): + value = int(value) + else: + error = True + elif type == "bool": + if value in ("0", "1"): + value = bool(int(value)) + elif value in ("true", "True", "TRUE"): + value = True + elif value in ("false", "False", "FALSE"): + value = False + else: + error = True + elif type == "list": + value = value.split("|") + elif type == "string": + pass + elif type == "ignore": + pass + else: + logger.log(u"API :: Invalid param type set " + str(type) + " can not check or convert ignoring it", logger.ERROR) + + if error: + # this is a real ApiError !! + raise ApiError(u"param: '" + str(name) + "' with given value: '" + str(value) + "' could not be parsed into '" + str(type) + "'") + + return value + + def _check_param_value(self, value, name, allowedValues): + """ will check if value (or all values in it ) are in allowed values + will raise an exception if value is "out of range" + if bool(allowedValue) == False a check is not performed and all values are excepted + """ + if allowedValues: + error = False + if isinstance(value, list): + for item in value: + if not item in allowedValues: + error = True + else: + if not value in allowedValues: + error = True + + if error: + # this is kinda a ApiError but raising an error is the only way of quitting here + raise ApiError(u"param: '" + str(name) + "' with given value: '" + str(value) + "' is out of allowed range '" + str(allowedValues) + "'") + + +class TVDBShorthandWrapper(ApiCall): + _help = {"desc": "this is an internal function wrapper. call the help command directly for more information"} + + def __init__(self, args, kwargs, sid): + self.origArgs = args + self.kwargs = kwargs + self.sid = sid + + self.s, args = self.check_params(args, kwargs, "s", None, False, "ignore", []) + self.e, args = self.check_params(args, kwargs, "e", None, False, "ignore", []) + self.args = args + + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ internal function wrapper """ + # how to add a var to a tuple + # http://stackoverflow.com/questions/1380860/add-variables-to-tuple + argstmp = (0, self.sid) # make a new tuple + args = argstmp + self.origArgs # add both + args = args[1:] # remove first fake element + if self.e: + return CMD_Episode(args, self.kwargs).run() + elif self.s: + return CMD_ShowSeasons(args, self.kwargs).run() + else: + return CMD_Show(args, self.kwargs).run() + + +################################ +# helper functions # +################################ + +def _is_int(data): + try: + int(data) + except (TypeError, ValueError, OverflowError): + return False + else: + return True + + +def _rename_element(dict, oldKey, newKey): + try: + dict[newKey] = dict[oldKey] + del dict[oldKey] + except (ValueError, TypeError, NameError): + pass + return dict + + +def _responds(result_type, data=None, msg=""): + """ + result is a string of given "type" (success/failure/timeout/error) + message is a human readable string, can be empty + data is either a dict or a array, can be a empty dict or empty array + """ + if data is None: + data = {} + return {"result": result_type_map[result_type], + "message": msg, + "data": data} + + +def _get_quality_string(q): + qualityString = "Custom" + if q in qualityPresetStrings: + qualityString = qualityPresetStrings[q] + elif q in Quality.qualityStrings: + qualityString = Quality.qualityStrings[q] + return qualityString + + +def _get_status_Strings(s): + return statusStrings[s] + + +def _ordinal_to_dateTimeForm(ordinal): + # workaround for episodes with no airdate + if int(ordinal) != 1: + date = datetime.date.fromordinal(ordinal) + else: + return "" + return date.strftime(dateTimeFormat) + + +def _ordinal_to_dateForm(ordinal): + if int(ordinal) != 1: + date = datetime.date.fromordinal(ordinal) + else: + return "" + return date.strftime(dateFormat) + + +def _historyDate_to_dateTimeForm(timeString): + date = datetime.datetime.strptime(timeString, history.dateFormat) + return date.strftime(dateTimeFormat) + + +def _replace_statusStrings_with_statusCodes(statusStrings): + statusCodes = [] + if "snatched" in statusStrings: + statusCodes += Quality.SNATCHED + if "downloaded" in statusStrings: + statusCodes += Quality.DOWNLOADED + if "skipped" in statusStrings: + statusCodes.append(SKIPPED) + if "wanted" in statusStrings: + statusCodes.append(WANTED) + if "archived" in statusStrings: + statusCodes.append(ARCHIVED) + if "ignored" in statusStrings: + statusCodes.append(IGNORED) + if "unaired" in statusStrings: + statusCodes.append(UNAIRED) + return statusCodes + + +def _mapQuality(showObj): + quality_map = _getQualityMap() + + anyQualities = [] + bestQualities = [] + + iqualityID, aqualityID = Quality.splitQuality(int(showObj)) + if iqualityID: + for quality in iqualityID: + anyQualities.append(quality_map[quality]) + if aqualityID: + for quality in aqualityID: + bestQualities.append(quality_map[quality]) + return anyQualities, bestQualities + + +def _getQualityMap(): + return {Quality.SDTV: 'sdtv', + Quality.SDDVD: 'sddvd', + Quality.HDTV: 'hdtv', + Quality.HDWEBDL: 'hdwebdl', + Quality.HDBLURAY: 'hdbluray', + Quality.FULLHDBLURAY: 'fullhdbluray', + Quality.UNKNOWN: 'unknown', + ANY: 'any'} + + +def _getRootDirs(): + if sickbeard.ROOT_DIRS == "": + return {} + + rootDir = {} + root_dirs = sickbeard.ROOT_DIRS.split('|') + default_index = int(sickbeard.ROOT_DIRS.split('|')[0]) + + rootDir["default_index"] = int(sickbeard.ROOT_DIRS.split('|')[0]) + # remove default_index value from list (this fixes the offset) + root_dirs.pop(0) + + if len(root_dirs) < default_index: + return {} + + # clean up the list - replace %xx escapes by their single-character equivalent + root_dirs = [urllib.unquote_plus(x) for x in root_dirs] + + default_dir = root_dirs[default_index] + + dir_list = [] + for root_dir in root_dirs: + valid = 1 + try: + ek.ek(os.listdir, root_dir) + except: + valid = 0 + default = 0 + if root_dir is default_dir: + default = 1 + + curDir = {} + curDir['valid'] = valid + curDir['location'] = root_dir + curDir['default'] = default + dir_list.append(curDir) + + return dir_list + + +class ApiError(Exception): + "Generic API error" + + +class IntParseError(Exception): + "A value could not be parsed into a int. But should be parsable to a int " + +#-------------------------------------------------------------------------------------# + + +class CMD_Help(ApiCall): + _help = {"desc": "display help information for a given subject/command", + "optionalParameters": {"subject": {"desc": "command - the top level command"}, + } + } + + def __init__(self, args, kwargs): + # required + # optional + self.subject, args = self.check_params(args, kwargs, "subject", "help", False, "string", _functionMaper.keys()) + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display help information for a given subject/command """ + if self.subject in _functionMaper: + out = _responds(RESULT_SUCCESS, _functionMaper.get(self.subject)((), {"help": 1}).run()) + else: + out = _responds(RESULT_FAILURE, msg="No such cmd") + return out + + +class CMD_ComingEpisodes(ApiCall): + _help = {"desc": "display the coming episodes", + "optionalParameters": {"sort": {"desc": "change the sort order"}, + "type": {"desc": "one or more of allowedValues separated by |"}, + "paused": {"desc": "0 to exclude paused shows, 1 to include them, or omitted to use the SB default"}, + } + } + + def __init__(self, args, kwargs): + # required + # optional + self.sort, args = self.check_params(args, kwargs, "sort", "date", False, "string", ["date", "show", "network"]) + self.type, args = self.check_params(args, kwargs, "type", "today|missed|soon|later", False, "list", ["missed", "later", "today", "soon"]) + self.paused, args = self.check_params(args, kwargs, "paused", sickbeard.COMING_EPS_DISPLAY_PAUSED, False, "int", [0, 1]) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display the coming episodes """ + today = datetime.date.today().toordinal() + next_week = (datetime.date.today() + datetime.timedelta(days=7)).toordinal() + recently = (datetime.date.today() - datetime.timedelta(days=3)).toordinal() + + done_show_list = [] + qualList = Quality.DOWNLOADED + Quality.SNATCHED + [ARCHIVED, IGNORED] + + myDB = db.DBConnection(row_type="dict") + sql_results = myDB.select("SELECT airdate, airs, episode, name AS 'ep_name', description AS 'ep_plot', network, season, showid AS 'tvdbid', show_name, tv_shows.quality AS quality, tv_shows.status AS 'show_status', tv_shows.paused AS 'paused' FROM tv_episodes, tv_shows WHERE season != 0 AND airdate >= ? AND airdate < ? AND tv_shows.tvdb_id = tv_episodes.showid AND tv_episodes.status NOT IN (" + ','.join(['?'] * len(qualList)) + ")", [today, next_week] + qualList) + for cur_result in sql_results: + done_show_list.append(int(cur_result["tvdbid"])) + + more_sql_results = myDB.select("SELECT airdate, airs, episode, name AS 'ep_name', description AS 'ep_plot', network, season, showid AS 'tvdbid', show_name, tv_shows.quality AS quality, tv_shows.status AS 'show_status', tv_shows.paused AS 'paused' FROM tv_episodes outer_eps, tv_shows WHERE season != 0 AND showid NOT IN (" + ','.join(['?'] * len(done_show_list)) + ") AND tv_shows.tvdb_id = outer_eps.showid AND airdate = (SELECT airdate FROM tv_episodes inner_eps WHERE inner_eps.showid = outer_eps.showid AND inner_eps.airdate >= ? ORDER BY inner_eps.airdate ASC LIMIT 1) AND outer_eps.status NOT IN (" + ','.join(['?'] * len(Quality.DOWNLOADED + Quality.SNATCHED)) + ")", done_show_list + [next_week] + Quality.DOWNLOADED + Quality.SNATCHED) + sql_results += more_sql_results + + more_sql_results = myDB.select("SELECT airdate, airs, episode, name AS 'ep_name', description AS 'ep_plot', network, season, showid AS 'tvdbid', show_name, tv_shows.quality AS quality, tv_shows.status AS 'show_status', tv_shows.paused AS 'paused' FROM tv_episodes, tv_shows WHERE season != 0 AND tv_shows.tvdb_id = tv_episodes.showid AND airdate < ? AND airdate >= ? AND tv_episodes.status = ? AND tv_episodes.status NOT IN (" + ','.join(['?'] * len(qualList)) + ")", [today, recently, WANTED] + qualList) + sql_results += more_sql_results + + # sort by air date + sorts = { + 'date': (lambda x, y: cmp(int(x["airdate"]), int(y["airdate"]))), + 'show': (lambda a, b: cmp(a["show_name"], b["show_name"])), + 'network': (lambda a, b: cmp(a["network"], b["network"])), + } + + sql_results.sort(sorts[self.sort]) + finalEpResults = {} + + # add all requested types or all + for curType in self.type: + finalEpResults[curType] = [] + + for ep in sql_results: + """ + Missed: yesterday... (less than 1week) + Today: today + Soon: tomorrow till next week + Later: later than next week + """ + + if ep["paused"] and not self.paused: + continue + + status = "soon" + if ep["airdate"] < today: + status = "missed" + elif ep["airdate"] >= next_week: + status = "later" + elif ep["airdate"] >= today and ep["airdate"] < next_week: + if ep["airdate"] == today: + status = "today" + else: + status = "soon" + + # skip unwanted + if self.type != None and not status in self.type: + continue + + ordinalAirdate = int(ep["airdate"]) + if not ep["network"]: + ep["network"] = "" + ep["airdate"] = _ordinal_to_dateForm(ordinalAirdate) + ep["quality"] = _get_quality_string(ep["quality"]) + # clean up tvdb horrible airs field + ep["airs"] = str(ep["airs"]).replace('am', ' AM').replace('pm', ' PM').replace(' ', ' ') + # start day of the week on 1 (monday) + ep["weekday"] = 1 + datetime.date.fromordinal(ordinalAirdate).weekday() + + # TODO: check if this obsolete + if not status in finalEpResults: + finalEpResults[status] = [] + + finalEpResults[status].append(ep) + myDB.connection.close() + return _responds(RESULT_SUCCESS, finalEpResults) + + +class CMD_Episode(ApiCall): + _help = {"desc": "display detailed info about an episode", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + "season": {"desc": "the season number"}, + "episode": {"desc": "the episode number"} + }, + "optionalParameters": {"full_path": {"desc": "show the full absolute path (if valid) instead of a relative path for the episode location"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + self.s, args = self.check_params(args, kwargs, "season", None, True, "int", []) + self.e, args = self.check_params(args, kwargs, "episode", None, True, "int", []) + # optional + self.fullPath, args = self.check_params(args, kwargs, "full_path", 0, False, "bool", []) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display detailed info about an episode """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + myDB = db.DBConnection(row_type="dict") + sqlResults = myDB.select("SELECT name, description, airdate, status, location FROM tv_episodes WHERE showid = ? AND episode = ? AND season = ?", [self.tvdbid, self.e, self.s]) + if not len(sqlResults) == 1: + raise ApiError("Episode not found") + episode = sqlResults[0] + # handle path options + # absolute vs relative vs broken + showPath = None + try: + showPath = showObj.location + except sickbeard.exceptions.ShowDirNotFoundException: + pass + + if bool(self.fullPath) == True and showPath: + pass + elif bool(self.fullPath) == False and showPath: + #i am using the length because lstrip removes to much + showPathLength = len(showPath) + 1 # the / or \ yeah not that nice i know + episode["location"] = episode["location"][showPathLength:] + elif not showPath: # show dir is broken ... episode path will be empty + episode["location"] = "" + # convert stuff to human form + episode["airdate"] = _ordinal_to_dateForm(episode["airdate"]) + status, quality = Quality.splitCompositeStatus(int(episode["status"])) + episode["status"] = _get_status_Strings(status) + episode["quality"] = _get_quality_string(quality) + + myDB.connection.close() + return _responds(RESULT_SUCCESS, episode) + + +class CMD_EpisodeSearch(ApiCall): + _help = {"desc": "search for an episode. the response might take some time", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + "season": {"desc": "the season number"}, + "episode": {"desc": "the episode number"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + self.s, args = self.check_params(args, kwargs, "season", None, True, "int", []) + self.e, args = self.check_params(args, kwargs, "episode", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ search for an episode """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + # retrieve the episode object and fail if we can't get one + epObj = showObj.getEpisode(int(self.s), int(self.e)) + if isinstance(epObj, str): + return _responds(RESULT_FAILURE, msg="Episode not found") + + # make a queue item for it and put it on the queue + ep_queue_item = search_queue.ManualSearchQueueItem(epObj) + sickbeard.searchQueueScheduler.action.add_item(ep_queue_item) #@UndefinedVariable + + # wait until the queue item tells us whether it worked or not + while ep_queue_item.success == None: #@UndefinedVariable + time.sleep(1) + + # return the correct json value + if ep_queue_item.success: + status, quality = Quality.splitCompositeStatus(epObj.status) #@UnusedVariable + # TODO: split quality and status? + return _responds(RESULT_SUCCESS, {"quality": _get_quality_string(quality)}, "Snatched (" + _get_quality_string(quality) + ")") + + return _responds(RESULT_FAILURE, msg='Unable to find episode') + + +class CMD_EpisodeSetStatus(ApiCall): + _help = {"desc": "set status of an episode", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + "season": {"desc": "the season number"}, + "episode": {"desc": "the episode number"}, + "status": {"desc": "the status values: wanted, skipped, archived, ignored"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + self.s, args = self.check_params(args, kwargs, "season", None, True, "int", []) + self.e, args = self.check_params(args, kwargs, "episode", None, True, "int", []) + self.status, args = self.check_params(args, kwargs, "status", None, True, "string", ["wanted", "skipped", "archived", "ignored"]) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ set status of an episode """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + # convert the string status to a int + for status in statusStrings.statusStrings: + if str(statusStrings[status]).lower() == str(self.status).lower(): + self.status = status + break + # this should be obsolete bcause of the above + if not self.status in statusStrings.statusStrings: + return _responds(RESULT_FAILURE, msg="Invalid Status") + + epObj = showObj.getEpisode(int(self.s), int(self.e)) + if epObj == None: + return _responds(RESULT_FAILURE, msg="Episode not found") + + #only allow the status options we want + if int(self.status) not in (3, 5, 6, 7): + return _responds(RESULT_FAILURE, msg="Show not found") + + segment_list = [] + if int(self.status) == WANTED: + # figure out what segment the episode is in and remember it so we can backlog it + if epObj.show.air_by_date: + ep_segment = str(epObj.airdate)[:7] + else: + ep_segment = epObj.season + + if ep_segment not in segment_list: + segment_list.append(ep_segment) + + with epObj.lock: + # don't let them mess up UNAIRED episodes + if epObj.status == UNAIRED: + return _responds(RESULT_FAILURE, msg="Refusing to change status because it is UNAIRED") + + if int(self.status) in Quality.DOWNLOADED and epObj.status not in Quality.SNATCHED + Quality.SNATCHED_PROPER + Quality.DOWNLOADED + [IGNORED] and not ek.ek(os.path.isfile, epObj.location): + return _responds(RESULT_FAILURE, msg="Refusing to change status to DOWNLOADED because it's not SNATCHED/DOWNLOADED") + + epObj.status = int(self.status) + epObj.saveToDB() + + for cur_segment in segment_list: + cur_backlog_queue_item = search_queue.BacklogQueueItem(showObj, cur_segment) + sickbeard.searchQueueScheduler.action.add_item(cur_backlog_queue_item) #@UndefinedVariable + logger.log(u"API :: Starting backlog for " + showObj.name + " season " + str(cur_segment) + " because some eps were set to wanted") + return _responds(RESULT_SUCCESS, msg="Episode status changed to Wanted, and backlog started") + + return _responds(RESULT_SUCCESS, msg="Episode status successfully changed to " + statusStrings[epObj.status]) + + +class CMD_Exceptions(ApiCall): + _help = {"desc": "display scene exceptions for all or a given show", + "optionalParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + } + } + + def __init__(self, args, kwargs): + # required + # optional + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, False, "int", []) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display scene exceptions for all or a given show """ + myDB = db.DBConnection("cache.db", row_type="dict") + + if self.tvdbid == None: + sqlResults = myDB.select("SELECT show_name, tvdb_id AS 'tvdbid' FROM scene_exceptions") + scene_exceptions = {} + for row in sqlResults: + tvdbid = row["tvdbid"] + if not tvdbid in scene_exceptions: + scene_exceptions[tvdbid] = [] + scene_exceptions[tvdbid].append(row["show_name"]) + + else: + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + sqlResults = myDB.select("SELECT show_name, tvdb_id AS 'tvdbid' FROM scene_exceptions WHERE tvdb_id = ?", [self.tvdbid]) + scene_exceptions = [] + for row in sqlResults: + scene_exceptions.append(row["show_name"]) + + myDB.connection.close() + return _responds(RESULT_SUCCESS, scene_exceptions) + + +class CMD_History(ApiCall): + _help = {"desc": "display sickbeard downloaded/snatched history", + "optionalParameters": {"limit": {"desc": "limit returned results"}, + "type": {"desc": "only show a specific type of results"}, + } + } + + def __init__(self, args, kwargs): + # required + # optional + self.limit, args = self.check_params(args, kwargs, "limit", 100, False, "int", []) + self.type, args = self.check_params(args, kwargs, "type", None, False, "string", ["downloaded", "snatched"]) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display sickbeard downloaded/snatched history """ + + typeCodes = [] + if self.type == "downloaded": + self.type = "Downloaded" + typeCodes = Quality.DOWNLOADED + elif self.type == "snatched": + self.type = "Snatched" + typeCodes = Quality.SNATCHED + else: + typeCodes = Quality.SNATCHED + Quality.DOWNLOADED + + myDB = db.DBConnection(row_type="dict") + + ulimit = min(int(self.limit), 100) + if ulimit == 0: + sqlResults = myDB.select("SELECT h.*, show_name FROM history h, tv_shows s WHERE h.showid=s.tvdb_id AND action in (" + ','.join(['?'] * len(typeCodes)) + ") ORDER BY date DESC", typeCodes) + else: + sqlResults = myDB.select("SELECT h.*, show_name FROM history h, tv_shows s WHERE h.showid=s.tvdb_id AND action in (" + ','.join(['?'] * len(typeCodes)) + ") ORDER BY date DESC LIMIT ?", typeCodes + [ulimit]) + + results = [] + for row in sqlResults: + status, quality = Quality.splitCompositeStatus(int(row["action"])) + status = _get_status_Strings(status) + if self.type and not status == self.type: + continue + row["status"] = status + row["quality"] = _get_quality_string(quality) + row["date"] = _historyDate_to_dateTimeForm(str(row["date"])) + del row["action"] + _rename_element(row, "showid", "tvdbid") + row["resource_path"] = os.path.dirname(row["resource"]) + row["resource"] = os.path.basename(row["resource"]) + results.append(row) + + myDB.connection.close() + return _responds(RESULT_SUCCESS, results) + + +class CMD_HistoryClear(ApiCall): + _help = {"desc": "clear sickbeard's history", + } + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ clear sickbeard's history """ + myDB = db.DBConnection() + myDB.action("DELETE FROM history WHERE 1=1") + + myDB.connection.close() + return _responds(RESULT_SUCCESS, msg="History cleared") + + +class CMD_HistoryTrim(ApiCall): + _help = {"desc": "trim sickbeard's history by removing entries greater than 30 days old" + } + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ trim sickbeard's history """ + myDB = db.DBConnection() + myDB.action("DELETE FROM history WHERE date < " + str((datetime.datetime.today() - datetime.timedelta(days=30)).strftime(history.dateFormat))) + + myDB.connection.close() + return _responds(RESULT_SUCCESS, msg="Removed history entries greater than 30 days old") + + +class CMD_Logs(ApiCall): + _help = {"desc": "view sickbeard's log", + "optionalParameters": {"min_level ": {"desc": "the minimum level classification of log entries to show, with each level inherting its above level"} } + } + + def __init__(self, args, kwargs): + # required + # optional + self.min_level, args = self.check_params(args, kwargs, "min_level", "error", False, "string", ["error", "warning", "info", "debug"]) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ view sickbeard's log """ + # 10 = Debug / 20 = Info / 30 = Warning / 40 = Error + minLevel = logger.reverseNames[str(self.min_level).upper()] + + data = [] + if os.path.isfile(logger.sb_log_instance.log_file): + f = ek.ek(open, logger.sb_log_instance.log_file) + data = f.readlines() + f.close() + + regex = "^(\w{3})\-(\d\d)\s*(\d\d)\:(\d\d):(\d\d)\s*([A-Z]+)\s*(.+?)\s*\:\:\s*(.*)$" + + finalData = [] + + numLines = 0 + lastLine = False + numToShow = min(50, len(data)) + + for x in reversed(data): + + x = x.decode('utf-8') + match = re.match(regex, x) + + if match: + level = match.group(6) + if level not in logger.reverseNames: + lastLine = False + continue + + if logger.reverseNames[level] >= minLevel: + lastLine = True + finalData.append(x.rstrip("\n")) + else: + lastLine = False + continue + + elif lastLine: + finalData.append("AA" + x) + + numLines += 1 + + if numLines >= numToShow: + break + + return _responds(RESULT_SUCCESS, finalData) + + +class CMD_SickBeard(ApiCall): + _help = {"desc": "display misc sickbeard related information"} + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display misc sickbeard related information """ + data = {"sb_version": sickbeard.version.SICKBEARD_VERSION, "api_version": Api.version, "api_commands": sorted(_functionMaper.keys())} + return _responds(RESULT_SUCCESS, data) + + +class CMD_SickBeardAddRootDir(ApiCall): + _help = {"desc": "add a sickbeard user's parent directory", + "requiredParameters": {"location": {"desc": "the full path to root (parent) directory"} + }, + "optionalParameters": {"default": {"desc": "make the location passed the default root (parent) directory"} + } + } + + def __init__(self, args, kwargs): + # required + self.location, args = self.check_params(args, kwargs, "location", None, True, "string", []) + # optional + self.default, args = self.check_params(args, kwargs, "default", 0, False, "bool", []) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ add a parent directory to sickbeard's config """ + + self.location = urllib.unquote_plus(self.location) + location_matched = 0 + + # dissallow adding/setting an invalid dir + if not ek.ek(os.path.isdir, self.location): + return _responds(RESULT_FAILURE, msg="Location is invalid") + + root_dirs = [] + + if sickbeard.ROOT_DIRS == "": + self.default = 1 + else: + root_dirs = sickbeard.ROOT_DIRS.split('|') + index = int(sickbeard.ROOT_DIRS.split('|')[0]) + root_dirs.pop(0) + # clean up the list - replace %xx escapes by their single-character equivalent + root_dirs = [urllib.unquote_plus(x) for x in root_dirs] + for x in root_dirs: + if(x == self.location): + location_matched = 1 + if (self.default == 1): + index = root_dirs.index(self.location) + break + + if(location_matched == 0): + if (self.default == 1): + index = 0 + root_dirs.insert(0, self.location) + else: + root_dirs.append(self.location) + + root_dirs_new = [urllib.unquote_plus(x) for x in root_dirs] + root_dirs_new.insert(0, index) + root_dirs_new = '|'.join(unicode(x) for x in root_dirs_new) + + sickbeard.ROOT_DIRS = root_dirs_new + return _responds(RESULT_SUCCESS, _getRootDirs(), msg="Root directories updated") + + +class CMD_SickBeardCheckScheduler(ApiCall): + _help = {"desc": "query the scheduler"} + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ query the scheduler """ + myDB = db.DBConnection() + sqlResults = myDB.select("SELECT last_backlog FROM info") + + backlogPaused = sickbeard.searchQueueScheduler.action.is_backlog_paused() #@UndefinedVariable + backlogRunning = sickbeard.searchQueueScheduler.action.is_backlog_in_progress() #@UndefinedVariable + searchStatus = sickbeard.currentSearchScheduler.action.amActive #@UndefinedVariable + nextSearch = str(sickbeard.currentSearchScheduler.timeLeft()).split('.')[0] + nextBacklog = sickbeard.backlogSearchScheduler.nextRun().strftime(dateFormat).decode(sickbeard.SYS_ENCODING) + + myDB.connection.close() + data = {"backlog_is_paused": int(backlogPaused), "backlog_is_running": int(backlogRunning), "last_backlog": _ordinal_to_dateForm(sqlResults[0]["last_backlog"]), "search_is_running": int(searchStatus), "next_search": nextSearch, "next_backlog": nextBacklog} + return _responds(RESULT_SUCCESS, data) + + +class CMD_SickBeardDeleteRootDir(ApiCall): + _help = {"desc": "delete a sickbeard user's parent directory", + "requiredParameters": {"location": {"desc": "the full path to root (parent) directory"} } + } + + def __init__(self, args, kwargs): + # required + self.location, args = self.check_params(args, kwargs, "location", None, True, "string", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ delete a parent directory from sickbeard's config """ + if sickbeard.ROOT_DIRS == "": + return _responds(RESULT_FAILURE, _getRootDirs(), msg="No root directories detected") + + root_dirs_new = [] + root_dirs = sickbeard.ROOT_DIRS.split('|') + index = int(root_dirs[0]) + root_dirs.pop(0) + # clean up the list - replace %xx escapes by their single-character equivalent + root_dirs = [urllib.unquote_plus(x) for x in root_dirs] + old_root_dir = root_dirs[index] + for curRootDir in root_dirs: + if not curRootDir == self.location: + root_dirs_new.append(curRootDir) + else: + newIndex = 0 + + for curIndex, curNewRootDir in enumerate(root_dirs_new): + if curNewRootDir is old_root_dir: + newIndex = curIndex + break + + root_dirs_new = [urllib.unquote_plus(x) for x in root_dirs_new] + if len(root_dirs_new) > 0: + root_dirs_new.insert(0, newIndex) + root_dirs_new = "|".join(unicode(x) for x in root_dirs_new) + + sickbeard.ROOT_DIRS = root_dirs_new + # what if the root dir was not found? + return _responds(RESULT_SUCCESS, _getRootDirs(), msg="Root directory deleted") + + +class CMD_SickBeardForceSearch(ApiCall): + _help = {"desc": "force the episode search early" + } + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ force the episode search early """ + # Changing all old missing episodes to status WANTED + # Beginning search for new episodes on RSS + # Searching all providers for any needed episodes + result = sickbeard.currentSearchScheduler.forceRun() + if result: + return _responds(RESULT_SUCCESS, msg="Episode search forced") + return _responds(RESULT_FAILURE, msg="Can not search for episode") + + +class CMD_SickBeardGetDefaults(ApiCall): + _help = {"desc": "get sickbeard user defaults"} + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ get sickbeard user defaults """ + + anyQualities, bestQualities = _mapQuality(sickbeard.QUALITY_DEFAULT) + + data = {"status": statusStrings[sickbeard.STATUS_DEFAULT].lower(), "season_folders": int(sickbeard.SEASON_FOLDERS_DEFAULT), "initial": anyQualities, "archive": bestQualities, "future_show_paused": int(sickbeard.COMING_EPS_DISPLAY_PAUSED) } + return _responds(RESULT_SUCCESS, data) + + +class CMD_SickBeardGetMessages(ApiCall): + _help = {"desc": "get all messages"} + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + messages = [] + for cur_notification in ui.notifications.get_notifications(): + messages.append({"title": cur_notification.title, + "message": cur_notification.message, + "type": cur_notification.type}) + return _responds(RESULT_SUCCESS, messages) + + +class CMD_SickBeardGetRootDirs(ApiCall): + _help = {"desc": "get sickbeard user parent directories"} + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ get the parent directories defined in sickbeard's config """ + + return _responds(RESULT_SUCCESS, _getRootDirs()) + + +class CMD_SickBeardPauseBacklog(ApiCall): + _help = {"desc": "pause the backlog search", + "optionalParameters": {"pause ": {"desc": "pause or unpause the global backlog"} } + } + + def __init__(self, args, kwargs): + # required + # optional + self.pause, args = self.check_params(args, kwargs, "pause", 0, False, "bool", []) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ pause the backlog search """ + if self.pause == True: + sickbeard.searchQueueScheduler.action.pause_backlog() #@UndefinedVariable + return _responds(RESULT_SUCCESS, msg="Backlog paused") + else: + sickbeard.searchQueueScheduler.action.unpause_backlog() #@UndefinedVariable + return _responds(RESULT_SUCCESS, msg="Backlog unpaused") + + +class CMD_SickBeardPing(ApiCall): + _help = {"desc": "check to see if sickbeard is running"} + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ check to see if sickbeard is running """ + cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + if sickbeard.started: + return _responds(RESULT_SUCCESS, {"pid": sickbeard.PID}, "Pong") + else: + return _responds(RESULT_SUCCESS, msg="Pong") + + +class CMD_SickBeardRestart(ApiCall): + _help = {"desc": "restart sickbeard"} + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ restart sickbeard """ + threading.Timer(2, sickbeard.invoke_restart, [False]).start() + return _responds(RESULT_SUCCESS, msg="SickBeard is restarting...") + + +class CMD_SickBeardSearchTVDB(ApiCall): + _help = {"desc": "search for show at tvdb with a given string and language", + "optionalParameters": {"name": {"desc": "name of the show you want to search for"}, + "tvdbid": {"desc": "thetvdb.com unique id of a show"}, + "lang": {"desc": "the 2 letter abbreviation lang id"} + } + } + + valid_languages = { + 'el': 20, 'en': 7, 'zh': 27, 'it': 15, 'cs': 28, 'es': 16, 'ru': 22, + 'nl': 13, 'pt': 26, 'no': 9, 'tr': 21, 'pl': 18, 'fr': 17, 'hr': 31, + 'de': 14, 'da': 10, 'fi': 11, 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, + 'sv': 8, 'sl': 30} + + def __init__(self, args, kwargs): + # required + # optional + self.name, args = self.check_params(args, kwargs, "name", None, False, "string", []) + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, False, "int", []) + self.lang, args = self.check_params(args, kwargs, "lang", "en", False, "string", self.valid_languages.keys()) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ search for show at tvdb with a given string and language """ + if self.name and not self.tvdbid: # only name was given + baseURL = "http://thetvdb.com/api/GetSeries.php?" + params = {"seriesname": str(self.name).encode('utf-8'), 'language': self.lang} + finalURL = baseURL + urllib.urlencode(params) + urlData = sickbeard.helpers.getURL(finalURL) + + try: + seriesXML = etree.ElementTree(etree.XML(urlData)) + except Exception, e: + logger.log(u"API :: Unable to parse XML for some reason: " + ex(e) + " from XML: " + urlData, logger.ERROR) + return _responds(RESULT_FAILURE, msg="Unable to read result from tvdb") + + series = seriesXML.getiterator('Series') + results = [] + for curSeries in series: + results.append({"tvdbid": int(curSeries.findtext('seriesid')), + "name": curSeries.findtext('SeriesName'), + "first_aired": curSeries.findtext('FirstAired')}) + + lang_id = self.valid_languages[self.lang] + return _responds(RESULT_SUCCESS, {"results": results, "langid": lang_id}) + elif self.tvdbid: + # There's gotta be a better way of doing this but we don't wanna + # change the language value elsewhere + ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() + + lang_id = self.valid_languages[self.lang] + if self.lang and not self.lang == 'en': + ltvdb_api_parms['language'] = self.lang + + t = tvdb_api.Tvdb(actors=False, **ltvdb_api_parms) + + try: + myShow = t[int(self.tvdbid)] + except (tvdb_exceptions.tvdb_shownotfound, tvdb_exceptions.tvdb_error): + logger.log(u"API :: Unable to find show with id " + str(self.tvdbid), logger.WARNING) + return _responds(RESULT_SUCCESS, {"results": [], "langid": lang_id}) + + showOut = [{"tvdbid": self.tvdbid, + "name": unicode(myShow.data['seriesname']), + "first_aired": myShow.data['firstaired']}] + + return _responds(RESULT_SUCCESS, {"results": showOut, "langid": lang_id}) + else: + return _responds(RESULT_FAILURE, msg="Either tvdbid or name is required") + + +class CMD_SickBeardSetDefaults(ApiCall): + _help = {"desc": "set sickbeard user defaults", + "optionalParameters": {"initial": {"desc": "initial quality for the show"}, + "archive": {"desc": "archive quality for the show"}, + "season_folder": {"desc": "use season subfolders within the show directory"}, + "status": {"desc": "status of missing episodes"} + } + } + + def __init__(self, args, kwargs): + # required + # optional + self.initial, args = self.check_params(args, kwargs, "initial", None, False, "list", ["sdtv", "sddvd", "hdtv", "hdwebdl", "hdbluray", "fullhdbluray", "unknown", "any"]) + self.archive, args = self.check_params(args, kwargs, "archive", None, False, "list", ["sddvd", "hdtv", "hdwebdl", "hdbluray", "fullhdbluray", "unknown", "any"]) + self.future_show_paused, args = self.check_params(args, kwargs, "future_show_paused", None, False, "bool", []) + self.season_folder, args = self.check_params(args, kwargs, "season_folder", None, False, "bool", []) + self.status, args = self.check_params(args, kwargs, "status", None, False, "string", ["wanted", "skipped", "archived", "ignored"]) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ set sickbeard user defaults """ + + quality_map = {'sdtv': Quality.SDTV, + 'sddvd': Quality.SDDVD, + 'hdtv': Quality.HDTV, + 'hdwebdl': Quality.HDWEBDL, + 'hdbluray': Quality.HDBLURAY, + 'fullhdbluray': Quality.FULLHDBLURAY, + 'unknown': Quality.UNKNOWN, + 'any': ANY } + + iqualityID = [] + aqualityID = [] + + if self.initial: + for quality in self.initial: + iqualityID.append(quality_map[quality]) + if self.archive: + for quality in self.archive: + aqualityID.append(quality_map[quality]) + + if iqualityID or aqualityID: + sickbeard.QUALITY_DEFAULT = Quality.combineQualities(iqualityID, aqualityID) + + if self.status: + # convert the string status to a int + for status in statusStrings.statusStrings: + if statusStrings[status].lower() == str(self.status).lower(): + self.status = status + break + # this should be obsolete bcause of the above + if not self.status in statusStrings.statusStrings: + raise ApiError("Invalid Status") + #only allow the status options we want + if int(self.status) not in (3, 5, 6, 7): + raise ApiError("Status Prohibited") + sickbeard.STATUS_DEFAULT = self.status + + if self.season_folder != None: + sickbeard.SEASON_FOLDERS_DEFAULT = int(self.season_folder) + + if self.future_show_paused != None: + sickbeard.COMING_EPS_DISPLAY_PAUSED = int(self.future_show_paused) + + return _responds(RESULT_SUCCESS, msg="Saved defaults") + + +class CMD_SickBeardShutdown(ApiCall): + _help = {"desc": "shutdown sickbeard"} + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ shutdown sickbeard """ + threading.Timer(2, sickbeard.invoke_shutdown).start() + return _responds(RESULT_SUCCESS, msg="SickBeard is shutting down...") + + +class CMD_Show(ApiCall): + _help = {"desc": "display information for a given show", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display information for a given show """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + showDict = {} + showDict["season_list"] = CMD_ShowSeasonList((), {"tvdbid": self.tvdbid}).run()["data"] + showDict["cache"] = CMD_ShowCache((), {"tvdbid": self.tvdbid}).run()["data"] + + genreList = [] + if showObj.genre: + genreListTmp = showObj.genre.split("|") + for genre in genreListTmp: + if genre: + genreList.append(genre) + showDict["genre"] = genreList + showDict["quality"] = _get_quality_string(showObj.quality) + + anyQualities, bestQualities = _mapQuality(showObj.quality) + showDict["quality_details"] = {"initial": anyQualities, "archive": bestQualities} + + try: + showDict["location"] = showObj.location + except sickbeard.exceptions.ShowDirNotFoundException: + showDict["location"] = "" + + showDict["language"] = showObj.lang + showDict["show_name"] = showObj.name + showDict["paused"] = showObj.paused + showDict["air_by_date"] = showObj.air_by_date + showDict["season_folders"] = showObj.seasonfolders + #clean up tvdb horrible airs field + showDict["airs"] = str(showObj.airs).replace('am', ' AM').replace('pm', ' PM').replace(' ', ' ') + showDict["tvrage_id"] = showObj.tvrid + showDict["tvrage_name"] = showObj.tvrname + showDict["network"] = showObj.network + if not showDict["network"]: + showDict["network"] = "" + showDict["status"] = showObj.status + + nextAirdate = '' + nextEps = showObj.nextEpisode() + if (len(nextEps) != 0): + nextAirdate = _ordinal_to_dateForm(nextEps[0].airdate.toordinal()) + showDict["next_ep_airdate"] = nextAirdate + + return _responds(RESULT_SUCCESS, showDict) + + +class CMD_ShowAddExisting(ApiCall): + _help = {"desc": "add a show in sickbeard with an existing folder", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + "location": {"desc": "full path to the existing folder for the show"} + }, + "optionalParameters": {"initial": {"desc": "initial quality for the show"}, + "archive": {"desc": "archive quality for the show"}, + "season_folder": {"desc": "use season subfolders for the show"} + } + } + + def __init__(self, args, kwargs): + # required + self.location, args = self.check_params(args, kwargs, "location", None, True, "string", []) + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + self.initial, args = self.check_params(args, kwargs, "initial", None, False, "list", ["sdtv", "sddvd", "hdtv", "hdwebdl", "hdbluray", "fullhdbluray", "unknown", "any"]) + self.archive, args = self.check_params(args, kwargs, "archive", None, False, "list", ["sddvd", "hdtv", "hdwebdl", "hdbluray", "fullhdbluray", "unknown", "any"]) + self.season_folder, args = self.check_params(args, kwargs, "season_folder", str(sickbeard.SEASON_FOLDERS_DEFAULT), False, "bool", []) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ add a show in sickbeard with an existing folder """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if showObj: + return _responds(RESULT_FAILURE, msg="An existing tvdbid already exists in the database") + + if not ek.ek(os.path.isdir, self.location): + return _responds(RESULT_FAILURE, msg='Not a valid location') + + tvdbName = None + tvdbResult = CMD_SickBeardSearchTVDB([], {"tvdbid": self.tvdbid}).run() + + if tvdbResult['result'] == result_type_map[RESULT_SUCCESS]: + if len(tvdbResult['data']['results']) == 1 and 'name' in tvdbResult['data']['results'][0]: + tvdbName = tvdbResult['data']['results'][0]['name'] + + if not tvdbName: + return _responds(RESULT_FAILURE, msg="Unable to retrieve information from tvdb") + + quality_map = {'sdtv': Quality.SDTV, + 'sddvd': Quality.SDDVD, + 'hdtv': Quality.HDTV, + 'hdwebdl': Quality.HDWEBDL, + 'hdbluray': Quality.HDBLURAY, + 'fullhdbluray': Quality.FULLHDBLURAY, + 'unknown': Quality.UNKNOWN, + 'any': ANY } + + #use default quality as a failsafe + newQuality = int(sickbeard.QUALITY_DEFAULT) + iqualityID = [] + aqualityID = [] + + if self.initial: + for quality in self.initial: + iqualityID.append(quality_map[quality]) + if self.archive: + for quality in self.archive: + aqualityID.append(quality_map[quality]) + + if iqualityID or aqualityID: + newQuality = Quality.combineQualities(iqualityID, aqualityID) + + sickbeard.showQueueScheduler.action.addShow(int(self.tvdbid), self.location, SKIPPED, newQuality, int(self.season_folder)) #@UndefinedVariable + return _responds(RESULT_SUCCESS, {"name": tvdbName}, tvdbName + " has been queued to be added") + + +class CMD_ShowAddNew(ApiCall): + _help = {"desc": "add a new show to sickbeard", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"} + }, + "optionalParameters": {"initial": {"desc": "initial quality for the show"}, + "location": {"desc": "base path for where the show folder is to be created"}, + "archive": {"desc": "archive quality for the show"}, + "season_folder": {"desc": "use season subfolders for the show"}, + "status": {"desc": "status of missing episodes"}, + "lang": {"desc": "the 2 letter lang abbreviation id"} + } + } + + valid_languages = { + 'el': 20, 'en': 7, 'zh': 27, 'it': 15, 'cs': 28, 'es': 16, 'ru': 22, + 'nl': 13, 'pt': 26, 'no': 9, 'tr': 21, 'pl': 18, 'fr': 17, 'hr': 31, + 'de': 14, 'da': 10, 'fi': 11, 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, + 'sv': 8, 'sl': 30} + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + self.location, args = self.check_params(args, kwargs, "location", None, False, "string", []) + self.initial, args = self.check_params(args, kwargs, "initial", None, False, "list", ["sdtv", "sddvd", "hdtv", "hdwebdl", "hdbluray", "fullhdbluray", "unknown", "any"]) + self.archive, args = self.check_params(args, kwargs, "archive", None, False, "list", ["sddvd", "hdtv", "hdwebdl", "hdbluray", "fullhdbluray", "unknown", "any"]) + self.season_folder, args = self.check_params(args, kwargs, "season_folder", str(sickbeard.SEASON_FOLDERS_DEFAULT), False, "bool", []) + self.status, args = self.check_params(args, kwargs, "status", None, False, "string", ["wanted", "skipped", "archived", "ignored"]) + self.lang, args = self.check_params(args, kwargs, "lang", "en", False, "string", self.valid_languages.keys()) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ add a show in sickbeard with an existing folder """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if showObj: + return _responds(RESULT_FAILURE, msg="An existing tvdbid already exists in database") + + if not self.location: + if sickbeard.ROOT_DIRS != "": + root_dirs = sickbeard.ROOT_DIRS.split('|') + root_dirs.pop(0) + default_index = int(sickbeard.ROOT_DIRS.split('|')[0]) + self.location = root_dirs[default_index] + else: + return _responds(RESULT_FAILURE, msg="Root directory is not set, please provide a location") + + if not ek.ek(os.path.isdir, self.location): + return _responds(RESULT_FAILURE, msg="'" + self.location + "' is not a valid location") + + quality_map = {'sdtv': Quality.SDTV, + 'sddvd': Quality.SDDVD, + 'hdtv': Quality.HDTV, + 'hdwebdl': Quality.HDWEBDL, + 'hdbluray': Quality.HDBLURAY, + 'fullhdbluray': Quality.FULLHDBLURAY, + 'unknown': Quality.UNKNOWN, + 'any': ANY } + + # use default quality as a failsafe + newQuality = int(sickbeard.QUALITY_DEFAULT) + iqualityID = [] + aqualityID = [] + + if self.initial: + for quality in self.initial: + iqualityID.append(quality_map[quality]) + if self.archive: + for quality in self.archive: + aqualityID.append(quality_map[quality]) + + if iqualityID or aqualityID: + newQuality = Quality.combineQualities(iqualityID, aqualityID) + + # use default status as a failsafe + newStatus = sickbeard.STATUS_DEFAULT + if self.status: + # convert the string status to a int + for status in statusStrings.statusStrings: + if statusStrings[status].lower() == str(self.status).lower(): + self.status = status + break + #TODO: check if obsolete + if not self.status in statusStrings.statusStrings: + raise ApiError("Invalid Status") + # only allow the status options we want + if int(self.status) not in (3, 5, 6, 7): + return _responds(RESULT_FAILURE, msg="Status prohibited") + newStatus = self.status + + tvdbName = None + tvdbResult = CMD_SickBeardSearchTVDB([], {"tvdbid": self.tvdbid}).run() + + if tvdbResult['result'] == result_type_map[RESULT_SUCCESS]: + if len(tvdbResult['data']['results']) == 1 and 'name' in tvdbResult['data']['results'][0]: + tvdbName = tvdbResult['data']['results'][0]['name'] + + if not tvdbName: + return _responds(RESULT_FAILURE, msg="Unable to retrieve information from tvdb") + + # moved the logic check to the end in an attempt to eliminate empty directory being created from previous errors + showPath = ek.ek(os.path.join, self.location, helpers.sanitizeFileName(tvdbName)) + dir_exists = helpers.makeDir(showPath) + if not dir_exists: + logger.log(u"API :: Unable to create the folder " + showPath + ", can't add the show", logger.ERROR) + return _responds(RESULT_FAILURE, {"path": showPath}, "Unable to create the folder " + showPath + ", can't add the show") + else: + helpers.chmodAsParent(showPath) + + sickbeard.showQueueScheduler.action.addShow(int(self.tvdbid), showPath, newStatus, newQuality, int(self.season_folder), self.lang) #@UndefinedVariable + return _responds(RESULT_SUCCESS, {"name": tvdbName}, tvdbName + " has been queued to be added") + + +class CMD_ShowCache(ApiCall): + _help = {"desc": "check sickbeard's cache to see if the banner or poster image for a show is valid", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ check sickbeard's cache to see if the banner or poster image for a show is valid """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + #TODO: catch if cache dir is missing/invalid.. so it doesn't break show/show.cache + #return {"poster": 0, "banner": 0} + + cache_obj = image_cache.ImageCache() + + has_poster = 0 + has_banner = 0 + + if ek.ek(os.path.isfile, cache_obj.poster_path(showObj.tvdbid)): + has_poster = 1 + if ek.ek(os.path.isfile, cache_obj.banner_path(showObj.tvdbid)): + has_banner = 1 + + return _responds(RESULT_SUCCESS, {"poster": has_poster, "banner": has_banner}) + + +class CMD_ShowDelete(ApiCall): + _help = {"desc": "delete a show in sickbeard", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ delete a show in sickbeard """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + if sickbeard.showQueueScheduler.action.isBeingAdded(showObj) or sickbeard.showQueueScheduler.action.isBeingUpdated(showObj): #@UndefinedVariable + return _responds(RESULT_FAILURE, msg="Show can not be deleted while being added or updated") + + showObj.deleteShow() + return _responds(RESULT_SUCCESS, msg=str(showObj.name) + " has been deleted") + + +class CMD_ShowGetQuality(ApiCall): + _help = {"desc": "get quality setting for a show in sickbeard", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ get quality setting for a show in sickbeard """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + anyQualities, bestQualities = _mapQuality(showObj.quality) + + return _responds(RESULT_SUCCESS, {"initial": anyQualities, "archive": bestQualities}) + + +class CMD_ShowGetPoster(ApiCall): + _help = {"desc": "get the poster stored for a show in sickbeard", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ get the poster for a show in sickbeard """ + return {'outputType': 'image', 'image': webserve.WebInterface().showPoster(self.tvdbid, 'poster')} + + +class CMD_ShowGetBanner(ApiCall): + _help = {"desc": "get the banner stored for a show in sickbeard", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ get the banner for a show in sickbeard """ + return {'outputType': 'image', 'image': webserve.WebInterface().showPoster(self.tvdbid, 'banner')} + + +class CMD_ShowPause(ApiCall): + _help = {"desc": "set a show's paused state in sickbeard", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + }, + "optionalParameters": {"pause": {"desc": "set the pause state of the show"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + self.pause, args = self.check_params(args, kwargs, "pause", 0, False, "bool", []) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ set a show's paused state in sickbeard """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + if self.pause == True: + showObj.paused = 1 + return _responds(RESULT_SUCCESS, msg=str(showObj.name) + " has been paused") + else: + showObj.paused = 0 + return _responds(RESULT_SUCCESS, msg=str(showObj.name) + " has been unpaused") + + return _responds(RESULT_FAILURE, msg=str(showObj.name) + " was unable to be paused") + + +class CMD_ShowRefresh(ApiCall): + _help = {"desc": "refresh a show in sickbeard", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ refresh a show in sickbeard """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + try: + sickbeard.showQueueScheduler.action.refreshShow(showObj) #@UndefinedVariable + return _responds(RESULT_SUCCESS, msg=str(showObj.name) + " has queued to be refreshed") + except exceptions.CantRefreshException: + # TODO: log the excption + return _responds(RESULT_FAILURE, msg="Unable to refresh " + str(showObj.name)) + + +class CMD_ShowSeasonList(ApiCall): + _help = {"desc": "display the season list for a given show", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + }, + "optionalParameters": {"sort": {"desc": "change the sort order from descending to ascending"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + self.sort, args = self.check_params(args, kwargs, "sort", "desc", False, "string", ["asc", "desc"]) # "asc" and "desc" default and fallback is "desc" + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display the season list for a given show """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + myDB = db.DBConnection(row_type="dict") + if self.sort == "asc": + sqlResults = myDB.select("SELECT DISTINCT season FROM tv_episodes WHERE showid = ? ORDER BY season ASC", [self.tvdbid]) + else: + sqlResults = myDB.select("SELECT DISTINCT season FROM tv_episodes WHERE showid = ? ORDER BY season DESC", [self.tvdbid]) + seasonList = [] # a list with all season numbers + for row in sqlResults: + seasonList.append(int(row["season"])) + + myDB.connection.close() + return _responds(RESULT_SUCCESS, seasonList) + + +class CMD_ShowSeasons(ApiCall): + _help = {"desc": "display a listing of episodes for all or a given season", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + }, + "optionalParameters": {"season": {"desc": "the season number"}, + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + self.season, args = self.check_params(args, kwargs, "season", None, False, "int", []) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display a listing of episodes for all or a given show """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + myDB = db.DBConnection(row_type="dict") + + if self.season == None: + sqlResults = myDB.select("SELECT name, episode, airdate, status, season FROM tv_episodes WHERE showid = ?", [self.tvdbid]) + seasons = {} + for row in sqlResults: + status, quality = Quality.splitCompositeStatus(int(row["status"])) + row["status"] = _get_status_Strings(status) + row["quality"] = _get_quality_string(quality) + row["airdate"] = _ordinal_to_dateForm(row["airdate"]) + curSeason = int(row["season"]) + curEpisode = int(row["episode"]) + del row["season"] + del row["episode"] + if not curSeason in seasons: + seasons[curSeason] = {} + seasons[curSeason][curEpisode] = row + + else: + sqlResults = myDB.select("SELECT name, episode, airdate, status FROM tv_episodes WHERE showid = ? AND season = ?", [self.tvdbid, self.season]) + if len(sqlResults) is 0: + return _responds(RESULT_FAILURE, msg="Season not found") + seasons = {} + for row in sqlResults: + curEpisode = int(row["episode"]) + del row["episode"] + status, quality = Quality.splitCompositeStatus(int(row["status"])) + row["status"] = _get_status_Strings(status) + row["quality"] = _get_quality_string(quality) + row["airdate"] = _ordinal_to_dateForm(row["airdate"]) + if not curEpisode in seasons: + seasons[curEpisode] = {} + seasons[curEpisode] = row + + myDB.connection.close() + return _responds(RESULT_SUCCESS, seasons) + + +class CMD_ShowSetQuality(ApiCall): + _help = {"desc": "set desired quality of a show in sickbeard. if neither initial or archive are provided then the config default quality will be used", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"} + }, + "optionalParameters": {"initial": {"desc": "initial quality for the show"}, + "archive": {"desc": "archive quality for the show"} + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # this for whatever reason removes hdbluray not sdtv... which is just wrong. reverting to previous code.. plus we didnt use the new code everywhere. + # self.archive, args = self.check_params(args, kwargs, "archive", None, False, "list", _getQualityMap().values()[1:]) + self.initial, args = self.check_params(args, kwargs, "initial", None, False, "list", ["sdtv", "sddvd", "hdtv", "hdwebdl", "hdbluray", "fullhdbluray", "unknown", "any"]) + self.archive, args = self.check_params(args, kwargs, "archive", None, False, "list", ["sddvd", "hdtv", "hdwebdl", "hdbluray", "fullhdbluray", "unknown", "any"]) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ set the quality for a show in sickbeard """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + """ + take in a deliminated string of quality, + map that to the # it corresponds to, + then combine qualities to make a new quality + + "self.initial": [ + "sdtv", + "sddvd", + "hdtv", + "hdwebdl", + "hdbluray", + "unknown" + ], + "iqualityID": [ + 1, + 2, + 4, + 8, + 16, + 32768 + ], + "newQuality": 32799 + """ + + quality_map = {'sdtv': Quality.SDTV, + 'sddvd': Quality.SDDVD, + 'hdtv': Quality.HDTV, + 'hdwebdl': Quality.HDWEBDL, + 'hdbluray': Quality.HDBLURAY, + 'fullhdbluray': Quality.FULLHDBLURAY, + 'unknown': Quality.UNKNOWN, + 'any': ANY } + + #use default quality as a failsafe + newQuality = int(sickbeard.QUALITY_DEFAULT) + iqualityID = [] + aqualityID = [] + + if self.initial: + for quality in self.initial: + iqualityID.append(quality_map[quality]) + if self.archive: + for quality in self.archive: + aqualityID.append(quality_map[quality]) + + if iqualityID or aqualityID: + newQuality = Quality.combineQualities(iqualityID, aqualityID) + showObj.quality = newQuality + + return _responds(RESULT_SUCCESS, msg=showObj.name + " quality has been changed to " + _get_quality_string(showObj.quality)) + + +class CMD_ShowStats(ApiCall): + _help = {"desc": "display episode statistics for a given show", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display episode statistics for a given show """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + # show stats + episode_status_counts_total = {} + episode_status_counts_total["total"] = 0 + for status in statusStrings.statusStrings.keys(): + if status in [UNKNOWN, DOWNLOADED, SNATCHED, SNATCHED_PROPER]: + continue + episode_status_counts_total[status] = 0 + + # add all the downloaded qualities + episode_qualities_counts_download = {} + episode_qualities_counts_download["total"] = 0 + for statusCode in Quality.DOWNLOADED: + status, quality = Quality.splitCompositeStatus(statusCode) + if quality in [Quality.NONE]: + continue + episode_qualities_counts_download[statusCode] = 0 + + # add all snatched qualities + episode_qualities_counts_snatch = {} + episode_qualities_counts_snatch["total"] = 0 + for statusCode in Quality.SNATCHED + Quality.SNATCHED_PROPER: + status, quality = Quality.splitCompositeStatus(statusCode) + if quality in [Quality.NONE]: + continue + episode_qualities_counts_snatch[statusCode] = 0 + + myDB = db.DBConnection(row_type="dict") + sqlResults = myDB.select("SELECT status, season FROM tv_episodes WHERE showid = ?", [self.tvdbid]) + # the main loop that goes through all episodes + for row in sqlResults: + status, quality = Quality.splitCompositeStatus(int(row["status"])) + + episode_status_counts_total["total"] += 1 + + if status in Quality.DOWNLOADED: + episode_qualities_counts_download["total"] += 1 + episode_qualities_counts_download[int(row["status"])] += 1 + elif status in Quality.SNATCHED + Quality.SNATCHED_PROPER: + episode_qualities_counts_snatch["total"] += 1 + episode_qualities_counts_snatch[int(row["status"])] += 1 + elif status == 0: # we dont count NONE = 0 = N/A + pass + else: + episode_status_counts_total[status] += 1 + + # the outgoing container + episodes_stats = {} + episodes_stats["downloaded"] = {} + # truning codes into strings + for statusCode in episode_qualities_counts_download: + if statusCode is "total": + episodes_stats["downloaded"]["total"] = episode_qualities_counts_download[statusCode] + continue + status, quality = Quality.splitCompositeStatus(int(statusCode)) + statusString = Quality.qualityStrings[quality].lower().replace(" ", "_").replace("(", "").replace(")", "") + episodes_stats["downloaded"][statusString] = episode_qualities_counts_download[statusCode] + + episodes_stats["snatched"] = {} + # truning codes into strings + # and combining proper and normal + for statusCode in episode_qualities_counts_snatch: + if statusCode is "total": + episodes_stats["snatched"]["total"] = episode_qualities_counts_snatch[statusCode] + continue + status, quality = Quality.splitCompositeStatus(int(statusCode)) + statusString = Quality.qualityStrings[quality].lower().replace(" ", "_").replace("(", "").replace(")", "") + if Quality.qualityStrings[quality] in episodes_stats["snatched"]: + episodes_stats["snatched"][statusString] += episode_qualities_counts_snatch[statusCode] + else: + episodes_stats["snatched"][statusString] = episode_qualities_counts_snatch[statusCode] + + #episodes_stats["total"] = {} + for statusCode in episode_status_counts_total: + if statusCode is "total": + episodes_stats["total"] = episode_status_counts_total[statusCode] + continue + status, quality = Quality.splitCompositeStatus(int(statusCode)) + statusString = statusStrings.statusStrings[statusCode].lower().replace(" ", "_").replace("(", "").replace(")", "") + episodes_stats[statusString] = episode_status_counts_total[statusCode] + + myDB.connection.close() + return _responds(RESULT_SUCCESS, episodes_stats) + + +class CMD_ShowUpdate(ApiCall): + _help = {"desc": "update a show in sickbeard", + "requiredParameters": {"tvdbid": {"desc": "thetvdb.com unique id of a show"}, + } + } + + def __init__(self, args, kwargs): + # required + self.tvdbid, args = self.check_params(args, kwargs, "tvdbid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ update a show in sickbeard """ + showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(self.tvdbid)) + if not showObj: + return _responds(RESULT_FAILURE, msg="Show not found") + + try: + sickbeard.showQueueScheduler.action.updateShow(showObj, True) #@UndefinedVariable + return _responds(RESULT_SUCCESS, msg=str(showObj.name) + " has queued to be updated") + except exceptions.CantUpdateException, e: + logger.log(u"API:: Unable to update " + str(showObj.name) + ". " + str(ex(e)), logger.ERROR) + return _responds(RESULT_FAILURE, msg="Unable to update " + str(showObj.name)) + + +class CMD_Shows(ApiCall): + _help = {"desc": "display all shows in sickbeard", + "optionalParameters": {"sort": {"desc": "sort the list of shows by show name instead of tvdbid"}, + "paused": {"desc": "only show the shows that are set to paused"}, + }, + } + + def __init__(self, args, kwargs): + # required + # optional + self.sort, args = self.check_params(args, kwargs, "sort", "id", False, "string", ["id", "name"]) + self.paused, args = self.check_params(args, kwargs, "paused", None, False, "bool", []) + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display_is_int_multi( self.tvdbid )shows in sickbeard """ + shows = {} + for curShow in sickbeard.showList: + nextAirdate = '' + nextEps = curShow.nextEpisode() + if (len(nextEps) != 0): + nextAirdate = _ordinal_to_dateForm(nextEps[0].airdate.toordinal()) + + if self.paused != None and bool(self.paused) != bool(curShow.paused): + continue + + showDict = {"paused": curShow.paused, + "quality": _get_quality_string(curShow.quality), + "language": curShow.lang, + "air_by_date": curShow.air_by_date, + "tvrage_id": curShow.tvrid, + "tvrage_name": curShow.tvrname, + "network": curShow.network, + "status": curShow.status, + "next_ep_airdate": nextAirdate} + showDict["cache"] = CMD_ShowCache((), {"tvdbid": curShow.tvdbid}).run()["data"] + if not showDict["network"]: + showDict["network"] = "" + if self.sort == "name": + showDict["tvdbid"] = curShow.tvdbid + shows[curShow.name] = showDict + else: + showDict["show_name"] = curShow.name + shows[curShow.tvdbid] = showDict + return _responds(RESULT_SUCCESS, shows) + + +class CMD_ShowsStats(ApiCall): + _help = {"desc": "display the global shows and episode stats" + } + + def __init__(self, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ display the global shows and episode stats """ + stats = {} + + myDB = db.DBConnection() + today = str(datetime.date.today().toordinal()) + stats["shows_total"] = len(sickbeard.showList) + stats["shows_active"] = len([show for show in sickbeard.showList if show.paused == 0 and show.status != "Ended"]) + stats["ep_downloaded"] = myDB.select("SELECT COUNT(*) FROM tv_episodes WHERE status IN (" + ",".join([str(show) for show in Quality.DOWNLOADED + [ARCHIVED]]) + ") AND season != 0 and episode != 0 AND airdate <= " + today + "")[0][0] + stats["ep_total"] = myDB.select("SELECT COUNT(*) FROM tv_episodes WHERE season != 0 and episode != 0 AND (airdate != 1 OR status IN (" + ",".join([str(show) for show in (Quality.DOWNLOADED + Quality.SNATCHED + Quality.SNATCHED_PROPER) + [ARCHIVED]]) + ")) AND airdate <= " + today + " AND status != " + str(IGNORED) + "")[0][0] + + myDB.connection.close() + return _responds(RESULT_SUCCESS, stats) + +# WARNING: never define a cmd call string that contains a "_" (underscore) +# this is reserved for cmd indexes used while cmd chaining + +# WARNING: never define a param name that contains a "." (dot) +# this is reserved for cmd namspaces used while cmd chaining +_functionMaper = {"help": CMD_Help, + "future": CMD_ComingEpisodes, + "episode": CMD_Episode, + "episode.search": CMD_EpisodeSearch, + "episode.setstatus": CMD_EpisodeSetStatus, + "exceptions": CMD_Exceptions, + "history": CMD_History, + "history.clear": CMD_HistoryClear, + "history.trim": CMD_HistoryTrim, + "logs": CMD_Logs, + "sb": CMD_SickBeard, + "sb.addrootdir": CMD_SickBeardAddRootDir, + "sb.checkscheduler": CMD_SickBeardCheckScheduler, + "sb.deleterootdir": CMD_SickBeardDeleteRootDir, + "sb.forcesearch": CMD_SickBeardForceSearch, + "sb.getdefaults": CMD_SickBeardGetDefaults, + "sb.getmessages": CMD_SickBeardGetMessages, + "sb.getrootdirs": CMD_SickBeardGetRootDirs, + "sb.pausebacklog": CMD_SickBeardPauseBacklog, + "sb.ping": CMD_SickBeardPing, + "sb.restart": CMD_SickBeardRestart, + "sb.searchtvdb": CMD_SickBeardSearchTVDB, + "sb.setdefaults": CMD_SickBeardSetDefaults, + "sb.shutdown": CMD_SickBeardShutdown, + "show": CMD_Show, + "show.addexisting": CMD_ShowAddExisting, + "show.addnew": CMD_ShowAddNew, + "show.cache": CMD_ShowCache, + "show.delete": CMD_ShowDelete, + "show.getquality": CMD_ShowGetQuality, + "show.getposter": CMD_ShowGetPoster, + "show.getbanner": CMD_ShowGetBanner, + "show.pause": CMD_ShowPause, + "show.refresh": CMD_ShowRefresh, + "show.seasonlist": CMD_ShowSeasonList, + "show.seasons": CMD_ShowSeasons, + "show.setquality": CMD_ShowSetQuality, + "show.stats": CMD_ShowStats, + "show.update": CMD_ShowUpdate, + "shows": CMD_Shows, + "shows.stats": CMD_ShowsStats + } diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index a943d55a7d701744d7fc61cdc55faca159cc5961..b2a985e406d10f5e3a1afc25436028a3ce3e34ed 100755 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -25,13 +25,14 @@ import urllib import re import threading import datetime +import random from Cheetah.Template import Template import cherrypy.lib import sickbeard -from sickbeard import config +from sickbeard import config, sab from sickbeard import history, notifiers, processTV from sickbeard import tv, ui from sickbeard import logger, helpers, exceptions, classes, db @@ -39,10 +40,11 @@ from sickbeard import encodingKludge as ek from sickbeard import search_queue from sickbeard import image_cache -from sickbeard.providers import newznab +from sickbeard.providers import newznab, getProviderClass from sickbeard.common import Quality, Overview, statusStrings from sickbeard.common import SNATCHED, DOWNLOADED, SKIPPED, UNAIRED, IGNORED, ARCHIVED, WANTED from sickbeard.exceptions import ex +from sickbeard.webapi import Api from lib.tvdb_api import tvdb_api @@ -61,8 +63,27 @@ class PageTemplate (Template): KWs['file'] = os.path.join(sickbeard.PROG_DIR, "data/interfaces/default/", KWs['file']) super(PageTemplate, self).__init__(*args, **KWs) self.sbRoot = sickbeard.WEB_ROOT + self.sbHttpPort = sickbeard.WEB_PORT + self.sbHttpsPort = sickbeard.WEB_PORT + self.sbHttpsEnabled = sickbeard.ENABLE_HTTPS + if cherrypy.request.headers['Host'][0] == '[': + self.sbHost = re.match("^\[.*\]", cherrypy.request.headers['Host'], re.X|re.M|re.S).group(0) + else: + self.sbHost = re.match("^[^:]+", cherrypy.request.headers['Host'], re.X|re.M|re.S).group(0) self.projectHomePage = "http://code.google.com/p/sickbeard/" + if sickbeard.NZBS and sickbeard.NZBS_UID and sickbeard.NZBS_HASH: + logger.log(u"NZBs.org has been replaced, please check the config to configure the new provider!", logger.ERROR) + ui.notifications.error("NZBs.org Config Update", "NZBs.org has a new site. Please <a href=\""+sickbeard.WEB_ROOT+"/config/providers\">update your config</a> with the api key from <a href=\"http://beta.nzbs.org/login\">http://beta.nzbs.org</a> and then disable the old NZBs.org provider.") + + if "X-Forwarded-Host" in cherrypy.request.headers: + self.sbHost = cherrypy.request.headers['X-Forwarded-Host'] + if "X-Forwarded-Port" in cherrypy.request.headers: + self.sbHttpPort = cherrypy.request.headers['X-Forwarded-Port'] + self.sbHttpsPort = self.sbHttpPort + if "X-Forwarded-Proto" in cherrypy.request.headers: + self.sbHttpsEnabled = True if cherrypy.request.headers['X-Forwarded-Proto'] == 'https' else False + logPageTitle = 'Logs & Errors' if len(classes.ErrorViewer.errors): logPageTitle += ' ('+str(len(classes.ErrorViewer.errors))+')' @@ -547,15 +568,19 @@ class Manage: class History: @cherrypy.expose - def index(self): + def index(self, limit=100): myDB = db.DBConnection() # sqlResults = myDB.select("SELECT h.*, show_name, name FROM history h, tv_shows s, tv_episodes e WHERE h.showid=s.tvdb_id AND h.showid=e.showid AND h.season=e.season AND h.episode=e.episode ORDER BY date DESC LIMIT "+str(numPerPage*(p-1))+", "+str(numPerPage)) - sqlResults = myDB.select("SELECT h.*, show_name FROM history h, tv_shows s WHERE h.showid=s.tvdb_id ORDER BY date DESC") + if limit == "0": + sqlResults = myDB.select("SELECT h.*, show_name FROM history h, tv_shows s WHERE h.showid=s.tvdb_id ORDER BY date DESC") + else: + sqlResults = myDB.select("SELECT h.*, show_name FROM history h, tv_shows s WHERE h.showid=s.tvdb_id ORDER BY date DESC LIMIT ?", [limit]) t = PageTemplate(file="history.tmpl") t.historyResults = sqlResults + t.limit = limit t.submenu = [ { 'title': 'Clear History', 'path': 'history/clearHistory' }, { 'title': 'Trim History', 'path': 'history/trimHistory' }, @@ -628,11 +653,34 @@ class ConfigGeneral: sickbeard.SEASON_FOLDERS_DEFAULT = int(defaultSeasonFolders) - + @cherrypy.expose + def generateKey(self): + """ Return a new randomized API_KEY + """ + + try: + from hashlib import md5 + except ImportError: + from md5 import md5 + + # Create some values to seed md5 + t = str(time.time()) + r = str(random.random()) + + # Create the md5 instance and give it the current time + m = md5(t) + + # Update the md5 instance with the random variable + m.update(r) + + # Return a hex digest of the md5, eg 49f68a5c8493ec2c0bf489821c21fc3b + logger.log(u"New API generated") + return m.hexdigest() + @cherrypy.expose def saveGeneral(self, log_dir=None, web_port=None, web_log=None, web_ipv6=None, - launch_browser=None, web_username=None, - web_password=None, version_notify=None): + launch_browser=None, web_username=None, use_api=None, api_key=None, + web_password=None, version_notify=None, enable_https=None, https_cert=None, https_key=None): results = [] @@ -667,6 +715,27 @@ class ConfigGeneral: sickbeard.WEB_USERNAME = web_username sickbeard.WEB_PASSWORD = web_password + if use_api == "on": + use_api = 1 + else: + use_api = 0 + + sickbeard.USE_API = use_api + sickbeard.API_KEY = api_key + + if enable_https == "on": + enable_https = 1 + else: + enable_https = 0 + + sickbeard.ENABLE_HTTPS = enable_https + + if not config.change_HTTPS_CERT(https_cert): + results += ["Unable to create directory " + os.path.normpath(https_cert) + ", https cert dir not changed."] + + if not config.change_HTTPS_KEY(https_key): + results += ["Unable to create directory " + os.path.normpath(https_key) + ", https key dir not changed."] + config.change_VERSION_NOTIFY(version_notify) sickbeard.save_config() @@ -775,7 +844,7 @@ class ConfigPostProcessing: def savePostProcessing(self, season_folders_format=None, naming_show_name=None, naming_ep_type=None, naming_multi_ep_type=None, naming_ep_name=None, naming_use_periods=None, naming_sep_type=None, naming_quality=None, naming_dates=None, - xbmc_data=None, mediabrowser_data=None, sony_ps3_data=None, wdtv_data=None, tivo_data=None, + xbmc_data=None, mediabrowser_data=None, synology_data=None, sony_ps3_data=None, wdtv_data=None, tivo_data=None, use_banner=None, keep_processed_dir=None, process_automatically=None, rename_episodes=None, move_associated_files=None, tv_download_dir=None): @@ -841,6 +910,7 @@ class ConfigPostProcessing: sickbeard.metadata_provider_dict['XBMC'].set_config(xbmc_data) sickbeard.metadata_provider_dict['MediaBrowser'].set_config(mediabrowser_data) + sickbeard.metadata_provider_dict['Synology'].set_config(synology_data) sickbeard.metadata_provider_dict['Sony PS3'].set_config(sony_ps3_data) sickbeard.metadata_provider_dict['WDTV'].set_config(wdtv_data) sickbeard.metadata_provider_dict['TIVO'].set_config(tivo_data) @@ -1019,10 +1089,10 @@ class ConfigProviders: @cherrypy.expose - def saveProviders(self, nzbs_org_uid=None, nzbs_org_hash=None, - nzbmatrix_username=None, nzbmatrix_apikey=None, + def saveProviders(self, nzbmatrix_username=None, nzbmatrix_apikey=None, nzbs_r_us_uid=None, nzbs_r_us_hash=None, newznab_string=None, - tvtorrents_digest=None, tvtorrents_hash=None, + tvtorrents_digest=None, tvtorrents_hash=None, + btn_user_id=None, btn_auth_token=None, btn_passkey=None, btn_authkey=None, newzbin_username=None, newzbin_password=None, provider_order=None): @@ -1057,7 +1127,6 @@ class ConfigProviders: finishedNames.append(curID) - # delete anything that is missing for curProvider in sickbeard.newznabProviderList: if curProvider.getID() not in finishedNames: @@ -1070,10 +1139,10 @@ class ConfigProviders: provider_list.append(curProvider) - if curProvider == 'nzbs_org': - sickbeard.NZBS = curEnabled - elif curProvider == 'nzbs_r_us': + if curProvider == 'nzbs_r_us': sickbeard.NZBSRUS = curEnabled + elif curProvider == 'nzbs_org_old': + sickbeard.NZBS = curEnabled elif curProvider == 'nzbmatrix': sickbeard.NZBMATRIX = curEnabled elif curProvider == 'newzbin': @@ -1086,6 +1155,8 @@ class ConfigProviders: sickbeard.EZRSS = curEnabled elif curProvider == 'tvtorrents': sickbeard.TVTORRENTS = curEnabled + elif curProvider == 'btn': + sickbeard.BTN = curEnabled elif curProvider in newznabProviderDict: newznabProviderDict[curProvider].enabled = bool(curEnabled) else: @@ -1094,8 +1165,10 @@ class ConfigProviders: sickbeard.TVTORRENTS_DIGEST = tvtorrents_digest.strip() sickbeard.TVTORRENTS_HASH = tvtorrents_hash.strip() - sickbeard.NZBS_UID = nzbs_org_uid.strip() - sickbeard.NZBS_HASH = nzbs_org_hash.strip() + sickbeard.BTN_USER_ID = btn_user_id.strip() + sickbeard.BTN_AUTH_TOKEN = btn_auth_token.strip() + sickbeard.BTN_PASSKEY = btn_passkey.strip() + sickbeard.BTN_AUTHKEY = btn_authkey.strip() sickbeard.NZBSRUS_UID = nzbs_r_us_uid.strip() sickbeard.NZBSRUS_HASH = nzbs_r_us_hash.strip() @@ -1137,8 +1210,14 @@ class ConfigNotifications: use_prowl=None, prowl_notify_onsnatch=None, prowl_notify_ondownload=None, prowl_api=None, prowl_priority=0, use_twitter=None, twitter_notify_onsnatch=None, twitter_notify_ondownload=None, use_notifo=None, notifo_notify_onsnatch=None, notifo_notify_ondownload=None, notifo_username=None, notifo_apisecret=None, + use_boxcar=None, boxcar_notify_onsnatch=None, boxcar_notify_ondownload=None, boxcar_username=None, + use_pushover=None, pushover_notify_onsnatch=None, pushover_notify_ondownload=None, pushover_userkey=None, use_libnotify=None, libnotify_notify_onsnatch=None, libnotify_notify_ondownload=None, - use_nmj=None, nmj_host=None, nmj_database=None, nmj_mount=None, use_synoindex=None): + use_nmj=None, nmj_host=None, nmj_database=None, nmj_mount=None, use_synoindex=None, + use_trakt=None, trakt_username=None, trakt_password=None, trakt_api=None, + use_pytivo=None, pytivo_notify_onsnatch=None, pytivo_notify_ondownload=None, pytivo_update_library=None, + pytivo_host=None, pytivo_share_name=None, pytivo_tivo_name=None, + use_nma=None, nma_notify_onsnatch=None, nma_notify_ondownload=None, nma_api=None, nma_priority=0 ): results = [] @@ -1244,6 +1323,34 @@ class ConfigNotifications: else: use_notifo = 0 + if boxcar_notify_onsnatch == "on": + boxcar_notify_onsnatch = 1 + else: + boxcar_notify_onsnatch = 0 + + if boxcar_notify_ondownload == "on": + boxcar_notify_ondownload = 1 + else: + boxcar_notify_ondownload = 0 + if use_boxcar == "on": + use_boxcar = 1 + else: + use_boxcar = 0 + + if pushover_notify_onsnatch == "on": + pushover_notify_onsnatch = 1 + else: + pushover_notify_onsnatch = 0 + + if pushover_notify_ondownload == "on": + pushover_notify_ondownload = 1 + else: + pushover_notify_ondownload = 0 + if use_pushover == "on": + use_pushover = 1 + else: + use_pushover = 0 + if use_nmj == "on": use_nmj = 1 else: @@ -1254,6 +1361,46 @@ class ConfigNotifications: else: use_synoindex = 0 + if use_trakt == "on": + use_trakt = 1 + else: + use_trakt = 0 + + if use_pytivo == "on": + use_pytivo = 1 + else: + use_pytivo = 0 + + if pytivo_notify_onsnatch == "on": + pytivo_notify_onsnatch = 1 + else: + pytivo_notify_onsnatch = 0 + + if pytivo_notify_ondownload == "on": + pytivo_notify_ondownload = 1 + else: + pytivo_notify_ondownload = 0 + + if pytivo_update_library == "on": + pytivo_update_library = 1 + else: + pytivo_update_library = 0 + + if use_nma == "on": + use_nma = 1 + else: + use_nma = 0 + + if nma_notify_onsnatch == "on": + nma_notify_onsnatch = 1 + else: + nma_notify_onsnatch = 0 + + if nma_notify_ondownload == "on": + nma_notify_ondownload = 1 + else: + nma_notify_ondownload = 0 + sickbeard.USE_XBMC = use_xbmc sickbeard.XBMC_NOTIFY_ONSNATCH = xbmc_notify_onsnatch sickbeard.XBMC_NOTIFY_ONDOWNLOAD = xbmc_notify_ondownload @@ -1294,6 +1441,16 @@ class ConfigNotifications: sickbeard.NOTIFO_USERNAME = notifo_username sickbeard.NOTIFO_APISECRET = notifo_apisecret + sickbeard.USE_BOXCAR = use_boxcar + sickbeard.BOXCAR_NOTIFY_ONSNATCH = boxcar_notify_onsnatch + sickbeard.BOXCAR_NOTIFY_ONDOWNLOAD = boxcar_notify_ondownload + sickbeard.BOXCAR_USERNAME = boxcar_username + + sickbeard.USE_PUSHOVER = use_pushover + sickbeard.PUSHOVER_NOTIFY_ONSNATCH = pushover_notify_onsnatch + sickbeard.PUSHOVER_NOTIFY_ONDOWNLOAD = pushover_notify_ondownload + sickbeard.PUSHOVER_USERKEY = pushover_userkey + sickbeard.USE_LIBNOTIFY = use_libnotify == "on" sickbeard.LIBNOTIFY_NOTIFY_ONSNATCH = libnotify_notify_onsnatch == "on" sickbeard.LIBNOTIFY_NOTIFY_ONDOWNLOAD = libnotify_notify_ondownload == "on" @@ -1305,6 +1462,25 @@ class ConfigNotifications: sickbeard.USE_SYNOINDEX = use_synoindex + sickbeard.USE_TRAKT = use_trakt + sickbeard.TRAKT_USERNAME = trakt_username + sickbeard.TRAKT_PASSWORD = trakt_password + sickbeard.TRAKT_API = trakt_api + + sickbeard.USE_PYTIVO = use_pytivo + sickbeard.PYTIVO_NOTIFY_ONSNATCH = pytivo_notify_onsnatch == "off" + sickbeard.PYTIVO_NOTIFY_ONDOWNLOAD = pytivo_notify_ondownload == "off" + sickbeard.PYTIVO_UPDATE_LIBRARY = pytivo_update_library + sickbeard.PYTIVO_HOST = pytivo_host + sickbeard.PYTIVO_SHARE_NAME = pytivo_share_name + sickbeard.PYTIVO_TIVO_NAME = pytivo_tivo_name + + sickbeard.USE_NMA = use_nma + sickbeard.NMA_NOTIFY_ONSNATCH = nma_notify_onsnatch + sickbeard.NMA_NOTIFY_ONDOWNLOAD = nma_notify_ondownload + sickbeard.NMA_API = nma_api + sickbeard.NMA_PRIORITY = nma_priority + sickbeard.save_config() if len(results) > 0: @@ -1337,18 +1513,18 @@ class Config: notifications = ConfigNotifications() -def haveXBMC(): - return sickbeard.XBMC_HOST - -def havePLEX(): - return sickbeard.PLEX_SERVER_HOST - +def haveXBMC(): + return sickbeard.XBMC_HOST + +def havePLEX(): + return sickbeard.PLEX_SERVER_HOST + def HomeMenu(): return [ { 'title': 'Add Shows', 'path': 'home/addShows/', }, { 'title': 'Manual Post-Processing', 'path': 'home/postprocess/' }, - { 'title': 'Update XBMC', 'path': 'home/updateXBMC/', 'requires': haveXBMC }, - { 'title': 'Update Plex', 'path': 'home/updatePLEX/', 'requires': havePLEX }, + { 'title': 'Update XBMC', 'path': 'home/updateXBMC/', 'requires': haveXBMC }, + { 'title': 'Update Plex', 'path': 'home/updatePLEX/', 'requires': havePLEX }, { 'title': 'Restart', 'path': 'home/restart/?pid='+str(sickbeard.PID), 'confirm': True }, { 'title': 'Shutdown', 'path': 'home/shutdown/', 'confirm': True }, ] @@ -1407,26 +1583,43 @@ class NewHomeAddShows: lang = "en" baseURL = "http://thetvdb.com/api/GetSeries.php?" + nameUTF8 = name.encode('utf-8') - params = {'seriesname': name.encode('utf-8'), - 'language': lang} + # Use each word in the show's name as a possible search term + keywords = nameUTF8.split(' ') - finalURL = baseURL + urllib.urlencode(params) + # Insert the whole show's name as the first search term so best results are first + # ex: keywords = ['Some Show Name', 'Some', 'Show', 'Name'] + keywords.insert(0, nameUTF8) - urlData = helpers.getURL(finalURL) + # Query the TVDB for each search term and build the list of results + results = [] + for searchTerm in keywords: + params = {'seriesname': searchTerm, + 'language': lang} - try: - seriesXML = etree.ElementTree(etree.XML(urlData)) - except Exception, e: - logger.log(u"Unable to parse XML for some reason: "+ex(e)+" from XML: "+urlData, logger.ERROR) - return '' + finalURL = baseURL + urllib.urlencode(params) - series = seriesXML.getiterator('Series') + urlData = helpers.getURL(finalURL) - results = [] + try: + seriesXML = etree.ElementTree(etree.XML(urlData)) + series = seriesXML.getiterator('Series') - for curSeries in series: - results.append((int(curSeries.findtext('seriesid')), curSeries.findtext('SeriesName'), curSeries.findtext('FirstAired'))) + except Exception, e: + # use finalURL in log, because urlData can be too much information + logger.log(u"Unable to parse XML for some reason: "+ex(e)+" from XML: "+finalURL, logger.ERROR) + series = '' + + # add each result to our list + for curSeries in series: + tvdb_id = int(curSeries.findtext('seriesid')) + + # don't add duplicates + if tvdb_id in [x[0] for x in results]: + continue + + results.append((tvdb_id, curSeries.findtext('SeriesName'), curSeries.findtext('FirstAired'))) lang_id = tvdb_api.Tvdb().config['langabbv_to_id'][lang] @@ -1790,13 +1983,20 @@ class ErrorLogs: class Home: @cherrypy.expose - def is_alive(self): + def is_alive(self, *args, **kwargs): + if 'callback' in kwargs and '_' in kwargs: + callback, _ = kwargs['callback'], kwargs['_'] + else: + return "Error: Unsupported Request. Send jsonp request with 'callback' variable in the query stiring." cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + cherrypy.response.headers['Content-Type'] = 'text/javascript' + cherrypy.response.headers['Access-Control-Allow-Origin'] = '*' + cherrypy.response.headers['Access-Control-Allow-Headers'] = 'x-requested-with' if sickbeard.started: - return str(sickbeard.PID) + return callback+'('+json.dumps({"msg": str(sickbeard.PID)})+');' else: - return "nope" + return callback+'('+json.dumps({"msg": "nope"})+');' @cherrypy.expose def index(self): @@ -1809,6 +2009,20 @@ class Home: postprocess = HomePostProcess() + @cherrypy.expose + def testSABnzbd(self, host=None, username=None, password=None, apikey=None): + if not host.endswith("/"): + host = host + "/" + connection, accesMsg = sab.getSabAccesMethod(host, username, password, apikey) + if connection: + authed, authMsg = sab.testAuthentication(host, username, password, apikey) #@UnusedVariable + if authed: + return "Success. Connected and authenticated" + else: + return "Authentication failed. SABnzbd expects '"+accesMsg+"' as authentication method" + else: + return "Unable to connect to host" + @cherrypy.expose def testGrowl(self, host=None, password=None): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" @@ -1844,6 +2058,26 @@ class Home: else: return "Error sending Notifo notification" + @cherrypy.expose + def testBoxcar(self, username=None): + cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + + result = notifiers.boxcar_notifier.test_notify(username) + if result: + return "Boxcar notification succeeded. Check your Boxcar clients to make sure it worked" + else: + return "Error sending Boxcar notification" + + @cherrypy.expose + def testPushover(self, userKey=None): + cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + + result = notifiers.pushover_notifier.test_notify(userKey) + if result: + return "Pushover notification succeeded. Check your Pushover clients to make sure it worked" + else: + return "Error sending Pushover notification" + @cherrypy.expose def twitterStep1(self): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" @@ -1876,7 +2110,7 @@ class Home: cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" result = notifiers.xbmc_notifier.test_notify(urllib.unquote_plus(host), username, password) - if result: + if len(result.split(":")) > 2 and 'OK' in result.split(":")[2]: return "Test notice sent successfully to "+urllib.unquote_plus(host) else: return "Test notice failed to "+urllib.unquote_plus(host) @@ -1920,6 +2154,25 @@ class Home: else: return '{"message": "Failed! Make sure your Popcorn is on and NMJ is running. (see Log & Errors -> Debug for detailed info)", "database": "", "mount": ""}' + @cherrypy.expose + def testTrakt(self, api=None, username=None, password=None): + cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + + result = notifiers.trakt_notifier.test_notify(api, username, password) + if result: + return "Test notice sent successfully to Trakt" + else: + return "Test notice failed to Trakt" + + @cherrypy.expose + def testNMA(self, nma_api=None, nma_priority=0): + cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + + result = notifiers.nma_notifier.test_notify(nma_api, nma_priority) + if result: + return "Test NMA notice sent successfully" + else: + return "Test NMA notice failed" @cherrypy.expose def shutdown(self): @@ -2135,7 +2388,7 @@ class Home: # if we change location clear the db of episodes, change it, write to db, and rescan if os.path.normpath(showObj._location) != os.path.normpath(location): - logger.log(os.path.normpath(showObj._location)+" != "+os.path.normpath(location)) + logger.log(os.path.normpath(showObj._location)+" != "+os.path.normpath(location), logger.DEBUG) if not ek.ek(os.path.isdir, location): errors.append("New location <tt>%s</tt> does not exist" % location) @@ -2239,27 +2492,27 @@ class Home: redirect("/home/displayShow?show="+str(showObj.tvdbid)) - @cherrypy.expose - def updateXBMC(self, showName=None): - - for curHost in [x.strip() for x in sickbeard.XBMC_HOST.split(",")]: - if notifiers.xbmc_notifier._update_library(curHost, showName=showName): - ui.notifications.message("Command sent to XBMC host " + curHost + " to update library") - else: - ui.notifications.error("Unable to contact XBMC host " + curHost) - redirect('/home') - - - @cherrypy.expose - def updatePLEX(self): - - if notifiers.plex_notifier._update_library(): - ui.notifications.message("Command sent to Plex Media Server host " + sickbeard.PLEX_HOST + " to update library") - logger.log(u"Plex library update initiated for host " + sickbeard.PLEX_HOST, logger.DEBUG) - else: - ui.notifications.error("Unable to contact Plex Media Server host " + sickbeard.PLEX_HOST) - logger.log(u"Plex library update failed for host " + sickbeard.PLEX_HOST, logger.ERROR) - redirect('/home') + @cherrypy.expose + def updateXBMC(self, showName=None): + + for curHost in [x.strip() for x in sickbeard.XBMC_HOST.split(",")]: + if notifiers.xbmc_notifier._update_library(curHost, showName=showName): + ui.notifications.message("Command sent to XBMC host " + curHost + " to update library") + else: + ui.notifications.error("Unable to contact XBMC host " + curHost) + redirect('/home') + + + @cherrypy.expose + def updatePLEX(self): + + if notifiers.plex_notifier._update_library(): + ui.notifications.message("Command sent to Plex Media Server host " + sickbeard.PLEX_HOST + " to update library") + logger.log(u"Plex library update initiated for host " + sickbeard.PLEX_HOST, logger.DEBUG) + else: + ui.notifications.error("Unable to contact Plex Media Server host " + sickbeard.PLEX_HOST) + logger.log(u"Plex library update failed for host " + sickbeard.PLEX_HOST, logger.ERROR) + redirect('/home') @cherrypy.expose @@ -2407,6 +2660,7 @@ class UI: return json.dumps(messages) + class WebInterface: @cherrypy.expose @@ -2455,9 +2709,10 @@ class WebInterface: size = 136, 200 else: return cherrypy.lib.static.serve_file(image_file_name, content_type="image/jpeg") - im.thumbnail(size, Image.ANTIALIAS) + im = im.resize(size, Image.ANTIALIAS) buffer = StringIO() - im.save(buffer, 'JPEG') + im.save(buffer, 'JPEG', quality=85) + cherrypy.response.headers['Content-Type'] = 'image/jpeg' return buffer.getvalue() else: return cherrypy.lib.static.serve_file(default_image_path, content_type="image/jpeg") @@ -2556,6 +2811,8 @@ class WebInterface: config = Config() home = Home() + + api = Api() browser = browser.WebFileBrowser() diff --git a/sickbeard/webserveInit.py b/sickbeard/webserveInit.py index 42fac12fff71f1576ae64f19bb343bd6a5802903..b8c17c3bde7185a4e877552bb6642dacb5cb7c01 100644 --- a/sickbeard/webserveInit.py +++ b/sickbeard/webserveInit.py @@ -20,9 +20,13 @@ import cherrypy.lib.auth_basic import os.path +import sickbeard + from sickbeard import logger from sickbeard.webserve import WebInterface +from sickbeard.helpers import create_https_certificates + def initWebServer(options = {}): options.setdefault('port', 8081) options.setdefault('host', '0.0.0.0') @@ -33,23 +37,76 @@ def initWebServer(options = {}): assert isinstance(options['port'], int) assert 'data_root' in options - # cherrypy setup - cherrypy.config.update({ - 'server.socket_port': options['port'], - 'server.socket_host': options['host'], - 'log.screen': False, - }) - - #HTTP Errors def http_error_401_hander(status, message, traceback, version): - args = [status, message, traceback, version] - if int(status) == 401: - logger.log(u"Authentication error, check cherrypy log for more details", logger.WARNING) - else: + """ Custom handler for 401 error """ + if status != "401 Unauthorized": logger.log(u"CherryPy caught an error: %s %s" % (status, message), logger.ERROR) logger.log(traceback, logger.DEBUG) - return "<html><body><h1>Error %s</h1>Something unexpected has happened. Please check the log.</body></html>" % args[0] - cherrypy.config.update({'error_page.401' : http_error_401_hander}) + return r''' +<html> + <head> + <title>%s</title> + </head> + <body> + <br/> + <font color="#0000FF">Error %s: You need to provide a valid username and password.</font> + </body> +</html> +''' % ('Access denied', status) + + def http_error_404_hander(status, message, traceback, version): + """ Custom handler for 404 error, redirect back to main page """ + return r''' +<html> + <head> + <title>404</title> + <script type="text/javascript" charset="utf-8"> + <!-- + location.href = "%s" + //--> + </script> + </head> + <body> + <br/> + </body> +</html> +''' % '/' + + # cherrypy setup + enable_https = options['enable_https'] + https_cert = options['https_cert'] + https_key = options['https_key'] + + if enable_https: + # If either the HTTPS certificate or key do not exist, make some self-signed ones. + if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)): + if not create_https_certificates(https_cert, https_key): + logger.log(u"Unable to create cert/key files, disabling HTTPS") + sickbeard.ENABLE_HTTPS = False + enable_https = False + + if not (os.path.exists(https_cert) and os.path.exists(https_key)): + logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING) + sickbeard.ENABLE_HTTPS = False + enable_https = False + + options_dict = { + 'server.socket_port': options['port'], + 'server.socket_host': options['host'], + 'log.screen': False, + 'error_page.401': http_error_401_hander, + 'error_page.404': http_error_404_hander, + } + + if enable_https: + options_dict['server.ssl_certificate'] = https_cert + options_dict['server.ssl_private_key'] = https_key + protocol = "https" + else: + protocol = "http" + + logger.log(u"Starting Sick Beard on "+protocol+"://" + str(options['host']) + ":" + str(options['port']) + "/") + cherrypy.config.update(options_dict) # setup cherrypy logging if options['log_dir'] and os.path.isdir(options['log_dir']): @@ -85,9 +142,18 @@ def initWebServer(options = {}): 'tools.auth_basic.on': True, 'tools.auth_basic.realm': 'SickBeard', 'tools.auth_basic.checkpassword': checkpassword + }, + '/api':{ + 'tools.auth_basic.on': False + }, + '/api/builder':{ + 'tools.auth_basic.on': True, + 'tools.auth_basic.realm': 'SickBeard', + 'tools.auth_basic.checkpassword': checkpassword } }) + cherrypy.server.start() cherrypy.server.wait() diff --git a/tests/name_parser_tests.py b/tests/name_parser_tests.py index 1e62cf0f2a94a9c1f40f0cbca8fa34b4752b60fd..e0fbef52b9a874fe38374c1eb8a8e2456ec8d576 100644 --- a/tests/name_parser_tests.py +++ b/tests/name_parser_tests.py @@ -111,7 +111,7 @@ combination_test_cases = [ parser.ParseResult(None, 'Show Name', 2, [3], 'Source.Quality.Etc', 'Group'), ['stupid', 'season_only']), - ('MythBusters.S08E16.720p.HDTV.x264-aAF\\aaf-mb.s08e16.720p.mkv', + ('MythBusters.S08E16.720p.HDTV.x264-aAF/aaf-mb.s08e16.720p.mkv', parser.ParseResult(None, 'MythBusters', 8, [16], '720p.HDTV.x264', 'aAF'), ['standard']), @@ -119,11 +119,11 @@ combination_test_cases = [ parser.ParseResult(None, None, 2, [6], 'The Tower is Tall, But the Fall is Short'), ['standard']), - (r'Q:\Test\TV\Jimmy Fallon\Season 2\Jimmy Fallon - 2010-12-15 - blah.avi', + (r'/Test/TV/Jimmy Fallon/Season 2/Jimmy Fallon - 2010-12-15 - blah.avi', parser.ParseResult(None, 'Jimmy Fallon', extra_info = 'blah', air_date = datetime.date(2010,12,15)), ['scene_date_format']), - (r'x:\30 Rock\Season 4\30 Rock - 4x22 -.avi', + (r'/X/30 Rock/Season 4/30 Rock - 4x22 -.avi', parser.ParseResult(None, '30 Rock', 4, [22]), ['fov']), @@ -138,6 +138,9 @@ unicode_test_cases = [ ), ] +failure_cases = ['7sins-jfcs01e09-720p-bluray-x264'] + + class UnicodeTests(unittest.TestCase): def _test_unicode(self, name, result): @@ -150,6 +153,23 @@ class UnicodeTests(unittest.TestCase): for (name, result) in unicode_test_cases: self._test_unicode(name, result) +class FailureCaseTests(unittest.TestCase): + + def _test_name(self, name): + np = parser.NameParser(True) + try: + parse_result = np.parse(name) + except parser.InvalidNameException: + return True + + if VERBOSE: + print 'Actual: ', parse_result.which_regex, parse_result + return False + + def test_failures(self): + for name in failure_cases: + self.assertTrue(self._test_name(name)) + class ComboTests(unittest.TestCase): def _test_combo(self, name, result, which_regexes): @@ -174,7 +194,9 @@ class ComboTests(unittest.TestCase): def test_combos(self): for (name, result, which_regexes) in combination_test_cases: - self._test_combo(name, result, which_regexes) + # Normalise the paths. Converts UNIX-style paths into Windows-style + # paths when test is run on Windows. + self._test_combo(os.path.normpath(name), result, which_regexes) class BasicTests(unittest.TestCase): @@ -308,3 +330,6 @@ if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(UnicodeTests) unittest.TextTestRunner(verbosity=2).run(suite) + + suite = unittest.TestLoader().loadTestsFromTestCase(FailureCaseTests) + unittest.TextTestRunner(verbosity=2).run(suite)