├── AUTHORS ├── form.py ├── model.py ├── static ├── actions.js ├── date.js ├── jquery.countdown.css ├── layout.css ├── jquery.countdown.js └── jquery.js ├── config.py ├── cherrypy.conf ├── util.py ├── README ├── templates ├── submit.html ├── layout.html └── index.html ├── updater.py ├── template.py ├── snipe.py ├── watcher.py ├── web.py ├── ebay.py └── COPYING /AUTHORS: -------------------------------------------------------------------------------- 1 | Sergey Anufrienko 2 | -------------------------------------------------------------------------------- /form.py: -------------------------------------------------------------------------------- 1 | from formencode import Schema, validators 2 | 3 | class ItemForm(Schema): 4 | id = validators.Int() 5 | maxbid = validators.Number() 6 | 7 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | 2 | class Item(object): 3 | def __init__(self, id, maxbid): 4 | self.id = id 5 | self.maxbid = maxbid 6 | self.info = None 7 | self.last_update = None 8 | self.ignore = False 9 | 10 | -------------------------------------------------------------------------------- /static/actions.js: -------------------------------------------------------------------------------- 1 | 2 | function domReady() 3 | { 4 | $("td.endtime").each(function() { 5 | $(this).countdown({ 6 | until: fromISO8601($(this).text()), 7 | compact: true 8 | }); 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | 2 | class Config: 3 | # EBay user credentials 4 | username = "user" 5 | password = "pass" 6 | 7 | # How many seconds until the end of the listing 8 | # will trigger the sniping procedure 9 | bidtime = 10 10 | 11 | # Filled in from the database 12 | items = { } 13 | -------------------------------------------------------------------------------- /cherrypy.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | server.socket_host = "0.0.0.0" 3 | server.socket_port = 8080 4 | tools.encode.on = True 5 | tools.encode.encoding = "utf-8" 6 | tools.decode.on = True 7 | tools.trailing_slash.on = True 8 | 9 | [/media] 10 | tools.staticdir.on = True 11 | tools.staticdir.dir = "static" 12 | 13 | -------------------------------------------------------------------------------- /util.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | from BeautifulSoup import BeautifulSoup, NavigableString 4 | 5 | def textOf(soup): 6 | if soup == None: 7 | return str(None) 8 | elif isinstance(soup, NavigableString): 9 | return str(soup) 10 | return str(' '.join(soup.findAll(text=True))) 11 | 12 | def stripSpaces(input): 13 | return re.sub('\s{2,}', ' ', input).strip() 14 | 15 | def stripCurrency(input): 16 | try: 17 | return float(re.search('([0-9.,]+)', input).groups(1)[0].replace(",", "")) 18 | except: 19 | return 0 20 | 21 | def fieldText(soup, descend = True): 22 | if soup == None: 23 | return None 24 | target = soup.parent.nextSibling.find("span") if descend else soup 25 | return stripSpaces(textOf(target)) 26 | 27 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is an open source eBay sniper written in Python. 2 | Tested to work under Linux 2.6 and Python 2.6.4 in May 2010. 3 | 4 | Prerequisites: 5 | - Python 2.6 6 | - mechanize 0.1 7 | - BautifulSoup 3.0 8 | - Genshi 0.5 9 | - FormEncode 1.2 10 | - CherryPy 3.1.2 11 | 12 | For configuration see config.py 13 | 14 | This code is distributed under the GPL license version 2, see COPYING for details. 15 | 16 | The current version is a beta version, which still contains some unstable code, and 17 | possible concurrency & thread synchronization issues, but should generally work fine. 18 | 19 | These issues will be fixed in future releases. 20 | 21 | If you would like to contact the author, please see the AUTHORS file. Thank you. 22 | 23 | -------------------------------------------------------------------------------- /static/date.js: -------------------------------------------------------------------------------- 1 | 2 | function fromISO8601(dString) { 3 | var regexp = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)(:)?(\d\d)(\.\d+)?(Z|([+-])(\d\d)(:)?(\d\d))/; 4 | var date = new Date(); 5 | if (dString.toString().match(new RegExp(regexp))) { 6 | var d = dString.match(new RegExp(regexp)); 7 | var offset = 0; 8 | date.setUTCDate(1); 9 | date.setUTCFullYear(parseInt(d[1],10)); 10 | date.setUTCMonth(parseInt(d[3],10) - 1); 11 | date.setUTCDate(parseInt(d[5],10)); 12 | date.setUTCHours(parseInt(d[7],10)); 13 | date.setUTCMinutes(parseInt(d[9],10)); 14 | date.setUTCSeconds(parseInt(d[11],10)); 15 | if (d[12]) 16 | date.setUTCMilliseconds(parseFloat(d[12]) * 1000); 17 | else 18 | date.setUTCMilliseconds(0); 19 | if (d[13] != 'Z') { 20 | offset = (d[15] * 60) + parseInt(d[17],10); 21 | offset *= ((d[14] == '-') ? -1 : 1); 22 | date.setTime(date.getTime() - offset * 60 * 1000); 23 | } 24 | } 25 | else 26 | { 27 | date.setTime(Date.parse(dString)); 28 | } 29 | return date; 30 | }; 31 | -------------------------------------------------------------------------------- /static/jquery.countdown.css: -------------------------------------------------------------------------------- 1 | /* jQuery Countdown styles 1.5.8. */ 2 | .hasCountdown { 3 | border: 1px solid #ccc; 4 | background-color: #eee; 5 | } 6 | .countdown_rtl { 7 | direction: rtl; 8 | } 9 | .countdown_holding span { 10 | background-color: #ccc; 11 | } 12 | .countdown_row { 13 | clear: both; 14 | width: 100%; 15 | padding: 0px 2px; 16 | text-align: center; 17 | } 18 | .countdown_show1 .countdown_section { 19 | width: 98%; 20 | } 21 | .countdown_show2 .countdown_section { 22 | width: 48%; 23 | } 24 | .countdown_show3 .countdown_section { 25 | width: 32.5%; 26 | } 27 | .countdown_show4 .countdown_section { 28 | width: 24.5%; 29 | } 30 | .countdown_show5 .countdown_section { 31 | width: 19.5%; 32 | } 33 | .countdown_show6 .countdown_section { 34 | width: 16.25%; 35 | } 36 | .countdown_show7 .countdown_section { 37 | width: 14%; 38 | } 39 | .countdown_section { 40 | display: block; 41 | float: left; 42 | font-size: 75%; 43 | text-align: center; 44 | } 45 | .countdown_amount { 46 | font-size: 200%; 47 | } 48 | .countdown_descr { 49 | display: block; 50 | width: 100%; 51 | } 52 | -------------------------------------------------------------------------------- /templates/submit.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Add new item 8 | 9 | 10 |

Add new item

11 | 12 |
13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 35 | 36 | 37 |
18 | 19 | ${errors.id} 20 |
25 | 26 | ${errors.maxbid} 27 |
32 | 33 | 34 |
38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /updater.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | from dateutil.tz import tzlocal 4 | from datetime import datetime, timedelta 5 | from config import Config 6 | 7 | class ItemUpdater: 8 | def __init__(self, cli): 9 | self.cli = cli 10 | 11 | def updateItem(self, item): 12 | item.info = self.cli.getItemInfo(item.id) 13 | item.last_update = datetime.now(tzlocal()) 14 | self.rescheduleItem(item) 15 | 16 | def rescheduleItem(self, item): 17 | delta = item.info['timedelta'] 18 | 19 | if delta < timedelta(): 20 | return 21 | elif(delta > timedelta(2, 0, 0)): 22 | interval = 86400 23 | elif(delta > timedelta(1, 0, 0)): 24 | interval = 3600 25 | elif(delta > timedelta(0, 3600, 0)): 26 | interval = 600 27 | elif(delta > timedelta(0, 600, 0)): 28 | interval = 300 29 | elif(delta < timedelta(0, 600, 0) and delta > timedelta(0, 300, 0)): 30 | interval = 60 31 | else: 32 | interval = 30 33 | 34 | print "set interval %d for delta %s" % (interval, delta) 35 | timer = threading.Timer(interval, self.updateItem, [item]) 36 | timer.start() 37 | 38 | def start(self): 39 | for item in Config.items.values(): 40 | self.updateItem(item) 41 | 42 | 43 | -------------------------------------------------------------------------------- /template.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cherrypy 3 | from genshi.core import Stream 4 | from genshi.output import encode, get_serializer 5 | from genshi.template import Context, TemplateLoader 6 | 7 | loader = TemplateLoader( 8 | os.path.join(os.path.dirname(__file__), 'templates'), 9 | auto_reload=True 10 | ) 11 | 12 | def output(filename, method='html', encoding='utf-8', **options): 13 | def decorate(func): 14 | def wrapper(*args, **kwargs): 15 | cherrypy.thread_data.template = loader.load(filename) 16 | opt = options.copy() 17 | if method == 'html': 18 | opt.setdefault('doctype', 'html') 19 | serializer = get_serializer(method, **opt) 20 | stream = func(*args, **kwargs) 21 | if not isinstance(stream, Stream): 22 | return stream 23 | return encode(serializer(stream), method=serializer,encoding=encoding) 24 | return wrapper 25 | return decorate 26 | 27 | def render(*args, **kwargs): 28 | if args: 29 | assert len(args) == 1, \ 30 | 'Expected exactly one argument, but got %r' % (args,) 31 | template = loader.load(args[0]) 32 | else: 33 | template = cherrypy.thread_data.template 34 | ctxt = Context(url=cherrypy.url) 35 | ctxt.push(kwargs) 36 | return template.generate(ctxt) 37 | 38 | -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <py:if test="title">${title}</py:if> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | ${select('*[local-name()!="title"]')} 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 |
26 | ${select('*|text()')} 27 |
28 | 32 |
33 | 34 |
35 | 36 | -------------------------------------------------------------------------------- /snipe.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import signal, sys, os, traceback, pickle 4 | from ebay import EBayClient 5 | from web import WebServer 6 | from updater import ItemUpdater 7 | from watcher import ItemWatcher 8 | from config import Config 9 | 10 | cli = EBayClient() 11 | itemUpdater = ItemUpdater(cli) 12 | itemWatcher = ItemWatcher(cli) 13 | webServer = WebServer(cli, itemUpdater) 14 | 15 | def signalHandler(signum, frame): 16 | if (signum == signal.SIGINT): 17 | print 'Caught SIGINT, shutting down...' 18 | exit(1) 19 | 20 | def exit(code): 21 | webServer.stop() 22 | sys.exit(code) 23 | 24 | def main(filename): 25 | signal.signal(signal.SIGINT, signalHandler) 26 | 27 | if os.path.exists(filename): 28 | fileObj = open(filename, "rb") 29 | try: 30 | Config.items = pickle.load(fileObj) 31 | finally: 32 | fileObj.close() 33 | else: 34 | Config.items = { } 35 | 36 | def _saveData(): 37 | fileObj = open(filename, "wb") 38 | try: 39 | pickle.dump(Config.items, fileObj) 40 | finally: 41 | fileObj.close() 42 | 43 | try: 44 | webServer.subscribe(_saveData) 45 | webServer.start() 46 | itemUpdater.start() 47 | itemWatcher.start() 48 | 49 | raw_input("Press Ctrl+C key to exit\n") 50 | print "Shutting down..." 51 | exit(0) 52 | except Exception, e: 53 | print "Caught error: %s" % e 54 | traceback.print_exc(file=sys.stdout) 55 | exit(2) 56 | 57 | if __name__ == "__main__": 58 | main("snipe.db") 59 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Item Watcher 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
IDDescriptionTime LeftLast Update
23 | ${item.id}

24 | Delete 25 |
${item.info.name}${item.info.timeleft}${item.last_update}
EndsBidsCurrentMinimumMaximumShippingReturns
${item.info.isoendtime}${item.info.bidhistory}${item.info.bid}${item.info.minbid}${item.maxbid}${item.info.shipping}${item.info.returns}
51 |

Add new item

52 | 53 | 54 | -------------------------------------------------------------------------------- /watcher.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | from dateutil.tz import tzlocal 4 | from datetime import datetime, timedelta 5 | from config import Config 6 | from ebay import EBayClient 7 | 8 | class ItemWatcher(threading.Thread): 9 | def __init__(self, cli): 10 | threading.Thread.__init__(self) 11 | self.cli = EBayClient() 12 | self.logged_in = False 13 | 14 | def timeLeft(self, item): 15 | if item.info == None: 16 | return None 17 | return item.info['endtime'] - datetime.now(tzlocal()) 18 | 19 | def watchItem(self, item): 20 | if item.info == None: 21 | return 22 | 23 | time_left = self.timeLeft(item) 24 | if (time_left == timedelta()): 25 | return 26 | 27 | if time_left < timedelta(0, Config.bidtime, 0) and not item.ignore: 28 | try: 29 | if item.maxbid >= item.info['minbid']: 30 | print "Sniping item %d (our bid %d)" % (item.id, item.maxbid) 31 | self.cli.bid(item.id, item.maxbid) 32 | print "Successful bid at %s! Hope you win!" % (self.timeLeft(item)) 33 | else: 34 | print "Skipping item %d as our max bid is lower than current minimum" % (item.maxbid) 35 | except Exception, e: 36 | print "BID FAILED: %s" % e 37 | finally: 38 | self.logged_in = False 39 | item.ignore = True 40 | 41 | elif time_left < timedelta(0, 300, 0) and not self.logged_in: 42 | try: 43 | print "Logging in to eBay as %s..." % Config.username 44 | self.cli.login(Config.username, Config.password) 45 | self.logged_in = True 46 | except Exception, e: 47 | print "FATAL: Login failed: %s" % e 48 | 49 | 50 | def run(self): 51 | while True: 52 | time.sleep(1) 53 | for item in Config.items.values(): 54 | self.watchItem(item) 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /static/layout.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body { 7 | background: #ddd; 8 | color: #333; 9 | font: normal 90%/1.3 Arial, Helvetica, sans-serif; 10 | } 11 | 12 | table td { 13 | background: #ccc; 14 | padding: 2px; 15 | text-align: center; 16 | } 17 | 18 | form table td { 19 | text-align: left; 20 | } 21 | 22 | :link, :visited { 23 | color: #c10000; 24 | text-decoration: none; 25 | } 26 | 27 | :link:hover, :visited:hover { 28 | text-decoration: underline; 29 | } 30 | 31 | :link img, :visited img { 32 | border: none; 33 | } 34 | 35 | .action:link, .action:visited { 36 | background: #f3f3f3; 37 | border: 1px outset #ddd; 38 | color: #666; 39 | font-size: 90%; 40 | padding: 0 .3em; 41 | } 42 | 43 | .action:link:hover, .action:visited:hover { 44 | background: #e8e8e8; 45 | border-color: #aaa; 46 | color: #000; 47 | text-decoration: none; 48 | } 49 | 50 | h1 { 51 | color: #666; 52 | font: normal xx-large/1.5 Georgia, serif; 53 | margin: 0 0 .5em; 54 | } 55 | 56 | blockquote { 57 | font-style: italic; 58 | } 59 | 60 | form table { 61 | margin-bottom: 1em; 62 | } 63 | 64 | form table tbody th { 65 | font-weight: normal; 66 | padding-top: .3em; 67 | text-align: right; 68 | vertical-align: top; 69 | } 70 | 71 | form label { 72 | color: #666; 73 | font-size: 90%; 74 | } 75 | 76 | form p.hint { 77 | color: #666; 78 | font-size: 90%; 79 | font-style: italic; 80 | margin: 0; 81 | } 82 | 83 | form .error { 84 | color: #b00; 85 | } 86 | 87 | #wrap { 88 | background: #fff; 89 | margin: 30px auto; 90 | } 91 | 92 | #content { 93 | border-left: 10px solid #b00; 94 | min-height: 240px; 95 | padding: 10px; 96 | } 97 | 98 | #footer { 99 | background: #4A4D4D; 100 | border-top: 2px solid #333; 101 | font-size: x-small; 102 | padding: 3px; 103 | text-align: center; 104 | } 105 | 106 | #footer hr { 107 | display: none; 108 | } 109 | 110 | .legalese { 111 | color: #999; 112 | margin: 0; 113 | } 114 | -------------------------------------------------------------------------------- /web.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import operator, os, sys 3 | import cherrypy 4 | import template 5 | from config import Config 6 | from model import Item 7 | from updater import ItemUpdater 8 | from form import ItemForm 9 | from formencode import Invalid 10 | from genshi.input import HTML 11 | from genshi.filters import HTMLFormFiller, HTMLSanitizer 12 | from ebay import ItemNotFoundException 13 | 14 | class Root(object): 15 | def __init__(self, updater): 16 | self.updater = updater 17 | 18 | @cherrypy.expose 19 | @template.output("index.html") 20 | def index(self): 21 | return template.render(items=Config.items.values()) 22 | 23 | @cherrypy.expose 24 | def delete(self, id=None, *args, **kw): 25 | id = int(id) 26 | if id in Config.items: 27 | del Config.items[id] 28 | raise cherrypy.HTTPRedirect('/') 29 | 30 | @cherrypy.expose 31 | @template.output('submit.html') 32 | def submit(self, cancel=False, **data): 33 | if cherrypy.request.method == 'POST': 34 | if cancel: 35 | raise cherrypy.HTTPRedirect('/') 36 | form = ItemForm() 37 | try: 38 | data = form.to_python(data) 39 | item = Item(**data) 40 | self.updater.updateItem(item) 41 | Config.items[item.id] = item 42 | raise cherrypy.HTTPRedirect('/') 43 | except Invalid, e: 44 | errors = e.unpack_errors() 45 | except ItemNotFoundException, e: 46 | errors = { "id" : e } 47 | else: 48 | errors = {} 49 | 50 | return template.render(errors=errors) | HTMLFormFiller(data=data) 51 | 52 | class WebServer(threading.Thread): 53 | def __init__(self, cli, updater): 54 | threading.Thread.__init__(self) 55 | self.cli = cli 56 | self.updater = updater 57 | 58 | def stop(self): 59 | cherrypy.engine.exit() 60 | 61 | def subscribe(self, callback): 62 | if hasattr(cherrypy.engine, 'subscribe'): 63 | cherrypy.engine.subscribe('stop', callback) 64 | else: 65 | cherrypy.engine.on_stop_engine_list.append(callback) 66 | 67 | def run(self): 68 | cherrypy.config.update({ 'global': { 69 | 'tools.staticdir.root': os.path.abspath(os.path.dirname(__file__)), 70 | 'log.screen': False, 71 | 'engine.SIGHUP': None, 72 | 'engine.SIGTERM': None 73 | } 74 | }) 75 | cherrypy.quickstart(Root(self.updater), '/', "cherrypy.conf") 76 | 77 | 78 | -------------------------------------------------------------------------------- /ebay.py: -------------------------------------------------------------------------------- 1 | import re 2 | import mechanize 3 | import sys, os 4 | import pytz 5 | from BeautifulSoup import BeautifulSoup 6 | from dateutil.parser import * 7 | from dateutil.tz import * 8 | from datetime import * 9 | from util import * 10 | 11 | class LoginException(Exception): pass 12 | class NotLoggedInException(Exception): pass 13 | class ItemNotFoundException(Exception): pass 14 | class IncorrectValueException(Exception): pass 15 | class OutbidException(Exception): pass 16 | class ParseException(Exception): pass 17 | 18 | class EBayClient: 19 | TZINFOS = { 20 | 'PDT': -25200, # UTC-7 21 | 'PST': -28800 # UTC-8 22 | } 23 | 24 | item_page = "http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&item=%s" 25 | bid_page = "http://offer.ebay.com/ws/eBayISAPI.dll?MakeBid&item=%s" 26 | 27 | def __init__(self): 28 | self.br = mechanize.Browser(factory=mechanize.RobustFactory()) 29 | 30 | def login(self, login, password): 31 | self.br.open('http://www.ebay.com/') 32 | self.br.set_handle_refresh(None, True) 33 | self.br.set_debug_redirects(True) 34 | self.br.set_handle_robots(False) 35 | 36 | try: 37 | response = self.br.follow_link(text_regex=re.compile(r'Sign in'), nr=0) 38 | assert self.br.viewing_html() 39 | response.close(); 40 | except mechanize._mechanize.LinkNotFoundError: 41 | print "Already logged in, skipping" 42 | return 43 | 44 | self.br.select_form(name='SignInForm') 45 | self.br['userid'] = login 46 | self.br['pass'] = password 47 | response = self.br.submit() 48 | 49 | try: 50 | response = self.br.follow_link(text_regex=re.compile(r'Continue')) 51 | except mechanize._mechanize.LinkNotFoundError: 52 | raise LoginException("Login failed for user %s" % login) 53 | 54 | def getBidURL(self, item): 55 | return self.bid_page % item 56 | 57 | def getItemURL(self, item): 58 | return self.item_page % item 59 | 60 | def getItemInfo(self, item): 61 | try: 62 | self.br.open(self.getItemURL(item)) 63 | except: 64 | raise ItemNotFoundException("Unable to open item page") 65 | 66 | page = self.br.response().read() 67 | m = re.match('^(.+) - eBay \(item ([0-9]+) end time (.+)\)$', self.br.title()) 68 | (description, id, end_strtime) = m.group(1, 2, 3) 69 | end_time = parse(end_strtime, tzinfos=self.TZINFOS) 70 | now_time = datetime.now(tzlocal()) 71 | 72 | result = dict() 73 | soup = BeautifulSoup(page) 74 | info = soup.find("form", "vi-is1-s4").find("table") 75 | minbid_re = "\(Enter (.+) or more\)" 76 | 77 | result['id'] = item 78 | result['name'] = description 79 | result['condition'] = fieldText(info.find(text=re.compile("Item condition"))); 80 | result['timeleft'] = fieldText(info.find(text=re.compile("Time left"))); 81 | result['ended'] = fieldText(info.find(text=re.compile("Ended"))); 82 | result['bidhistory'] = fieldText(info.find(text=re.compile("Bid history"))); 83 | result['bid'] = stripCurrency(fieldText(info.find(text=re.compile("(Current|Starting|Winning) bid")))) 84 | result['minbid'] = stripCurrency(fieldText(info.find(text=re.compile(minbid_re)), False)) 85 | result['shipping'] = stripCurrency(fieldText(info.find(text=re.compile("Shipping")))) 86 | result['returns'] = fieldText(info.find(text=re.compile("Returns"))); 87 | result['timedelta'] = end_time - now_time 88 | result['endtime'] = end_time.astimezone(tzlocal()) 89 | result['isoendtime'] = end_time.isoformat() 90 | result['bidurl'] = self.getBidURL(item) 91 | result['itemurl'] = self.getItemURL(item) 92 | 93 | return result 94 | 95 | def bid(self, item, maxbid): 96 | try: 97 | self.br.open(self.getBidURL(item)) 98 | except: 99 | raise ItemNotFoundException("Unable to open bid page") 100 | 101 | try: 102 | self.br.select_form(name='SignInForm') 103 | raise NotLoggedInException("Not logged in") 104 | except mechanize._mechanize.FormNotFoundError: 105 | pass 106 | 107 | if 'MakeBidErrorInvalidItem' in self.br.response().read(): 108 | raise ItemNotFoundException("Item with ID %s not found" % item) 109 | 110 | try: 111 | self.br.select_form(name='PlaceBid') 112 | except mechanize._mechanize.FormNotFoundError, e: 113 | raise ParseException("Bidding form not found") 114 | 115 | self.br['maxbid'] = str(maxbid).replace('.', ',') 116 | response = self.br.submit() 117 | 118 | r = response.read() 119 | if 'must be corrected' in r: 120 | raise IncorrectValueException("Invalid value. Perhaps lower than the minimal bid?") 121 | 122 | self.br.select_form(name='PlaceBid') 123 | response = self.br.submit() 124 | r = response.read() 125 | 126 | if 'just been outbid' in r: 127 | raise OutbidException("You've just been outbid. Try to bid again") 128 | 129 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /static/jquery.countdown.js: -------------------------------------------------------------------------------- 1 | /* http://keith-wood.name/countdown.html 2 | Countdown for jQuery v1.5.8. 3 | Written by Keith Wood (kbwood{at}iinet.com.au) January 2008. 4 | Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and 5 | MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses. 6 | Please attribute the author if you use it. */ 7 | 8 | /* Display a countdown timer. 9 | Attach it with options like: 10 | $('div selector').countdown( 11 | {until: new Date(2009, 1 - 1, 1, 0, 0, 0), onExpiry: happyNewYear}); */ 12 | 13 | (function($) { // Hide scope, no $ conflict 14 | 15 | /* Countdown manager. */ 16 | function Countdown() { 17 | this.regional = []; // Available regional settings, indexed by language code 18 | this.regional[''] = { // Default regional settings 19 | // The display texts for the counters 20 | labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'], 21 | // The display texts for the counters if only one 22 | labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'], 23 | compactLabels: ['y', 'm', 'w', 'd'], // The compact texts for the counters 24 | whichLabels: null, // Function to determine which labels to use 25 | timeSeparator: ':', // Separator for time periods 26 | isRTL: false // True for right-to-left languages, false for left-to-right 27 | }; 28 | this._defaults = { 29 | until: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count down to 30 | // or numeric for seconds offset, or string for unit offset(s): 31 | // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds 32 | since: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count up from 33 | // or numeric for seconds offset, or string for unit offset(s): 34 | // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds 35 | timezone: null, // The timezone (hours or minutes from GMT) for the target times, 36 | // or null for client local 37 | serverSync: null, // A function to retrieve the current server time for synchronisation 38 | format: 'dHMS', // Format for display - upper case for always, lower case only if non-zero, 39 | // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds 40 | layout: '', // Build your own layout for the countdown 41 | compact: false, // True to display in a compact format, false for an expanded one 42 | significant: 0, // The number of periods with values to show, zero for all 43 | description: '', // The description displayed for the countdown 44 | expiryUrl: '', // A URL to load upon expiry, replacing the current page 45 | expiryText: '', // Text to display upon expiry, replacing the countdown 46 | alwaysExpire: false, // True to trigger onExpiry even if never counted down 47 | onExpiry: null, // Callback when the countdown expires - 48 | // receives no parameters and 'this' is the containing division 49 | onTick: null, // Callback when the countdown is updated - 50 | // receives int[7] being the breakdown by period (based on format) 51 | // and 'this' is the containing division 52 | tickInterval: 1 // Interval (seconds) between onTick callbacks 53 | }; 54 | $.extend(this._defaults, this.regional['']); 55 | this._serverSyncs = []; 56 | } 57 | 58 | var PROP_NAME = 'countdown'; 59 | 60 | var Y = 0; // Years 61 | var O = 1; // Months 62 | var W = 2; // Weeks 63 | var D = 3; // Days 64 | var H = 4; // Hours 65 | var M = 5; // Minutes 66 | var S = 6; // Seconds 67 | 68 | $.extend(Countdown.prototype, { 69 | /* Class name added to elements to indicate already configured with countdown. */ 70 | markerClassName: 'hasCountdown', 71 | 72 | /* Shared timer for all countdowns. */ 73 | _timer: setInterval(function() { $.countdown._updateTargets(); }, 980), 74 | /* List of currently active countdown targets. */ 75 | _timerTargets: [], 76 | 77 | /* Override the default settings for all instances of the countdown widget. 78 | @param options (object) the new settings to use as defaults */ 79 | setDefaults: function(options) { 80 | this._resetExtraLabels(this._defaults, options); 81 | extendRemove(this._defaults, options || {}); 82 | }, 83 | 84 | /* Convert a date/time to UTC. 85 | @param tz (number) the hour or minute offset from GMT, e.g. +9, -360 86 | @param year (Date) the date/time in that timezone or 87 | (number) the year in that timezone 88 | @param month (number, optional) the month (0 - 11) (omit if year is a Date) 89 | @param day (number, optional) the day (omit if year is a Date) 90 | @param hours (number, optional) the hour (omit if year is a Date) 91 | @param mins (number, optional) the minute (omit if year is a Date) 92 | @param secs (number, optional) the second (omit if year is a Date) 93 | @param ms (number, optional) the millisecond (omit if year is a Date) 94 | @return (Date) the equivalent UTC date/time */ 95 | UTCDate: function(tz, year, month, day, hours, mins, secs, ms) { 96 | if (typeof year == 'object' && year.constructor == Date) { 97 | ms = year.getMilliseconds(); 98 | secs = year.getSeconds(); 99 | mins = year.getMinutes(); 100 | hours = year.getHours(); 101 | day = year.getDate(); 102 | month = year.getMonth(); 103 | year = year.getFullYear(); 104 | } 105 | var d = new Date(); 106 | d.setUTCFullYear(year); 107 | d.setUTCDate(1); 108 | d.setUTCMonth(month || 0); 109 | d.setUTCDate(day || 1); 110 | d.setUTCHours(hours || 0); 111 | d.setUTCMinutes((mins || 0) - (Math.abs(tz) < 30 ? tz * 60 : tz)); 112 | d.setUTCSeconds(secs || 0); 113 | d.setUTCMilliseconds(ms || 0); 114 | return d; 115 | }, 116 | 117 | /* Convert a set of periods into seconds. 118 | Averaged for months and years. 119 | @param periods (number[7]) the periods per year/month/week/day/hour/minute/second 120 | @return (number) the corresponding number of seconds */ 121 | periodsToSeconds: function(periods) { 122 | return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 + 123 | periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6]; 124 | }, 125 | 126 | /* Retrieve one or more settings values. 127 | @param name (string, optional) the name of the setting to retrieve 128 | or 'all' for all instance settings or omit for all default settings 129 | @return (any) the requested setting(s) */ 130 | _settingsCountdown: function(target, name) { 131 | if (!name) { 132 | return $.countdown._defaults; 133 | } 134 | var inst = $.data(target, PROP_NAME); 135 | return (name == 'all' ? inst.options : inst.options[name]); 136 | }, 137 | 138 | /* Attach the countdown widget to a div. 139 | @param target (element) the containing division 140 | @param options (object) the initial settings for the countdown */ 141 | _attachCountdown: function(target, options) { 142 | var $target = $(target); 143 | if ($target.hasClass(this.markerClassName)) { 144 | return; 145 | } 146 | $target.addClass(this.markerClassName); 147 | var inst = {options: $.extend({}, options), 148 | _periods: [0, 0, 0, 0, 0, 0, 0]}; 149 | $.data(target, PROP_NAME, inst); 150 | this._changeCountdown(target); 151 | }, 152 | 153 | /* Add a target to the list of active ones. 154 | @param target (element) the countdown target */ 155 | _addTarget: function(target) { 156 | if (!this._hasTarget(target)) { 157 | this._timerTargets.push(target); 158 | } 159 | }, 160 | 161 | /* See if a target is in the list of active ones. 162 | @param target (element) the countdown target 163 | @return (boolean) true if present, false if not */ 164 | _hasTarget: function(target) { 165 | return ($.inArray(target, this._timerTargets) > -1); 166 | }, 167 | 168 | /* Remove a target from the list of active ones. 169 | @param target (element) the countdown target */ 170 | _removeTarget: function(target) { 171 | this._timerTargets = $.map(this._timerTargets, 172 | function(value) { return (value == target ? null : value); }); // delete entry 173 | }, 174 | 175 | /* Update each active timer target. */ 176 | _updateTargets: function() { 177 | for (var i = this._timerTargets.length - 1; i >= 0; i--) { 178 | this._updateCountdown(this._timerTargets[i]); 179 | } 180 | }, 181 | 182 | /* Redisplay the countdown with an updated display. 183 | @param target (jQuery) the containing division 184 | @param inst (object) the current settings for this instance */ 185 | _updateCountdown: function(target, inst) { 186 | var $target = $(target); 187 | inst = inst || $.data(target, PROP_NAME); 188 | if (!inst) { 189 | return; 190 | } 191 | $target.html(this._generateHTML(inst)); 192 | $target[(this._get(inst, 'isRTL') ? 'add' : 'remove') + 'Class']('countdown_rtl'); 193 | var onTick = this._get(inst, 'onTick'); 194 | if (onTick) { 195 | var periods = inst._hold != 'lap' ? inst._periods : 196 | this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date()); 197 | var tickInterval = this._get(inst, 'tickInterval'); 198 | if (tickInterval == 1 || this.periodsToSeconds(periods) % tickInterval == 0) { 199 | onTick.apply(target, [periods]); 200 | } 201 | } 202 | var expired = inst._hold != 'pause' && 203 | (inst._since ? inst._now.getTime() < inst._since.getTime() : 204 | inst._now.getTime() >= inst._until.getTime()); 205 | if (expired && !inst._expiring) { 206 | inst._expiring = true; 207 | if (this._hasTarget(target) || this._get(inst, 'alwaysExpire')) { 208 | this._removeTarget(target); 209 | var onExpiry = this._get(inst, 'onExpiry'); 210 | if (onExpiry) { 211 | onExpiry.apply(target, []); 212 | } 213 | var expiryText = this._get(inst, 'expiryText'); 214 | if (expiryText) { 215 | var layout = this._get(inst, 'layout'); 216 | inst.options.layout = expiryText; 217 | this._updateCountdown(target, inst); 218 | inst.options.layout = layout; 219 | } 220 | var expiryUrl = this._get(inst, 'expiryUrl'); 221 | if (expiryUrl) { 222 | window.location = expiryUrl; 223 | } 224 | } 225 | inst._expiring = false; 226 | } 227 | else if (inst._hold == 'pause') { 228 | this._removeTarget(target); 229 | } 230 | $.data(target, PROP_NAME, inst); 231 | }, 232 | 233 | /* Reconfigure the settings for a countdown div. 234 | @param target (element) the containing division 235 | @param options (object) the new settings for the countdown or 236 | (string) an individual property name 237 | @param value (any) the individual property value 238 | (omit if options is an object) */ 239 | _changeCountdown: function(target, options, value) { 240 | options = options || {}; 241 | if (typeof options == 'string') { 242 | var name = options; 243 | options = {}; 244 | options[name] = value; 245 | } 246 | var inst = $.data(target, PROP_NAME); 247 | if (inst) { 248 | this._resetExtraLabels(inst.options, options); 249 | extendRemove(inst.options, options); 250 | this._adjustSettings(target, inst); 251 | $.data(target, PROP_NAME, inst); 252 | var now = new Date(); 253 | if ((inst._since && inst._since < now) || 254 | (inst._until && inst._until > now)) { 255 | this._addTarget(target); 256 | } 257 | this._updateCountdown(target, inst); 258 | } 259 | }, 260 | 261 | /* Reset any extra labelsn and compactLabelsn entries if changing labels. 262 | @param base (object) the options to be updated 263 | @param options (object) the new option values */ 264 | _resetExtraLabels: function(base, options) { 265 | var changingLabels = false; 266 | for (var n in options) { 267 | if (n != 'whichLabels' && n.match(/[Ll]abels/)) { 268 | changingLabels = true; 269 | break; 270 | } 271 | } 272 | if (changingLabels) { 273 | for (var n in base) { // Remove custom numbered labels 274 | if (n.match(/[Ll]abels[0-9]/)) { 275 | base[n] = null; 276 | } 277 | } 278 | } 279 | }, 280 | 281 | /* Calculate interal settings for an instance. 282 | @param target (element) the containing division 283 | @param inst (object) the current settings for this instance */ 284 | _adjustSettings: function(target, inst) { 285 | var now; 286 | var serverSync = this._get(inst, 'serverSync'); 287 | var serverOffset = 0; 288 | var serverEntry = null; 289 | for (var i = 0; i < this._serverSyncs.length; i++) { 290 | if (this._serverSyncs[i][0] == serverSync) { 291 | serverEntry = this._serverSyncs[i][1]; 292 | break; 293 | } 294 | } 295 | if (serverEntry != null) { 296 | serverOffset = (serverSync ? serverEntry : 0); 297 | now = new Date(); 298 | } 299 | else { 300 | var serverResult = (serverSync ? serverSync.apply(target, []) : null); 301 | now = new Date(); 302 | serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0); 303 | this._serverSyncs.push([serverSync, serverOffset]); 304 | } 305 | var timezone = this._get(inst, 'timezone'); 306 | timezone = (timezone == null ? -now.getTimezoneOffset() : timezone); 307 | inst._since = this._get(inst, 'since'); 308 | if (inst._since != null) { 309 | inst._since = this.UTCDate(timezone, this._determineTime(inst._since, null)); 310 | if (inst._since && serverOffset) { 311 | inst._since.setMilliseconds(inst._since.getMilliseconds() + serverOffset); 312 | } 313 | } 314 | inst._until = this.UTCDate(timezone, this._determineTime(this._get(inst, 'until'), now)); 315 | if (serverOffset) { 316 | inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset); 317 | } 318 | inst._show = this._determineShow(inst); 319 | }, 320 | 321 | /* Remove the countdown widget from a div. 322 | @param target (element) the containing division */ 323 | _destroyCountdown: function(target) { 324 | var $target = $(target); 325 | if (!$target.hasClass(this.markerClassName)) { 326 | return; 327 | } 328 | this._removeTarget(target); 329 | $target.removeClass(this.markerClassName).empty(); 330 | $.removeData(target, PROP_NAME); 331 | }, 332 | 333 | /* Pause a countdown widget at the current time. 334 | Stop it running but remember and display the current time. 335 | @param target (element) the containing division */ 336 | _pauseCountdown: function(target) { 337 | this._hold(target, 'pause'); 338 | }, 339 | 340 | /* Pause a countdown widget at the current time. 341 | Stop the display but keep the countdown running. 342 | @param target (element) the containing division */ 343 | _lapCountdown: function(target) { 344 | this._hold(target, 'lap'); 345 | }, 346 | 347 | /* Resume a paused countdown widget. 348 | @param target (element) the containing division */ 349 | _resumeCountdown: function(target) { 350 | this._hold(target, null); 351 | }, 352 | 353 | /* Pause or resume a countdown widget. 354 | @param target (element) the containing division 355 | @param hold (string) the new hold setting */ 356 | _hold: function(target, hold) { 357 | var inst = $.data(target, PROP_NAME); 358 | if (inst) { 359 | if (inst._hold == 'pause' && !hold) { 360 | inst._periods = inst._savePeriods; 361 | var sign = (inst._since ? '-' : '+'); 362 | inst[inst._since ? '_since' : '_until'] = 363 | this._determineTime(sign + inst._periods[0] + 'y' + 364 | sign + inst._periods[1] + 'o' + sign + inst._periods[2] + 'w' + 365 | sign + inst._periods[3] + 'd' + sign + inst._periods[4] + 'h' + 366 | sign + inst._periods[5] + 'm' + sign + inst._periods[6] + 's'); 367 | this._addTarget(target); 368 | } 369 | inst._hold = hold; 370 | inst._savePeriods = (hold == 'pause' ? inst._periods : null); 371 | $.data(target, PROP_NAME, inst); 372 | this._updateCountdown(target, inst); 373 | } 374 | }, 375 | 376 | /* Return the current time periods. 377 | @param target (element) the containing division 378 | @return (number[7]) the current periods for the countdown */ 379 | _getTimesCountdown: function(target) { 380 | var inst = $.data(target, PROP_NAME); 381 | return (!inst ? null : (!inst._hold ? inst._periods : 382 | this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date()))); 383 | }, 384 | 385 | /* Get a setting value, defaulting if necessary. 386 | @param inst (object) the current settings for this instance 387 | @param name (string) the name of the required setting 388 | @return (any) the setting's value or a default if not overridden */ 389 | _get: function(inst, name) { 390 | return (inst.options[name] != null ? 391 | inst.options[name] : $.countdown._defaults[name]); 392 | }, 393 | 394 | /* A time may be specified as an exact value or a relative one. 395 | @param setting (string or number or Date) - the date/time value 396 | as a relative or absolute value 397 | @param defaultTime (Date) the date/time to use if no other is supplied 398 | @return (Date) the corresponding date/time */ 399 | _determineTime: function(setting, defaultTime) { 400 | var offsetNumeric = function(offset) { // e.g. +300, -2 401 | var time = new Date(); 402 | time.setTime(time.getTime() + offset * 1000); 403 | return time; 404 | }; 405 | var offsetString = function(offset) { // e.g. '+2d', '-4w', '+3h +30m' 406 | offset = offset.toLowerCase(); 407 | var time = new Date(); 408 | var year = time.getFullYear(); 409 | var month = time.getMonth(); 410 | var day = time.getDate(); 411 | var hour = time.getHours(); 412 | var minute = time.getMinutes(); 413 | var second = time.getSeconds(); 414 | var pattern = /([+-]?[0-9]+)\s*(s|m|h|d|w|o|y)?/g; 415 | var matches = pattern.exec(offset); 416 | while (matches) { 417 | switch (matches[2] || 's') { 418 | case 's': second += parseInt(matches[1], 10); break; 419 | case 'm': minute += parseInt(matches[1], 10); break; 420 | case 'h': hour += parseInt(matches[1], 10); break; 421 | case 'd': day += parseInt(matches[1], 10); break; 422 | case 'w': day += parseInt(matches[1], 10) * 7; break; 423 | case 'o': 424 | month += parseInt(matches[1], 10); 425 | day = Math.min(day, $.countdown._getDaysInMonth(year, month)); 426 | break; 427 | case 'y': 428 | year += parseInt(matches[1], 10); 429 | day = Math.min(day, $.countdown._getDaysInMonth(year, month)); 430 | break; 431 | } 432 | matches = pattern.exec(offset); 433 | } 434 | return new Date(year, month, day, hour, minute, second, 0); 435 | }; 436 | var time = (setting == null ? defaultTime : 437 | (typeof setting == 'string' ? offsetString(setting) : 438 | (typeof setting == 'number' ? offsetNumeric(setting) : setting))); 439 | if (time) time.setMilliseconds(0); 440 | return time; 441 | }, 442 | 443 | /* Determine the number of days in a month. 444 | @param year (number) the year 445 | @param month (number) the month 446 | @return (number) the days in that month */ 447 | _getDaysInMonth: function(year, month) { 448 | return 32 - new Date(year, month, 32).getDate(); 449 | }, 450 | 451 | /* Determine which set of labels should be used for an amount. 452 | @param num (number) the amount to be displayed 453 | @return (number) the set of labels to be used for this amount */ 454 | _normalLabels: function(num) { 455 | return num; 456 | }, 457 | 458 | /* Generate the HTML to display the countdown widget. 459 | @param inst (object) the current settings for this instance 460 | @return (string) the new HTML for the countdown display */ 461 | _generateHTML: function(inst) { 462 | // Determine what to show 463 | var significant = this._get(inst, 'significant'); 464 | inst._periods = (inst._hold ? inst._periods : 465 | this._calculatePeriods(inst, inst._show, significant, new Date())); 466 | // Show all 'asNeeded' after first non-zero value 467 | var shownNonZero = false; 468 | var showCount = 0; 469 | var sigCount = significant; 470 | var show = $.extend({}, inst._show); 471 | for (var period = Y; period <= S; period++) { 472 | shownNonZero |= (inst._show[period] == '?' && inst._periods[period] > 0); 473 | show[period] = (inst._show[period] == '?' && !shownNonZero ? null : inst._show[period]); 474 | showCount += (show[period] ? 1 : 0); 475 | sigCount -= (inst._periods[period] > 0 ? 1 : 0); 476 | } 477 | var showSignificant = [false, false, false, false, false, false, false]; 478 | for (var period = S; period >= Y; period--) { // Determine significant periods 479 | if (inst._show[period]) { 480 | if (inst._periods[period]) { 481 | showSignificant[period] = true; 482 | } 483 | else { 484 | showSignificant[period] = sigCount > 0; 485 | sigCount--; 486 | } 487 | } 488 | } 489 | var compact = this._get(inst, 'compact'); 490 | var layout = this._get(inst, 'layout'); 491 | var labels = (compact ? this._get(inst, 'compactLabels') : this._get(inst, 'labels')); 492 | var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels; 493 | var timeSeparator = this._get(inst, 'timeSeparator'); 494 | var description = this._get(inst, 'description') || ''; 495 | var showCompact = function(period) { 496 | var labelsNum = $.countdown._get(inst, 497 | 'compactLabels' + whichLabels(inst._periods[period])); 498 | return (show[period] ? inst._periods[period] + 499 | (labelsNum ? labelsNum[period] : labels[period]) + ' ' : ''); 500 | }; 501 | var showFull = function(period) { 502 | var labelsNum = $.countdown._get(inst, 'labels' + whichLabels(inst._periods[period])); 503 | return ((!significant && show[period]) || (significant && showSignificant[period]) ? 504 | '' + 505 | inst._periods[period] + '
' + 506 | (labelsNum ? labelsNum[period] : labels[period]) + '
' : ''); 507 | }; 508 | return (layout ? this._buildLayout(inst, show, layout, compact, significant, showSignificant) : 509 | ((compact ? // Compact version 510 | '' + 512 | showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) + 513 | (show[H] ? this._minDigits(inst._periods[H], 2) : '') + 514 | (show[M] ? (show[H] ? timeSeparator : '') + 515 | this._minDigits(inst._periods[M], 2) : '') + 516 | (show[S] ? (show[H] || show[M] ? timeSeparator : '') + 517 | this._minDigits(inst._periods[S], 2) : '') : 518 | // Full version 519 | '' + 521 | showFull(Y) + showFull(O) + showFull(W) + showFull(D) + 522 | showFull(H) + showFull(M) + showFull(S)) + '' + 523 | (description ? '' + description + '' : ''))); 524 | }, 525 | 526 | /* Construct a custom layout. 527 | @param inst (object) the current settings for this instance 528 | @param show (string[7]) flags indicating which periods are requested 529 | @param layout (string) the customised layout 530 | @param compact (boolean) true if using compact labels 531 | @param significant (number) the number of periods with values to show, zero for all 532 | @param showSignificant (boolean[7]) other periods to show for significance 533 | @return (string) the custom HTML */ 534 | _buildLayout: function(inst, show, layout, compact, significant, showSignificant) { 535 | var labels = this._get(inst, (compact ? 'compactLabels' : 'labels')); 536 | var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels; 537 | var labelFor = function(index) { 538 | return ($.countdown._get(inst, 539 | (compact ? 'compactLabels' : 'labels') + whichLabels(inst._periods[index])) || 540 | labels)[index]; 541 | }; 542 | var digit = function(value, position) { 543 | return Math.floor(value / position) % 10; 544 | }; 545 | var subs = {desc: this._get(inst, 'description'), sep: this._get(inst, 'timeSeparator'), 546 | yl: labelFor(Y), yn: inst._periods[Y], ynn: this._minDigits(inst._periods[Y], 2), 547 | ynnn: this._minDigits(inst._periods[Y], 3), y1: digit(inst._periods[Y], 1), 548 | y10: digit(inst._periods[Y], 10), y100: digit(inst._periods[Y], 100), 549 | y1000: digit(inst._periods[Y], 1000), 550 | ol: labelFor(O), on: inst._periods[O], onn: this._minDigits(inst._periods[O], 2), 551 | onnn: this._minDigits(inst._periods[O], 3), o1: digit(inst._periods[O], 1), 552 | o10: digit(inst._periods[O], 10), o100: digit(inst._periods[O], 100), 553 | o1000: digit(inst._periods[O], 1000), 554 | wl: labelFor(W), wn: inst._periods[W], wnn: this._minDigits(inst._periods[W], 2), 555 | wnnn: this._minDigits(inst._periods[W], 3), w1: digit(inst._periods[W], 1), 556 | w10: digit(inst._periods[W], 10), w100: digit(inst._periods[W], 100), 557 | w1000: digit(inst._periods[W], 1000), 558 | dl: labelFor(D), dn: inst._periods[D], dnn: this._minDigits(inst._periods[D], 2), 559 | dnnn: this._minDigits(inst._periods[D], 3), d1: digit(inst._periods[D], 1), 560 | d10: digit(inst._periods[D], 10), d100: digit(inst._periods[D], 100), 561 | d1000: digit(inst._periods[D], 1000), 562 | hl: labelFor(H), hn: inst._periods[H], hnn: this._minDigits(inst._periods[H], 2), 563 | hnnn: this._minDigits(inst._periods[H], 3), h1: digit(inst._periods[H], 1), 564 | h10: digit(inst._periods[H], 10), h100: digit(inst._periods[H], 100), 565 | h1000: digit(inst._periods[H], 1000), 566 | ml: labelFor(M), mn: inst._periods[M], mnn: this._minDigits(inst._periods[M], 2), 567 | mnnn: this._minDigits(inst._periods[M], 3), m1: digit(inst._periods[M], 1), 568 | m10: digit(inst._periods[M], 10), m100: digit(inst._periods[M], 100), 569 | m1000: digit(inst._periods[M], 1000), 570 | sl: labelFor(S), sn: inst._periods[S], snn: this._minDigits(inst._periods[S], 2), 571 | snnn: this._minDigits(inst._periods[S], 3), s1: digit(inst._periods[S], 1), 572 | s10: digit(inst._periods[S], 10), s100: digit(inst._periods[S], 100), 573 | s1000: digit(inst._periods[S], 1000)}; 574 | var html = layout; 575 | // Replace period containers: {p<}...{p>} 576 | for (var i = Y; i <= S; i++) { 577 | var period = 'yowdhms'.charAt(i); 578 | var re = new RegExp('\\{' + period + '<\\}(.*)\\{' + period + '>\\}', 'g'); 579 | html = html.replace(re, ((!significant && show[i]) || 580 | (significant && showSignificant[i]) ? '$1' : '')); 581 | } 582 | // Replace period values: {pn} 583 | $.each(subs, function(n, v) { 584 | var re = new RegExp('\\{' + n + '\\}', 'g'); 585 | html = html.replace(re, v); 586 | }); 587 | return html; 588 | }, 589 | 590 | /* Ensure a numeric value has at least n digits for display. 591 | @param value (number) the value to display 592 | @param len (number) the minimum length 593 | @return (string) the display text */ 594 | _minDigits: function(value, len) { 595 | value = '' + value; 596 | if (value.length >= len) { 597 | return value; 598 | } 599 | value = '0000000000' + value; 600 | return value.substr(value.length - len); 601 | }, 602 | 603 | /* Translate the format into flags for each period. 604 | @param inst (object) the current settings for this instance 605 | @return (string[7]) flags indicating which periods are requested (?) or 606 | required (!) by year, month, week, day, hour, minute, second */ 607 | _determineShow: function(inst) { 608 | var format = this._get(inst, 'format'); 609 | var show = []; 610 | show[Y] = (format.match('y') ? '?' : (format.match('Y') ? '!' : null)); 611 | show[O] = (format.match('o') ? '?' : (format.match('O') ? '!' : null)); 612 | show[W] = (format.match('w') ? '?' : (format.match('W') ? '!' : null)); 613 | show[D] = (format.match('d') ? '?' : (format.match('D') ? '!' : null)); 614 | show[H] = (format.match('h') ? '?' : (format.match('H') ? '!' : null)); 615 | show[M] = (format.match('m') ? '?' : (format.match('M') ? '!' : null)); 616 | show[S] = (format.match('s') ? '?' : (format.match('S') ? '!' : null)); 617 | return show; 618 | }, 619 | 620 | /* Calculate the requested periods between now and the target time. 621 | @param inst (object) the current settings for this instance 622 | @param show (string[7]) flags indicating which periods are requested/required 623 | @param significant (number) the number of periods with values to show, zero for all 624 | @param now (Date) the current date and time 625 | @return (number[7]) the current time periods (always positive) 626 | by year, month, week, day, hour, minute, second */ 627 | _calculatePeriods: function(inst, show, significant, now) { 628 | // Find endpoints 629 | inst._now = now; 630 | inst._now.setMilliseconds(0); 631 | var until = new Date(inst._now.getTime()); 632 | if (inst._since) { 633 | if (now.getTime() < inst._since.getTime()) { 634 | inst._now = now = until; 635 | } 636 | else { 637 | now = inst._since; 638 | } 639 | } 640 | else { 641 | until.setTime(inst._until.getTime()); 642 | if (now.getTime() > inst._until.getTime()) { 643 | inst._now = now = until; 644 | } 645 | } 646 | // Calculate differences by period 647 | var periods = [0, 0, 0, 0, 0, 0, 0]; 648 | if (show[Y] || show[O]) { 649 | // Treat end of months as the same 650 | var lastNow = $.countdown._getDaysInMonth(now.getFullYear(), now.getMonth()); 651 | var lastUntil = $.countdown._getDaysInMonth(until.getFullYear(), until.getMonth()); 652 | var sameDay = (until.getDate() == now.getDate() || 653 | (until.getDate() >= Math.min(lastNow, lastUntil) && 654 | now.getDate() >= Math.min(lastNow, lastUntil))); 655 | var getSecs = function(date) { 656 | return (date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds(); 657 | }; 658 | var months = Math.max(0, 659 | (until.getFullYear() - now.getFullYear()) * 12 + until.getMonth() - now.getMonth() + 660 | ((until.getDate() < now.getDate() && !sameDay) || 661 | (sameDay && getSecs(until) < getSecs(now)) ? -1 : 0)); 662 | periods[Y] = (show[Y] ? Math.floor(months / 12) : 0); 663 | periods[O] = (show[O] ? months - periods[Y] * 12 : 0); 664 | // Adjust for months difference and end of month if necessary 665 | now = new Date(now.getTime()); 666 | var wasLastDay = (now.getDate() == lastNow); 667 | var lastDay = $.countdown._getDaysInMonth(now.getFullYear() + periods[Y], 668 | now.getMonth() + periods[O]); 669 | if (now.getDate() > lastDay) { 670 | now.setDate(lastDay); 671 | } 672 | now.setFullYear(now.getFullYear() + periods[Y]); 673 | now.setMonth(now.getMonth() + periods[O]); 674 | if (wasLastDay) { 675 | now.setDate(lastDay); 676 | } 677 | } 678 | var diff = Math.floor((until.getTime() - now.getTime()) / 1000); 679 | var extractPeriod = function(period, numSecs) { 680 | periods[period] = (show[period] ? Math.floor(diff / numSecs) : 0); 681 | diff -= periods[period] * numSecs; 682 | }; 683 | extractPeriod(W, 604800); 684 | extractPeriod(D, 86400); 685 | extractPeriod(H, 3600); 686 | extractPeriod(M, 60); 687 | extractPeriod(S, 1); 688 | if (diff > 0 && !inst._since) { // Round up if left overs 689 | var multiplier = [1, 12, 4.3482, 7, 24, 60, 60]; 690 | var lastShown = S; 691 | var max = 1; 692 | for (var period = S; period >= Y; period--) { 693 | if (show[period]) { 694 | if (periods[lastShown] >= max) { 695 | periods[lastShown] = 0; 696 | diff = 1; 697 | } 698 | if (diff > 0) { 699 | periods[period]++; 700 | diff = 0; 701 | lastShown = period; 702 | max = 1; 703 | } 704 | } 705 | max *= multiplier[period]; 706 | } 707 | } 708 | if (significant) { // Zero out insignificant periods 709 | for (var period = Y; period <= S; period++) { 710 | if (significant && periods[period]) { 711 | significant--; 712 | } 713 | else if (!significant) { 714 | periods[period] = 0; 715 | } 716 | } 717 | } 718 | return periods; 719 | } 720 | }); 721 | 722 | /* jQuery extend now ignores nulls! 723 | @param target (object) the object to update 724 | @param props (object) the new settings 725 | @return (object) the updated object */ 726 | function extendRemove(target, props) { 727 | $.extend(target, props); 728 | for (var name in props) { 729 | if (props[name] == null) { 730 | target[name] = null; 731 | } 732 | } 733 | return target; 734 | } 735 | 736 | /* Process the countdown functionality for a jQuery selection. 737 | @param command (string) the command to run (optional, default 'attach') 738 | @param options (object) the new settings to use for these countdown instances 739 | @return (jQuery) for chaining further calls */ 740 | $.fn.countdown = function(options) { 741 | var otherArgs = Array.prototype.slice.call(arguments, 1); 742 | if (options == 'getTimes' || options == 'settings') { 743 | return $.countdown['_' + options + 'Countdown']. 744 | apply($.countdown, [this[0]].concat(otherArgs)); 745 | } 746 | return this.each(function() { 747 | if (typeof options == 'string') { 748 | $.countdown['_' + options + 'Countdown'].apply($.countdown, [this].concat(otherArgs)); 749 | } 750 | else { 751 | $.countdown._attachCountdown(this, options); 752 | } 753 | }); 754 | }; 755 | 756 | /* Initialise the countdown functionality. */ 757 | $.countdown = new Countdown(); // singleton instance 758 | 759 | })(jQuery); 760 | -------------------------------------------------------------------------------- /static/jquery.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery JavaScript Library v1.4.2 3 | * http://jquery.com/ 4 | * 5 | * Copyright 2010, John Resig 6 | * Dual licensed under the MIT or GPL Version 2 licenses. 7 | * http://jquery.org/license 8 | * 9 | * Includes Sizzle.js 10 | * http://sizzlejs.com/ 11 | * Copyright 2010, The Dojo Foundation 12 | * Released under the MIT, BSD, and GPL Licenses. 13 | * 14 | * Date: Sat Feb 13 22:33:48 2010 -0500 15 | */ 16 | (function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, 21 | Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& 22 | (d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, 23 | a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== 24 | "find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(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(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, 25 | function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; 34 | var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, 35 | parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= 36 | false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= 37 | s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, 38 | applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; 39 | else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, 40 | a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== 41 | w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, 42 | cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= 47 | c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); 48 | a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, 49 | function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); 50 | k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), 51 | C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= 53 | e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& 54 | f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; 55 | if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", 63 | e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, 64 | "_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, 65 | d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, 71 | e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); 72 | t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| 73 | g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, 80 | CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, 81 | g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, 82 | text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, 83 | setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= 84 | h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== 86 | "="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, 87 | h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& 90 | q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; 91 | if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); 92 | (function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: 93 | function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= 96 | {},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== 97 | "string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", 98 | d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? 99 | a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== 100 | 1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= 102 | c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, 103 | wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, 104 | prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(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,false,function(b){this.parentNode.insertBefore(b, 105 | this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); 106 | return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, 107 | ""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); 111 | return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", 112 | ""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= 113 | c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? 114 | c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= 115 | function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= 116 | Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, 117 | "border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= 118 | a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= 119 | a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== 120 | "string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, 121 | serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), 122 | function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, 123 | global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& 124 | e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? 125 | "&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== 126 | false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= 127 | false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", 128 | c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| 129 | d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); 130 | g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== 131 | 1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== 132 | "json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; 133 | if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== 139 | "number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| 140 | c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; 141 | this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= 142 | this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, 143 | e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; 149 | a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); 150 | c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, 151 | d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- 152 | f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": 153 | "pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in 154 | e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); 155 | --------------------------------------------------------------------------------