Repository: sinacloud/sae-python-dev-guide Branch: master Commit: d60f361535ea Files: 158 Total size: 1.2 MB Directory structure: gitextract_f045oq39/ ├── .gitignore ├── README ├── dev_server/ │ ├── README │ ├── bundle_local.py │ ├── cloudsql.py │ ├── dev_server.py │ ├── sae/ │ │ ├── __init__.py │ │ ├── _restful_mysql/ │ │ │ ├── __init__.py │ │ │ ├── _mysql.py │ │ │ ├── _mysql_exceptions.py │ │ │ ├── connections.py │ │ │ ├── constants/ │ │ │ │ ├── CLIENT.py │ │ │ │ ├── CR.py │ │ │ │ ├── ER.py │ │ │ │ ├── FIELD_TYPE.py │ │ │ │ ├── FLAG.py │ │ │ │ ├── REFRESH.py │ │ │ │ └── __init__.py │ │ │ ├── converters.py │ │ │ ├── cursors.py │ │ │ ├── monkey.py │ │ │ ├── release.py │ │ │ └── times.py │ │ ├── channel.js │ │ ├── channel.py │ │ ├── channel.src.js │ │ ├── conf.py │ │ ├── const.py │ │ ├── core.py │ │ ├── ext/ │ │ │ ├── __init__.py │ │ │ ├── django/ │ │ │ │ ├── __init__.py │ │ │ │ ├── mail/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── backend.py │ │ │ │ └── storage/ │ │ │ │ ├── __init__.py │ │ │ │ └── backend.py │ │ │ ├── shell.py │ │ │ └── storage/ │ │ │ ├── __init__.py │ │ │ └── monkey.py │ │ ├── kvdb.py │ │ ├── mail.py │ │ ├── memcache.py │ │ ├── sae_signature.py │ │ ├── storage.py │ │ ├── taskqueue.py │ │ └── util.py │ ├── saecloud │ └── setup.py ├── docs/ │ ├── Makefile │ ├── conf.py │ ├── exts/ │ │ └── chinese_search.py │ ├── faq.rst │ ├── index.rst │ ├── quickstart.rst │ ├── runtime.rst │ ├── service.rst │ ├── static/ │ │ └── memcache.html │ ├── theme/ │ │ └── nature/ │ │ ├── layout.html │ │ ├── static/ │ │ │ ├── nature.css_t │ │ │ └── sae.js │ │ └── theme.conf │ └── tools.rst └── examples/ ├── apibus/ │ └── apibus_handler.py ├── bottle/ │ ├── README │ └── index.wsgi ├── django/ │ ├── 1.2.7/ │ │ ├── README │ │ ├── config.yaml │ │ ├── index.wsgi │ │ ├── mysite/ │ │ │ ├── __init__.py │ │ │ ├── demo/ │ │ │ │ ├── __init__.py │ │ │ │ ├── models.py │ │ │ │ ├── tests.py │ │ │ │ └── views.py │ │ │ ├── manage.py │ │ │ ├── settings.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ └── static/ │ │ ├── css/ │ │ │ ├── base.css │ │ │ ├── changelists.css │ │ │ ├── dashboard.css │ │ │ ├── forms.css │ │ │ ├── ie.css │ │ │ ├── login.css │ │ │ ├── rtl.css │ │ │ └── widgets.css │ │ └── js/ │ │ ├── SelectBox.js │ │ ├── SelectFilter2.js │ │ ├── actions.js │ │ ├── admin/ │ │ │ ├── DateTimeShortcuts.js │ │ │ ├── RelatedObjectLookups.js │ │ │ └── ordering.js │ │ ├── calendar.js │ │ ├── collapse.js │ │ ├── compress.py │ │ ├── core.js │ │ ├── dateparse.js │ │ ├── getElementsBySelector.js │ │ ├── inlines.js │ │ ├── jquery.init.js │ │ ├── jquery.js │ │ ├── prepopulate.js │ │ ├── timeparse.js │ │ └── urlify.js │ └── 1.4/ │ ├── README │ ├── config.yaml │ ├── db.sql │ ├── index.wsgi │ ├── manage.py │ ├── mysite/ │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── templates/ │ │ │ ├── 404.html │ │ │ └── 500.html │ │ ├── urls.py │ │ └── wsgi.py │ └── polls/ │ ├── __init__.py │ ├── admin.py │ ├── models.py │ ├── templates/ │ │ ├── detail.html │ │ ├── index.html │ │ └── results.html │ ├── tests.py │ ├── urls.py │ └── views.py ├── flask/ │ ├── README │ ├── app.py │ ├── index.wsgi │ └── myapp.py ├── helloworld/ │ └── 1/ │ └── index.wsgi ├── matplotshell/ │ ├── README │ ├── config.yaml │ └── index.wsgi ├── renren/ │ ├── config.yaml │ ├── db.sql │ ├── error.html │ ├── index.wsgi │ ├── oauth.html │ └── renrenoauth.py ├── segment/ │ ├── config.yaml │ └── index.wsgi ├── static-site/ │ ├── README │ ├── config.yaml │ └── www/ │ └── index.html ├── tornado/ │ ├── async/ │ │ ├── config.yaml │ │ └── index.wsgi │ └── wsgi/ │ ├── README │ └── index.wsgi ├── trac/ │ ├── README.md │ ├── config.yaml │ ├── index.wsgi │ ├── project/ │ │ ├── README │ │ ├── VERSION │ │ ├── conf/ │ │ │ ├── trac.ini │ │ │ └── trac.ini.sample │ │ └── templates/ │ │ └── site.html.sample │ └── setup.sql ├── webpy/ │ ├── index.wsgi │ └── templates/ │ └── hello.html └── weibo/ ├── appstack.py └── index.wsgi ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ build/* docs/_build/* dev_server/build/* dev_server/sae_python_dev.egg-info/* *~ *.DS_Store *.default *.types *.pyc *.egg *.pdf *.bak *.doc *.ppt *.xls *.mht *.mp3 *.mp4 *.wma *.rar *.zip *.7z *.xz *.map *.log *.txt *.swp *.gz *.ko *.so .tmp* .svn .cvs ================================================ FILE: README ================================================ Copyright © 2011 新浪网研发中心. All rights reserved. SAE Python Team ================================================ FILE: dev_server/README ================================================ SAE Python development server - experimental All Rights Reserved 2011 SAE Python Team 目前支持的服务包括:mysql, taskqueue, memcache, storage, mail。 大部分的服务直接运行dev_server.py进行调试就可以了,部分服务需要做一些配置。 注意: 本工具仅为应用开发便利之用,对sae python环境的模拟并不完整。 Install -------------- sudo python setup.py install 基本使用 ------------ 使用svn检出app代码之后,建立以数字为标识的发布目录,切换到发布目录: $ pwd /home/jaime/source/blackfire/1 编辑index.wsgi和config.yaml: $ vi index.wsgi import sae def app(environ, start_response): status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return ['Hello, world! reloading test3'] application = sae.create_wsgi_app(app) $ vi config.yaml --- name: blackfire version: 1 ... 运行dev_server.py: $ dev_server.py MySQL config not found: app.py Start development server on http://localhost:8080/ 访问 http://localhost:8080 端口就可以看到Hello, world!了。 使用MySQL服务 ---------------- 配置好MySQL本地开发server,使用 `--mysql` 参数运行dev_server.py。 $ dev_server.py --mysql=user:password@host:port 现在你可以在应用代码中像在SAE线上环境一样使用MySQL服务了。dev_server.py默认使用 名为 `app_应用名` 的数据库。 使用storage服务 --------------- 使用 `--storage-path` 参数运行dev_server.py。 $ dev_server.py --storage-path=/path/to/local/storage/data 本地的storage服务使用以下的目录结构来模拟线上的storage。 storage-path/ domain1/ key1 key2 domain2/ domain3/ --storage-path配置的路径下每个子文件夹会映射为storage中的一个domain,而每个子文 件夹下的文件映射为domain下的一个key,其内容为对应key的数据。 .. note: 为方便调试,dev_server自带的sae.storage在某个domain不存在的情况下会自动创建 该domain。线上环境中的domain需要在sae后台面板中手动创建。 使用pylibmc -------------- dev_server自带了一个dummy pylibmc,所以无须安装pylibmc就可以直接使用memcache服务 了。该模块将所有的数据存贮在内存中,dev_server.py进程结束时,所有的数据都会丢失 。 使用kvdb ---------------- kvdb默认数据存在内存中,dev_server.py进程结束时,数据会全部丢失,如果需要保存数据, 请使用如下命令行启动dev_server.py $ dev_server.py --kvdb-file=/path/to/kvdb/local/file ================================================ FILE: dev_server/bundle_local.py ================================================ #!/usr/bin/env python """Create a local bundle for your virtualenv environment Export all the packages listed in requirements.txt to ./virtualenv.bundle directory Then you can create a .zip file before uploading them to sae Usage: bundle_local -r requirements.txt """ from optparse import OptionParser import os import sys import pip.util import shutil TMP = 'virtualenv.bundle' ZIP_FILE = TMP + '.zip' def main(): parser = OptionParser() parser.add_option("-r", dest="requirements", help="The requirements.txt file outputed by pip freeze") (options, args) = parser.parse_args() if not options.requirements: print 'requirements.txt not found' sys.exit(-1) if os.path.exists(TMP): shutil.rmtree(TMP) os.mkdir(TMP) shutil.copy2(options.requirements, os.path.join(TMP, 'requirements.txt')) # Get all installed packages on system installed_dists = {} for dist in pip.util.get_installed_distributions(): installed_dists[dist.project_name] = dist # Get the dists in requirements.txt dists = [] for line in open(options.requirements, 'r').readlines(): if line.strip() or line.startswith('#'): pass pkg = line.split('==')[0] if pkg not in installed_dists: raise Exception('%s not installed' % pkg) dists.append(installed_dists[pkg]) top_levels = [] for dist in dists: mods = [(dist.location, mod) for mod in dist.get_metadata('top_level.txt').splitlines()] top_levels += mods top_levels = list(set(top_levels)) copy_modules(top_levels, TMP) def copy_modules(mod_paths, dest): for loc, mod in mod_paths: if os.path.isdir(loc): src = os.path.join(loc, mod) if os.path.isdir(src): shutil.copytree(src, os.path.join(dest, mod), ignore=shutil.ignore_patterns('*.pyc')) else: # Single file module shutil.copy2(src + '.py', dest) else: # Egg file ? import zipfile zf = zipfile.ZipFile(loc) members = filter(lambda f: f.startswith(mod), zf.namelist()) for m in members: zf.extract(m, dest) zf.close() if __name__ == '__main__': main() ================================================ FILE: dev_server/cloudsql.py ================================================ #!/usr/bin/env python # Copyright (C) 2012-2013 SINA, All rights reserved. """Command line client for SAE MySQL Service. """ import sys import os import logging import optparse import sae._restful_mysql import sae._restful_mysql._mysql_exceptions sys.modules['_mysql_exceptions'] = sae._restful_mysql._mysql_exceptions from grizzled import db from grizzled.db import mysql import prettytable import sqlcmd from sqlcmd import config logging.basicConfig(level=logging.WARNING) sqlcmd.log = logging.getLogger('cloudsql') sqlcmd.DEFAULT_CONFIG_DIR = os.path.expanduser('~/.saecloud') sqlcmd.RC_FILE = os.path.join(sqlcmd.DEFAULT_CONFIG_DIR, 'cloudsql.config') sqlcmd.HISTORY_FILE_FORMAT = os.path.join(sqlcmd.DEFAULT_CONFIG_DIR, '%s.hist') sqlcmd.INTRO = 'SAE MySQL Client\n\nType "help" or "?" for help.\n' DEFAULT_ENCODING = 'utf-8' USAGE = '%prog [options] database_name' DEFAULT_SAE_MYSQL_HOST = 'w.rdc.sae.sina.com.cn' DEFAULT_SAE_MYSQL_PORT = 3307 DEFAULT_SAE_MYSQL_DB_PREFIX = 'app_' class CloudSqlDriver(mysql.MySQLDriver): """Grizzled DB Driver for Cloud SAE MySQL Service.""" NAME = 'cloudsql' def get_import(self): return sae._restful_mysql def get_display_name(self): return 'Cloud SQL' def do_connect(self, host, port, user, password, database): # Fix grizzled's mysql driver which omit the port argument when connecting. dbi = self.get_import() port = port and int(port) or 3306 return dbi.connect(host=host, user=user, passwd=password, db=database, port=port) class CloudSqlCmd(sqlcmd.SQLCmd): """The SQLCmd command interpreter for Cloud SQL.""" sqlcmd.SQLCmd.MAIN_PROMPT = 'mysql> ' sqlcmd.SQLCmd.CONTINUATION_PROMPT = ' -> ' sqlcmd.SQLCmd.NO_SEMI_NEEDED.update( ['about', 'desc', 'describe', 'echo', 'exit', 'h', 'hist', 'history', 'load', 'run', 'r', 'redo', 'set', 'show', 'var', 'vars']) for method in ['do_dot_connect', 'do_dot_desc', 'do_begin']: delattr(sqlcmd.SQLCmd, method) for cmd in ['show', 'describe', 'echo', 'load', 'run', 'exit', 'h', 'hist', 'history', 'var', 'vars', 'about']: method = 'do_dot_' + cmd setattr(sqlcmd.SQLCmd, method.replace('dot_', ''), getattr( sqlcmd.SQLCmd, method)) delattr(sqlcmd.SQLCmd, method) method = 'complete_dot_' + cmd if hasattr(sqlcmd.SQLCmd, method): setattr(sqlcmd.SQLCmd, method.replace('dot_', ''), getattr( sqlcmd.SQLCmd, method)) delattr(sqlcmd.SQLCmd, method) def do_redo(self, args): # XXX: Fix global name 'do_r' is not defined problem in sqlcmd self.do_r(args) def _SQLCmd__set_setting(self, varname, value): # XXX: Fix bool object has no lower attribute in sqlcmd return sqlcmd.SQLCmd._SQLCmd__set_setting(self, varname, str(value)) def do_desc(self, args): self.do_describe(args, cmd='.desc') complete_desc = sqlcmd.SQLCmd.complete_dot_desc def do_load(self, args): self.do_run(args) def preloop(self, *args, **kwargs): sqlcmd.SQLCmd.preloop(self, *args, **kwargs) # Just exit if the connect failed if self._SQLCmd__db is None: sys.exit(1) def __init__(self, *args, **kwargs): sqlcmd.SQLCmd.__init__(self, *args, **kwargs) self.prompt = sqlcmd.SQLCmd.MAIN_PROMPT self.output_encoding = DEFAULT_ENCODING def set_output_encoding(self, encoding): self.output_encoding = encoding def _build_table(self, cursor): """Builds an output PrettyTable from the results in the given cursor.""" if not cursor.description: return None column_names = [column[0] for column in cursor.description] table = prettytable.PrettyTable(column_names) rows = cursor.fetchall() if not rows: return table for i, col in enumerate(rows[0]): table.align[column_names[i]] = isinstance(col, basestring) and 'l' or 'r' for row in rows: table.add_row(row) return table def _SQLCmd__handle_select(self, args, cursor, command='select'): """Overrides SQLCmd.__handle_select to display output with prettytable.""" self._SQLCmd__exec_SQL(cursor, command, args) table = self._build_table(cursor) if table: output = table.get_string() if isinstance(output, unicode): print output.encode(self.output_encoding) else: print output def _create_config_dir(): """Creates the sqlcmd config directory if necessary.""" directory = sqlcmd.DEFAULT_CONFIG_DIR if not os.access(directory, os.R_OK | os.W_OK | os.X_OK): old_umask = os.umask(077) os.makedirs(sqlcmd.DEFAULT_CONFIG_DIR) os.umask(old_umask) def main(argv): parser = optparse.OptionParser(usage=USAGE) parser.add_option('-u', '--username', dest='username', help='MySQL username to use when connecting to the server.') parser.add_option('-p', '--password', dest='password', help='MySQL password to use when connecting to the server.') parser.add_option('-e', '--output_encoding', dest='output_encoding', default=DEFAULT_ENCODING, help='Output encoding. Defaults to %s.' % DEFAULT_ENCODING) (options, args) = parser.parse_args(argv[1:]) if len(args) != 1: parser.print_help(sys.stderr) return 1 if not options.username or not options.password: print >>sys.stderr, 'Error: username or password is missing.\n' return 1 if args[0].startswith(DEFAULT_SAE_MYSQL_DB_PREFIX): database_name = args[0] else: database_name = DEFAULT_SAE_MYSQL_DB_PREFIX + args[0] instance_alias = database_name _create_config_dir() db.add_driver(CloudSqlDriver.NAME, CloudSqlDriver) sql_cmd_config = config.SQLCmdConfig(None) sql_cmd_config.add('__cloudsql__', instance_alias, DEFAULT_SAE_MYSQL_HOST , DEFAULT_SAE_MYSQL_PORT, database_name, CloudSqlDriver.NAME, options.username, options.password) sql_cmd = CloudSqlCmd(sql_cmd_config) sql_cmd.set_output_encoding(options.output_encoding) sql_cmd.set_database(instance_alias) sql_cmd.cmdloop() return 0 if __name__ == '__main__': sys.exit(main(sys.argv)) ================================================ FILE: dev_server/dev_server.py ================================================ #!/usr/bin/env python """Simple development server Make sure you're use python 2.7 for developing """ import sys import os import os.path import re import imp import yaml from optparse import OptionParser from sae.util import search_file_bottom_up from sae.channel import _channel_wrapper def setup_sae_environ(conf): # Add dummy pylibmc module import sae.memcache sys.modules['pylibmc'] = sae.memcache # Save kvdb data in this file else the data will lost # when the dev_server.py is down if conf.kvdb: print 'KVDB: ', conf.kvdb os.environ['sae.kvdb.file'] = conf.kvdb # Add app_root to sys.path cwd = os.getcwd() if cwd not in sys.path: sys.path.insert(0, cwd) try: appname = str(conf.name) appversion = str(conf.version) except AttributeError: raise AttributeError('`name` or `version` not found in `config.yaml`') if conf.mysql: import sae.const p = re.compile('^(.+):(.+)@(.+):(\d+)$') m = p.match(conf.mysql) if not m: raise Exception("Invalid mysql configuration") user, password, host, port = m.groups() dbname = 'app_' + appname sae.const.MYSQL_DB = dbname sae.const.MYSQL_USER = user sae.const.MYSQL_PASS = password sae.const.MYSQL_PORT = port sae.const.MYSQL_HOST = host sae.const.MYSQL_HOST_S = host print 'MySQL: %s.%s' % (conf.mysql, dbname) else: print 'MySQL config not found' if conf.storage: os.environ['sae.storage.path'] = os.path.abspath(conf.storage) # Add custom environment variable os.environ['HTTP_HOST'] = '%s:%d' % (conf.host, conf.port) os.environ['APP_NAME'] = appname os.environ['APP_VERSION'] = appversion class Worker: def __init__(self, conf, app): self.conf = conf self.application = app self.collect_statifiles() def collect_statifiles(self): self.static_files = {} if hasattr(self.conf, 'handlers'): for h in self.conf.handlers: url = h['url'] if h.has_key('static_dir'): self.static_files[url] = os.path.join(app_root, h['static_dir']) elif h.has_key('static_path'): self.static_files[url] = os.path.join(app_root, h['static_path']) if not len(self.static_files): self.static_files.update({ '/static': os.path.join(app_root, 'static'), '/media': os.path.join(app_root, 'media'), '/favicon.ico': os.path.join(app_root, 'favicon.ico'), }) import sae self.static_files['/_sae/channel/api.js'] = os.path.join(os.path.dirname(sae.__file__), 'channel.js') if self.conf.storage: # stor dispatch: for test usage only self.static_files['/stor-stub/'] = os.path.abspath(self.conf.storage) def run(self): raise NotImplementedError() class WsgiWorker(Worker): def run(self): # FIXME: All files under current directory files = ['index.wsgi'] # XXX: # when django template renders `environ` in its 500 page, it will # try to call `environ['werkzeug.server.shutdown'` and cause the # server exit unexpectedly. # See: https://docs.djangoproject.com/en/dev/ref/templates/api/#variables-and-lookups def wrap(app): def _(environ, start_response): try: del environ['werkzeug.server.shutdown'] except KeyError: pass return app(environ, start_response) return _ if 'WERKZEUG_RUN_MAIN' in os.environ: os.environ['sae.run_main'] = '1' self.application = _channel_wrapper(self.application) from werkzeug.serving import run_simple run_simple(self.conf.host, self.conf.port, wrap(self.application), use_reloader = True, use_debugger = True, extra_files = files, static_files = self.static_files) class TornadoWorker(Worker): def run(self): import tornado.autoreload tornado.autoreload.watch('index.wsgi') import re from tornado.web import URLSpec, StaticFileHandler # The user should not use `tornado.web.Application.add_handlers` # since here in SAE one application only has a single host, so here # we can just use the first host_handers. handlers = self.application.handlers[0][1] for prefix, path in self.static_files.iteritems(): pattern = re.escape(prefix) + r"(.*)" handlers.insert(0, URLSpec(pattern, StaticFileHandler, {"path": path})) os.environ['sae.run_main'] = '1' import tornado.ioloop from tornado.httpserver import HTTPServer server = HTTPServer(self.application, xheaders=True) server.listen(self.conf.port, self.conf.host) tornado.ioloop.IOLoop.instance().start() def main(options): conf_path = os.path.join(app_root, 'config.yaml') conf = yaml.load(open(conf_path, "r")) options.__dict__.update(conf) conf = options # if env `WERKZEUG_RUN_MAIN` is not defined, then we are in # the reloader process. # if os.environ.get('WERKZEUG_RUN_MAIN', False): setup_sae_environ(conf) try: index = imp.load_source('index', 'index.wsgi') except IOError: print >>sys.stderr, "Seems you don't have an index.wsgi" return if not hasattr(index, 'application'): print >>sys.stderr, "application not found in index.wsgi" return if not callable(index.application): print >>sys.stderr, "application is not a callable" return application = index.application cls_name = getattr(conf, 'worker', 'wsgi').capitalize() + 'Worker' try: globals().get(cls_name, WsgiWorker)(conf, application).run() except KeyboardInterrupt: pass if __name__ == '__main__': parser = OptionParser() parser.add_option("-p", "--port", type="int", dest="port", default="8080", help="Which port to listen") parser.add_option("--host", dest="host", default="localhost", help="Which host to listen") parser.add_option("--mysql", dest="mysql", help="Mysql configuration: user:password@host:port") parser.add_option("--storage-path", dest="storage", help="Directory used as local stoarge") parser.add_option("--kvdb-file", dest="kvdb", help="File to save kvdb data") (options, args) = parser.parse_args() app_root = search_file_bottom_up('config.yaml') if app_root is None: print >> sys.stderr, \ 'Error: Not an app directory(or any of the parent directories)' sys.exit(1) if app_root != os.getcwd(): os.chdir(app_root) main(options) ================================================ FILE: dev_server/sae/__init__.py ================================================ """SAE Python Jaime Chen 2011 """ import core def create_wsgi_app(app): return app def dev_server(conf): core.environ = conf import sys, os.path _PYTHON_VERSION = 'python%d.%d' % (sys.version_info[0], sys.version_info[1]) def add_vendor_dir(path, index=1): """Insert site dir or virtualenv at a given index in sys.path. Args: path: relative path to a site dir or virtualenv. index: sys.path position to insert the site dir. Raises: ValueError: path doesn't exist. """ venv_path = os.path.join(path, 'lib', _PYTHON_VERSION, 'site-packages') if os.path.isdir(venv_path): site_dir = venv_path elif os.path.isdir(path): site_dir = path else: raise ValueError('virtualenv: cannot access %s: ' 'No such virtualenv or site directory' % path) sys_path = sys.path[:] del sys.path[index:] import site site.addsitedir(site_dir) sys.path.extend(sys_path[index:]) ================================================ FILE: dev_server/sae/_restful_mysql/__init__.py ================================================ """MySQLdb - A DB API v2.0 compatible interface to MySQL. This package is a wrapper around _mysql, which mostly implements the MySQL C API. connect() -- connects to server See the C API specification and the MySQL documentation for more info on other items. For information on how MySQLdb handles type conversion, see the MySQLdb.converters module. """ __revision__ = """$Revision: 603 $"""[11:-2] from release import __version__, version_info, __author__ import _mysql if version_info != _mysql.version_info: raise ImportError("this is MySQLdb version %s, but _mysql is version %r" % (version_info, _mysql.version_info)) threadsafety = 1 apilevel = "2.0" paramstyle = "format" from _mysql import * from constants import FIELD_TYPE from times import Date, Time, Timestamp, \ DateFromTicks, TimeFromTicks, TimestampFromTicks try: frozenset except NameError: from sets import ImmutableSet as frozenset class DBAPISet(frozenset): """A special type of set for which A == x is true if A is a DBAPISet and x is a member of that set.""" def __eq__(self, other): if isinstance(other, DBAPISet): return not self.difference(other) return other in self STRING = DBAPISet([FIELD_TYPE.ENUM, FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING]) BINARY = DBAPISet([FIELD_TYPE.BLOB, FIELD_TYPE.LONG_BLOB, FIELD_TYPE.MEDIUM_BLOB, FIELD_TYPE.TINY_BLOB]) NUMBER = DBAPISet([FIELD_TYPE.DECIMAL, FIELD_TYPE.DOUBLE, FIELD_TYPE.FLOAT, FIELD_TYPE.INT24, FIELD_TYPE.LONG, FIELD_TYPE.LONGLONG, FIELD_TYPE.TINY, FIELD_TYPE.YEAR]) DATE = DBAPISet([FIELD_TYPE.DATE, FIELD_TYPE.NEWDATE]) TIME = DBAPISet([FIELD_TYPE.TIME]) TIMESTAMP = DBAPISet([FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME]) DATETIME = TIMESTAMP ROWID = DBAPISet() def test_DBAPISet_set_equality(): assert STRING == STRING def test_DBAPISet_set_inequality(): assert STRING != NUMBER def test_DBAPISet_set_equality_membership(): assert FIELD_TYPE.VAR_STRING == STRING def test_DBAPISet_set_inequality_membership(): assert FIELD_TYPE.DATE != STRING def Binary(x): return str(x) def Connect(*args, **kwargs): """Factory function for connections.Connection.""" from connections import Connection return Connection(*args, **kwargs) connect = Connection = Connect __all__ = [ 'BINARY', 'Binary', 'Connect', 'Connection', 'DATE', 'Date', 'Time', 'Timestamp', 'DateFromTicks', 'TimeFromTicks', 'TimestampFromTicks', 'DataError', 'DatabaseError', 'Error', 'FIELD_TYPE', 'IntegrityError', 'InterfaceError', 'InternalError', 'MySQLError', 'NULL', 'NUMBER', 'NotSupportedError', 'DBAPISet', 'OperationalError', 'ProgrammingError', 'ROWID', 'STRING', 'TIME', 'TIMESTAMP', 'Warning', 'apilevel', 'connect', 'connections', 'constants', 'converters', 'cursors', 'debug', 'escape', 'escape_dict', 'escape_sequence', 'escape_string', 'get_client_info', 'paramstyle', 'string_literal', 'threadsafety', 'version_info'] ================================================ FILE: dev_server/sae/_restful_mysql/_mysql.py ================================================ # Copyright (C) 2012-2013 SINA, All rights reserved. from _mysql_exceptions import * """An proxy for the MySQL C API Translate the _mysql C API call into restfull call """ import types import pickle import urllib2 from release import __version__, version_info import logging logger = logging.getLogger('sae._mysql') NULL = 'NULL' _SAE_MYSQL_API_BACKEND = 'http://2.python.sinaapp.com/api/mysql/' # refs: # http://www.python.org/dev/peps/pep-0249 # http://mysql-python.sourceforge.net/MySQLdb.html#mysql class connection(object): def __init__(self, *args, **kwargs): self.converter = kwargs.pop('conv', {}) self._conn_args = args self._conn_kwargs = kwargs self._conn_id = None self._rows = None self._description = None self._description_flags = None self._rowcount = None self._warnings = None self._info = None self._lastrowid = None self._open_connection() def open(self): pass def close(self): self._conn_id = None def shutdown(self): pass def select_db(self, *args): self._request('select_db', args) def change_user(self): pass def character_set_name(self): if not hasattr(self, '_charset'): self._charset = self._request('character_set_name') return self._charset def set_character_set(self, charset): if getattr(self, '_charset', None) != charset: self._request('set_character_set', charset) self._charset = charset def set_server_option(self, *args, **kws): logging.warning('Ignored set_server_option: %s, %s', args, kws) def query(self, query): retval = self._request('query', query=query) self._rows = retval['rows'] self._description = retval['description'] self._description_flags = retval['description_flags'] self._rowcount = retval['rowcount'] self._warnings = retval['warnings'] self._info = retval['info'] self._lastrowid = retval['lastrowid'] def commit(self): pass def rollback(self): pass def autocommit(self, value): pass def use_result(self): return self.store_result() def store_result(self): if self._rows: return StoreResult(self, self._rows, self.converter, self._description, self._description_flags) else: return None def next_result(self, *args, **kws): # TODO return -1 def affected_rows(self): return self._rowcount def insert_id(self): return self._lastrowid def info(self): return self._info def get_host_info(self): return self._host_info def get_proto_info(self): return self._proto_info def get_server_info(self): return self._server_info def ping(self): pass def escape(self, item, dct=None): return escape(item, dct or self.converter) def escape_string(self, str): return escape_string(str) def string_literal(self, obj): return '\'%s\'' % escape_string(str(obj)) def _open_connection(self): retval = self._request('open', *self._conn_args, **self._conn_kwargs) self._conn_id = retval['connection_id'] self._host_info = retval['host_info'] self._proto_info = retval['proto_info'] self._server_info = retval['server_info'] self.server_capabilities = retval['server_capabilities'] def _request(self, op, *args, **kwargs): req = { 'connection_id': self._conn_id, 'op': op, 'args': args, 'kwargs': kwargs } logger.debug('REQ: %s', req) payload = pickle.dumps(req) body = urllib2.urlopen(_SAE_MYSQL_API_BACKEND, payload).read() rep = pickle.loads(body) logger.debug('REP: %s', rep) if rep.get('sql_exception'): raise rep.get('sql_exception') return rep.get('result') def _mysql_rows_to_python(rows, conv, field_info, how): def row_to_python0(row): nrow = [] for i, v in enumerate(row): # XXX: NULL is always converted to None, so here we # do not need to do it again. nrow.append(None if v is None else conv[i](v)) return tuple(nrow) def row_to_python1(row): nrow = {} for i, v in enumerate(row): # XXX: NULL is always converted to None, so here we # do not need to do it again. nrow[field_info[i][0]] = None if v is None else conv[i](v) return nrow if how: return tuple(row_to_python1(r) for r in rows) else: return tuple(row_to_python0(r) for r in rows) class StoreResult: def __init__(self, conn, rows, conv, description, description_flags): self.conn = conn self.current = 0 self.description = description self.description_flags = description_flags self._cached = rows self._init_conv(conv) def _init_conv(self, conv): # _mysql.c:_mysql_ResultObject_Initialize self.converter = [] for n, i in enumerate(self.description): c = conv.get(i[1], str) # search by field.type if isinstance(c, list): nc = None mask = self.description_flags[n] for j in c: if isinstance(j[0], int): if mask & j[0]: # search by field.flags nc = j[1] break else: nc = j[1] break # wildcard c = nc if nc is not None else str self.converter.append(c) def fetch_row(self, maxrows=1, how=0): if maxrows == 0: retval = self._cached self._cached = () else: retval = self._cached[self.current:maxrows] self.current += maxrows return _mysql_rows_to_python(retval, self.converter, self.description, how) def describe(self): return self.description def field_flags(self): return self.description_flags connect = connection def get_client_info(): return '5.1.67' def escape(item, dct): return _escape_item(item, dct) def _escape_item(val, dct): d = dct.get(type(val)) or dct.get(types.StringType) return d(val, dct) # Copied from pymysql # See: https://github.com/petehunt/PyMySQL/blob/master/pymysql/converters.py import re ESCAPE_REGEX = re.compile(r"[\0\n\r\032\'\"\\]", re.IGNORECASE) def escape_string(value): def rep(m): n = m.group(0) if n == "\0": return "\\0" elif n == "\n": return "\\n" elif n == "\r": return "\\r" elif n == "\032": return "\\Z" else: return "\\"+n s = re.sub(ESCAPE_REGEX, rep, value) return s def string_literal(obj): return '\'%s\'' % escape_string(str(obj)) def escape_dict(val, dct): n = {} for k, v in val.items(): quoted = _escape_item(v) n[k] = quoted return n def escape_sequence(val, dct): return tuple(_escape_item(v, dct) for v in val) ================================================ FILE: dev_server/sae/_restful_mysql/_mysql_exceptions.py ================================================ """_mysql_exceptions: Exception classes for _mysql and MySQLdb. These classes are dictated by the DB API v2.0: http://www.python.org/topics/database/DatabaseAPI-2.0.html """ from exceptions import Exception, StandardError, Warning class MySQLError(StandardError): """Exception related to operation with MySQL.""" class Warning(Warning, MySQLError): """Exception raised for important warnings like data truncations while inserting, etc.""" class Error(MySQLError): """Exception that is the base class of all other error exceptions (not Warning).""" class InterfaceError(Error): """Exception raised for errors that are related to the database interface rather than the database itself.""" class DatabaseError(Error): """Exception raised for errors that are related to the database.""" class DataError(DatabaseError): """Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range, etc.""" class OperationalError(DatabaseError): """Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer, e.g. an unexpected disconnect occurs, the data source name is not found, a transaction could not be processed, a memory allocation error occurred during processing, etc.""" class IntegrityError(DatabaseError): """Exception raised when the relational integrity of the database is affected, e.g. a foreign key check fails, duplicate key, etc.""" class InternalError(DatabaseError): """Exception raised when the database encounters an internal error, e.g. the cursor is not valid anymore, the transaction is out of sync, etc.""" class ProgrammingError(DatabaseError): """Exception raised for programming errors, e.g. table not found or already exists, syntax error in the SQL statement, wrong number of parameters specified, etc.""" class NotSupportedError(DatabaseError): """Exception raised in case a method or database API was used which is not supported by the database, e.g. requesting a .rollback() on a connection that does not support transaction or has transactions turned off.""" del Exception, StandardError ================================================ FILE: dev_server/sae/_restful_mysql/connections.py ================================================ """ This module implements connections for MySQLdb. Presently there is only one class: Connection. Others are unlikely. However, you might want to make your own subclasses. In most cases, you will probably override Connection.default_cursor with a non-standard Cursor class. """ import cursors from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \ DatabaseError, OperationalError, IntegrityError, InternalError, \ NotSupportedError, ProgrammingError import types, _mysql import re def defaulterrorhandler(connection, cursor, errorclass, errorvalue): """ If cursor is not None, (errorclass, errorvalue) is appended to cursor.messages; otherwise it is appended to connection.messages. Then errorclass is raised with errorvalue as the value. You can override this with your own error handler by assigning it to the instance. """ error = errorclass, errorvalue if cursor: cursor.messages.append(error) else: connection.messages.append(error) del cursor del connection raise errorclass, errorvalue re_numeric_part = re.compile(r"^(\d+)") def numeric_part(s): """Returns the leading numeric part of a string. >>> numeric_part("20-alpha") 20 >>> numeric_part("foo") >>> numeric_part("16b") 16 """ m = re_numeric_part.match(s) if m: return int(m.group(1)) return None class Connection(_mysql.connection): """MySQL Database Connection Object""" default_cursor = cursors.Cursor def __init__(self, *args, **kwargs): """ Create a connection to the database. It is strongly recommended that you only use keyword parameters. Consult the MySQL C API documentation for more information. host string, host to connect user string, user to connect as passwd string, password to use db string, database to use port integer, TCP/IP port to connect to unix_socket string, location of unix_socket to use conv conversion dictionary, see MySQLdb.converters connect_timeout number of seconds to wait before the connection attempt fails. compress if set, compression is enabled named_pipe if set, a named pipe is used to connect (Windows only) init_command command which is run once the connection is created read_default_file file from which default client values are read read_default_group configuration group to use from the default file cursorclass class object, used to create cursors (keyword only) use_unicode If True, text-like columns are returned as unicode objects using the connection's character set. Otherwise, text-like columns are returned as strings. columns are returned as normal strings. Unicode objects will always be encoded to the connection's character set regardless of this setting. charset If supplied, the connection character set will be changed to this character set (MySQL-4.1 and newer). This implies use_unicode=True. sql_mode If supplied, the session SQL mode will be changed to this setting (MySQL-4.1 and newer). For more details and legal values, see the MySQL documentation. client_flag integer, flags to use or 0 (see MySQL docs or constants/CLIENTS.py) ssl dictionary or mapping, contains SSL connection parameters; see the MySQL documentation for more details (mysql_ssl_set()). If this is set, and the client does not support SSL, NotSupportedError will be raised. local_infile integer, non-zero enables LOAD LOCAL INFILE; zero disables There are a number of undocumented, non-standard methods. See the documentation for the MySQL C API for some hints on what they do. """ from constants import CLIENT, FIELD_TYPE from converters import conversions from weakref import proxy, WeakValueDictionary import types kwargs2 = kwargs.copy() if kwargs.has_key('conv'): conv = kwargs['conv'] else: conv = conversions conv2 = {} for k, v in conv.items(): if isinstance(k, int) and isinstance(v, list): conv2[k] = v[:] else: conv2[k] = v kwargs2['conv'] = conv2 self.cursorclass = kwargs2.pop('cursorclass', self.default_cursor) charset = kwargs2.pop('charset', '') if charset: use_unicode = True else: use_unicode = False use_unicode = kwargs2.pop('use_unicode', use_unicode) sql_mode = kwargs2.pop('sql_mode', '') client_flag = kwargs.get('client_flag', 0) client_version = tuple([ numeric_part(n) for n in _mysql.get_client_info().split('.')[:2] ]) if client_version >= (4, 1): client_flag |= CLIENT.MULTI_STATEMENTS if client_version >= (5, 0): client_flag |= CLIENT.MULTI_RESULTS kwargs2['client_flag'] = client_flag super(Connection, self).__init__(*args, **kwargs2) self.encoders = dict([ (k, v) for k, v in conv.items() if type(k) is not int ]) self._server_version = tuple([ numeric_part(n) for n in self.get_server_info().split('.')[:2] ]) db = proxy(self) def _get_string_literal(): def string_literal(obj, dummy=None): return db.string_literal(obj) return string_literal def _get_unicode_literal(): def unicode_literal(u, dummy=None): return db.literal(u.encode(unicode_literal.charset)) return unicode_literal def _get_string_decoder(): def string_decoder(s): return s.decode(string_decoder.charset) return string_decoder string_literal = _get_string_literal() self.unicode_literal = unicode_literal = _get_unicode_literal() self.string_decoder = string_decoder = _get_string_decoder() if not charset: charset = self.character_set_name() self.set_character_set(charset) if sql_mode: self.set_sql_mode(sql_mode) if use_unicode: self.converter[FIELD_TYPE.STRING].append((None, string_decoder)) self.converter[FIELD_TYPE.VAR_STRING].append((None, string_decoder)) self.converter[FIELD_TYPE.VARCHAR].append((None, string_decoder)) self.converter[FIELD_TYPE.BLOB].append((None, string_decoder)) self.encoders[types.StringType] = string_literal self.encoders[types.UnicodeType] = unicode_literal self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS if self._transactional: # PEP-249 requires autocommit to be initially off self.autocommit(False) self.messages = [] def cursor(self, cursorclass=None): """ Create a cursor on which queries may be performed. The optional cursorclass parameter is used to create the Cursor. By default, self.cursorclass=cursors.Cursor is used. """ return (cursorclass or self.cursorclass)(self) def __enter__(self): return self.cursor() def __exit__(self, exc, value, tb): if exc: self.rollback() else: self.commit() def literal(self, o): """ If o is a single object, returns an SQL literal as a string. If o is a non-string sequence, the items of the sequence are converted and returned as a sequence. Non-standard. For internal use; do not use this in your applications. """ return self.escape(o, self.encoders) def begin(self): """Explicitly begin a connection. Non-standard. DEPRECATED: Will be removed in 1.3. Use an SQL BEGIN statement instead.""" from warnings import warn warn("begin() is non-standard and will be removed in 1.3", DeprecationWarning, 2) self.query("BEGIN") if not hasattr(_mysql.connection, 'warning_count'): def warning_count(self): """Return the number of warnings generated from the last query. This is derived from the info() method.""" from string import atoi info = self.info() if info: return atoi(info.split()[-1]) else: return 0 def set_character_set(self, charset): """Set the connection character set to charset. The character set can only be changed in MySQL-4.1 and newer. If you try to change the character set from the current value in an older version, NotSupportedError will be raised.""" if self.character_set_name() != charset: try: super(Connection, self).set_character_set(charset) except AttributeError: if self._server_version < (4, 1): raise NotSupportedError("server is too old to set charset") self.query('SET NAMES %s' % charset) self.store_result() self.string_decoder.charset = charset self.unicode_literal.charset = charset def set_sql_mode(self, sql_mode): """Set the connection sql_mode. See MySQL documentation for legal values.""" if self._server_version < (4, 1): raise NotSupportedError("server is too old to set sql_mode") self.query("SET SESSION sql_mode='%s'" % sql_mode) self.store_result() def show_warnings(self): """Return detailed information about warnings as a sequence of tuples of (Level, Code, Message). This is only supported in MySQL-4.1 and up. If your server is an earlier version, an empty sequence is returned.""" if self._server_version < (4,1): return () self.query("SHOW WARNINGS") r = self.store_result() warnings = r.fetch_row(0) return warnings Warning = Warning Error = Error InterfaceError = InterfaceError DatabaseError = DatabaseError DataError = DataError OperationalError = OperationalError IntegrityError = IntegrityError InternalError = InternalError ProgrammingError = ProgrammingError NotSupportedError = NotSupportedError errorhandler = defaulterrorhandler ================================================ FILE: dev_server/sae/_restful_mysql/constants/CLIENT.py ================================================ """MySQL CLIENT constants These constants are used when creating the connection. Use bitwise-OR (|) to combine options together, and pass them as the client_flags parameter to MySQLdb.Connection. For more information on these flags, see the MySQL C API documentation for mysql_real_connect(). """ LONG_PASSWORD = 1 FOUND_ROWS = 2 LONG_FLAG = 4 CONNECT_WITH_DB = 8 NO_SCHEMA = 16 COMPRESS = 32 ODBC = 64 LOCAL_FILES = 128 IGNORE_SPACE = 256 CHANGE_USER = 512 INTERACTIVE = 1024 SSL = 2048 IGNORE_SIGPIPE = 4096 TRANSACTIONS = 8192 # mysql_com.h was WRONG prior to 3.23.35 RESERVED = 16384 SECURE_CONNECTION = 32768 MULTI_STATEMENTS = 65536 MULTI_RESULTS = 131072 ================================================ FILE: dev_server/sae/_restful_mysql/constants/CR.py ================================================ """MySQL Connection Errors Nearly all of these raise OperationalError. COMMANDS_OUT_OF_SYNC raises ProgrammingError. """ MIN_ERROR = 2000 MAX_ERROR = 2999 UNKNOWN_ERROR = 2000 SOCKET_CREATE_ERROR = 2001 CONNECTION_ERROR = 2002 CONN_HOST_ERROR = 2003 IPSOCK_ERROR = 2004 UNKNOWN_HOST = 2005 SERVER_GONE_ERROR = 2006 VERSION_ERROR = 2007 OUT_OF_MEMORY = 2008 WRONG_HOST_INFO = 2009 LOCALHOST_CONNECTION = 2010 TCP_CONNECTION = 2011 SERVER_HANDSHAKE_ERR = 2012 SERVER_LOST = 2013 COMMANDS_OUT_OF_SYNC = 2014 NAMEDPIPE_CONNECTION = 2015 NAMEDPIPEWAIT_ERROR = 2016 NAMEDPIPEOPEN_ERROR = 2017 NAMEDPIPESETSTATE_ERROR = 2018 CANT_READ_CHARSET = 2019 NET_PACKET_TOO_LARGE = 2020 ================================================ FILE: dev_server/sae/_restful_mysql/constants/ER.py ================================================ """MySQL ER Constants These constants are error codes for the bulk of the error conditions that may occur. """ HASHCHK = 1000 NISAMCHK = 1001 NO = 1002 YES = 1003 CANT_CREATE_FILE = 1004 CANT_CREATE_TABLE = 1005 CANT_CREATE_DB = 1006 DB_CREATE_EXISTS = 1007 DB_DROP_EXISTS = 1008 DB_DROP_DELETE = 1009 DB_DROP_RMDIR = 1010 CANT_DELETE_FILE = 1011 CANT_FIND_SYSTEM_REC = 1012 CANT_GET_STAT = 1013 CANT_GET_WD = 1014 CANT_LOCK = 1015 CANT_OPEN_FILE = 1016 FILE_NOT_FOUND = 1017 CANT_READ_DIR = 1018 CANT_SET_WD = 1019 CHECKREAD = 1020 DISK_FULL = 1021 DUP_KEY = 1022 ERROR_ON_CLOSE = 1023 ERROR_ON_READ = 1024 ERROR_ON_RENAME = 1025 ERROR_ON_WRITE = 1026 FILE_USED = 1027 FILSORT_ABORT = 1028 FORM_NOT_FOUND = 1029 GET_ERRNO = 1030 ILLEGAL_HA = 1031 KEY_NOT_FOUND = 1032 NOT_FORM_FILE = 1033 NOT_KEYFILE = 1034 OLD_KEYFILE = 1035 OPEN_AS_READONLY = 1036 OUTOFMEMORY = 1037 OUT_OF_SORTMEMORY = 1038 UNEXPECTED_EOF = 1039 CON_COUNT_ERROR = 1040 OUT_OF_RESOURCES = 1041 BAD_HOST_ERROR = 1042 HANDSHAKE_ERROR = 1043 DBACCESS_DENIED_ERROR = 1044 ACCESS_DENIED_ERROR = 1045 NO_DB_ERROR = 1046 UNKNOWN_COM_ERROR = 1047 BAD_NULL_ERROR = 1048 BAD_DB_ERROR = 1049 TABLE_EXISTS_ERROR = 1050 BAD_TABLE_ERROR = 1051 NON_UNIQ_ERROR = 1052 SERVER_SHUTDOWN = 1053 BAD_FIELD_ERROR = 1054 WRONG_FIELD_WITH_GROUP = 1055 WRONG_GROUP_FIELD = 1056 WRONG_SUM_SELECT = 1057 WRONG_VALUE_COUNT = 1058 TOO_LONG_IDENT = 1059 DUP_FIELDNAME = 1060 DUP_KEYNAME = 1061 DUP_ENTRY = 1062 WRONG_FIELD_SPEC = 1063 PARSE_ERROR = 1064 EMPTY_QUERY = 1065 NONUNIQ_TABLE = 1066 INVALID_DEFAULT = 1067 MULTIPLE_PRI_KEY = 1068 TOO_MANY_KEYS = 1069 TOO_MANY_KEY_PARTS = 1070 TOO_LONG_KEY = 1071 KEY_COLUMN_DOES_NOT_EXITS = 1072 BLOB_USED_AS_KEY = 1073 TOO_BIG_FIELDLENGTH = 1074 WRONG_AUTO_KEY = 1075 READY = 1076 NORMAL_SHUTDOWN = 1077 GOT_SIGNAL = 1078 SHUTDOWN_COMPLETE = 1079 FORCING_CLOSE = 1080 IPSOCK_ERROR = 1081 NO_SUCH_INDEX = 1082 WRONG_FIELD_TERMINATORS = 1083 BLOBS_AND_NO_TERMINATED = 1084 TEXTFILE_NOT_READABLE = 1085 FILE_EXISTS_ERROR = 1086 LOAD_INFO = 1087 ALTER_INFO = 1088 WRONG_SUB_KEY = 1089 CANT_REMOVE_ALL_FIELDS = 1090 CANT_DROP_FIELD_OR_KEY = 1091 INSERT_INFO = 1092 INSERT_TABLE_USED = 1093 NO_SUCH_THREAD = 1094 KILL_DENIED_ERROR = 1095 NO_TABLES_USED = 1096 TOO_BIG_SET = 1097 NO_UNIQUE_LOGFILE = 1098 TABLE_NOT_LOCKED_FOR_WRITE = 1099 TABLE_NOT_LOCKED = 1100 BLOB_CANT_HAVE_DEFAULT = 1101 WRONG_DB_NAME = 1102 WRONG_TABLE_NAME = 1103 TOO_BIG_SELECT = 1104 UNKNOWN_ERROR = 1105 UNKNOWN_PROCEDURE = 1106 WRONG_PARAMCOUNT_TO_PROCEDURE = 1107 WRONG_PARAMETERS_TO_PROCEDURE = 1108 UNKNOWN_TABLE = 1109 FIELD_SPECIFIED_TWICE = 1110 INVALID_GROUP_FUNC_USE = 1111 UNSUPPORTED_EXTENSION = 1112 TABLE_MUST_HAVE_COLUMNS = 1113 RECORD_FILE_FULL = 1114 UNKNOWN_CHARACTER_SET = 1115 TOO_MANY_TABLES = 1116 TOO_MANY_FIELDS = 1117 TOO_BIG_ROWSIZE = 1118 STACK_OVERRUN = 1119 WRONG_OUTER_JOIN = 1120 NULL_COLUMN_IN_INDEX = 1121 CANT_FIND_UDF = 1122 CANT_INITIALIZE_UDF = 1123 UDF_NO_PATHS = 1124 UDF_EXISTS = 1125 CANT_OPEN_LIBRARY = 1126 CANT_FIND_DL_ENTRY = 1127 FUNCTION_NOT_DEFINED = 1128 HOST_IS_BLOCKED = 1129 HOST_NOT_PRIVILEGED = 1130 PASSWORD_ANONYMOUS_USER = 1131 PASSWORD_NOT_ALLOWED = 1132 PASSWORD_NO_MATCH = 1133 UPDATE_INFO = 1134 CANT_CREATE_THREAD = 1135 WRONG_VALUE_COUNT_ON_ROW = 1136 CANT_REOPEN_TABLE = 1137 INVALID_USE_OF_NULL = 1138 REGEXP_ERROR = 1139 MIX_OF_GROUP_FUNC_AND_FIELDS = 1140 NONEXISTING_GRANT = 1141 TABLEACCESS_DENIED_ERROR = 1142 COLUMNACCESS_DENIED_ERROR = 1143 ILLEGAL_GRANT_FOR_TABLE = 1144 GRANT_WRONG_HOST_OR_USER = 1145 NO_SUCH_TABLE = 1146 NONEXISTING_TABLE_GRANT = 1147 NOT_ALLOWED_COMMAND = 1148 SYNTAX_ERROR = 1149 DELAYED_CANT_CHANGE_LOCK = 1150 TOO_MANY_DELAYED_THREADS = 1151 ABORTING_CONNECTION = 1152 NET_PACKET_TOO_LARGE = 1153 NET_READ_ERROR_FROM_PIPE = 1154 NET_FCNTL_ERROR = 1155 NET_PACKETS_OUT_OF_ORDER = 1156 NET_UNCOMPRESS_ERROR = 1157 NET_READ_ERROR = 1158 NET_READ_INTERRUPTED = 1159 NET_ERROR_ON_WRITE = 1160 NET_WRITE_INTERRUPTED = 1161 TOO_LONG_STRING = 1162 TABLE_CANT_HANDLE_BLOB = 1163 TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164 DELAYED_INSERT_TABLE_LOCKED = 1165 WRONG_COLUMN_NAME = 1166 WRONG_KEY_COLUMN = 1167 WRONG_MRG_TABLE = 1168 DUP_UNIQUE = 1169 BLOB_KEY_WITHOUT_LENGTH = 1170 PRIMARY_CANT_HAVE_NULL = 1171 TOO_MANY_ROWS = 1172 REQUIRES_PRIMARY_KEY = 1173 NO_RAID_COMPILED = 1174 UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175 KEY_DOES_NOT_EXITS = 1176 CHECK_NO_SUCH_TABLE = 1177 CHECK_NOT_IMPLEMENTED = 1178 CANT_DO_THIS_DURING_AN_TRANSACTION = 1179 ERROR_DURING_COMMIT = 1180 ERROR_DURING_ROLLBACK = 1181 ERROR_DURING_FLUSH_LOGS = 1182 ERROR_DURING_CHECKPOINT = 1183 NEW_ABORTING_CONNECTION = 1184 DUMP_NOT_IMPLEMENTED = 1185 FLUSH_MASTER_BINLOG_CLOSED = 1186 INDEX_REBUILD = 1187 MASTER = 1188 MASTER_NET_READ = 1189 MASTER_NET_WRITE = 1190 FT_MATCHING_KEY_NOT_FOUND = 1191 LOCK_OR_ACTIVE_TRANSACTION = 1192 UNKNOWN_SYSTEM_VARIABLE = 1193 CRASHED_ON_USAGE = 1194 CRASHED_ON_REPAIR = 1195 WARNING_NOT_COMPLETE_ROLLBACK = 1196 TRANS_CACHE_FULL = 1197 SLAVE_MUST_STOP = 1198 SLAVE_NOT_RUNNING = 1199 BAD_SLAVE = 1200 MASTER_INFO = 1201 SLAVE_THREAD = 1202 TOO_MANY_USER_CONNECTIONS = 1203 SET_CONSTANTS_ONLY = 1204 LOCK_WAIT_TIMEOUT = 1205 LOCK_TABLE_FULL = 1206 READ_ONLY_TRANSACTION = 1207 DROP_DB_WITH_READ_LOCK = 1208 CREATE_DB_WITH_READ_LOCK = 1209 WRONG_ARGUMENTS = 1210 NO_PERMISSION_TO_CREATE_USER = 1211 UNION_TABLES_IN_DIFFERENT_DIR = 1212 LOCK_DEADLOCK = 1213 TABLE_CANT_HANDLE_FT = 1214 CANNOT_ADD_FOREIGN = 1215 NO_REFERENCED_ROW = 1216 ROW_IS_REFERENCED = 1217 CONNECT_TO_MASTER = 1218 QUERY_ON_MASTER = 1219 ERROR_WHEN_EXECUTING_COMMAND = 1220 WRONG_USAGE = 1221 WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222 CANT_UPDATE_WITH_READLOCK = 1223 MIXING_NOT_ALLOWED = 1224 DUP_ARGUMENT = 1225 USER_LIMIT_REACHED = 1226 SPECIFIC_ACCESS_DENIED_ERROR = 1227 LOCAL_VARIABLE = 1228 GLOBAL_VARIABLE = 1229 NO_DEFAULT = 1230 WRONG_VALUE_FOR_VAR = 1231 WRONG_TYPE_FOR_VAR = 1232 VAR_CANT_BE_READ = 1233 CANT_USE_OPTION_HERE = 1234 NOT_SUPPORTED_YET = 1235 MASTER_FATAL_ERROR_READING_BINLOG = 1236 SLAVE_IGNORED_TABLE = 1237 INCORRECT_GLOBAL_LOCAL_VAR = 1238 WRONG_FK_DEF = 1239 KEY_REF_DO_NOT_MATCH_TABLE_REF = 1240 OPERAND_COLUMNS = 1241 SUBQUERY_NO_1_ROW = 1242 UNKNOWN_STMT_HANDLER = 1243 CORRUPT_HELP_DB = 1244 CYCLIC_REFERENCE = 1245 AUTO_CONVERT = 1246 ILLEGAL_REFERENCE = 1247 DERIVED_MUST_HAVE_ALIAS = 1248 SELECT_REDUCED = 1249 TABLENAME_NOT_ALLOWED_HERE = 1250 NOT_SUPPORTED_AUTH_MODE = 1251 SPATIAL_CANT_HAVE_NULL = 1252 COLLATION_CHARSET_MISMATCH = 1253 SLAVE_WAS_RUNNING = 1254 SLAVE_WAS_NOT_RUNNING = 1255 TOO_BIG_FOR_UNCOMPRESS = 1256 ZLIB_Z_MEM_ERROR = 1257 ZLIB_Z_BUF_ERROR = 1258 ZLIB_Z_DATA_ERROR = 1259 CUT_VALUE_GROUP_CONCAT = 1260 WARN_TOO_FEW_RECORDS = 1261 WARN_TOO_MANY_RECORDS = 1262 WARN_NULL_TO_NOTNULL = 1263 WARN_DATA_OUT_OF_RANGE = 1264 WARN_DATA_TRUNCATED = 1265 WARN_USING_OTHER_HANDLER = 1266 CANT_AGGREGATE_2COLLATIONS = 1267 DROP_USER = 1268 REVOKE_GRANTS = 1269 CANT_AGGREGATE_3COLLATIONS = 1270 CANT_AGGREGATE_NCOLLATIONS = 1271 VARIABLE_IS_NOT_STRUCT = 1272 UNKNOWN_COLLATION = 1273 SLAVE_IGNORED_SSL_PARAMS = 1274 SERVER_IS_IN_SECURE_AUTH_MODE = 1275 WARN_FIELD_RESOLVED = 1276 BAD_SLAVE_UNTIL_COND = 1277 MISSING_SKIP_SLAVE = 1278 UNTIL_COND_IGNORED = 1279 WRONG_NAME_FOR_INDEX = 1280 WRONG_NAME_FOR_CATALOG = 1281 WARN_QC_RESIZE = 1282 BAD_FT_COLUMN = 1283 UNKNOWN_KEY_CACHE = 1284 WARN_HOSTNAME_WONT_WORK = 1285 UNKNOWN_STORAGE_ENGINE = 1286 WARN_DEPRECATED_SYNTAX = 1287 NON_UPDATABLE_TABLE = 1288 FEATURE_DISABLED = 1289 OPTION_PREVENTS_STATEMENT = 1290 DUPLICATED_VALUE_IN_TYPE = 1291 TRUNCATED_WRONG_VALUE = 1292 TOO_MUCH_AUTO_TIMESTAMP_COLS = 1293 INVALID_ON_UPDATE = 1294 UNSUPPORTED_PS = 1295 GET_ERRMSG = 1296 GET_TEMPORARY_ERRMSG = 1297 UNKNOWN_TIME_ZONE = 1298 WARN_INVALID_TIMESTAMP = 1299 INVALID_CHARACTER_STRING = 1300 WARN_ALLOWED_PACKET_OVERFLOWED = 1301 CONFLICTING_DECLARATIONS = 1302 SP_NO_RECURSIVE_CREATE = 1303 SP_ALREADY_EXISTS = 1304 SP_DOES_NOT_EXIST = 1305 SP_DROP_FAILED = 1306 SP_STORE_FAILED = 1307 SP_LILABEL_MISMATCH = 1308 SP_LABEL_REDEFINE = 1309 SP_LABEL_MISMATCH = 1310 SP_UNINIT_VAR = 1311 SP_BADSELECT = 1312 SP_BADRETURN = 1313 SP_BADSTATEMENT = 1314 UPDATE_LOG_DEPRECATED_IGNORED = 1315 UPDATE_LOG_DEPRECATED_TRANSLATED = 1316 QUERY_INTERRUPTED = 1317 SP_WRONG_NO_OF_ARGS = 1318 SP_COND_MISMATCH = 1319 SP_NORETURN = 1320 SP_NORETURNEND = 1321 SP_BAD_CURSOR_QUERY = 1322 SP_BAD_CURSOR_SELECT = 1323 SP_CURSOR_MISMATCH = 1324 SP_CURSOR_ALREADY_OPEN = 1325 SP_CURSOR_NOT_OPEN = 1326 SP_UNDECLARED_VAR = 1327 SP_WRONG_NO_OF_FETCH_ARGS = 1328 SP_FETCH_NO_DATA = 1329 SP_DUP_PARAM = 1330 SP_DUP_VAR = 1331 SP_DUP_COND = 1332 SP_DUP_CURS = 1333 SP_CANT_ALTER = 1334 SP_SUBSELECT_NYI = 1335 STMT_NOT_ALLOWED_IN_SF_OR_TRG = 1336 SP_VARCOND_AFTER_CURSHNDLR = 1337 SP_CURSOR_AFTER_HANDLER = 1338 SP_CASE_NOT_FOUND = 1339 FPARSER_TOO_BIG_FILE = 1340 FPARSER_BAD_HEADER = 1341 FPARSER_EOF_IN_COMMENT = 1342 FPARSER_ERROR_IN_PARAMETER = 1343 FPARSER_EOF_IN_UNKNOWN_PARAMETER = 1344 VIEW_NO_EXPLAIN = 1345 FRM_UNKNOWN_TYPE = 1346 WRONG_OBJECT = 1347 NONUPDATEABLE_COLUMN = 1348 VIEW_SELECT_DERIVED = 1349 VIEW_SELECT_CLAUSE = 1350 VIEW_SELECT_VARIABLE = 1351 VIEW_SELECT_TMPTABLE = 1352 VIEW_WRONG_LIST = 1353 WARN_VIEW_MERGE = 1354 WARN_VIEW_WITHOUT_KEY = 1355 VIEW_INVALID = 1356 SP_NO_DROP_SP = 1357 SP_GOTO_IN_HNDLR = 1358 TRG_ALREADY_EXISTS = 1359 TRG_DOES_NOT_EXIST = 1360 TRG_ON_VIEW_OR_TEMP_TABLE = 1361 TRG_CANT_CHANGE_ROW = 1362 TRG_NO_SUCH_ROW_IN_TRG = 1363 NO_DEFAULT_FOR_FIELD = 1364 DIVISION_BY_ZERO = 1365 TRUNCATED_WRONG_VALUE_FOR_FIELD = 1366 ILLEGAL_VALUE_FOR_TYPE = 1367 VIEW_NONUPD_CHECK = 1368 VIEW_CHECK_FAILED = 1369 PROCACCESS_DENIED_ERROR = 1370 RELAY_LOG_FAIL = 1371 PASSWD_LENGTH = 1372 UNKNOWN_TARGET_BINLOG = 1373 IO_ERR_LOG_INDEX_READ = 1374 BINLOG_PURGE_PROHIBITED = 1375 FSEEK_FAIL = 1376 BINLOG_PURGE_FATAL_ERR = 1377 LOG_IN_USE = 1378 LOG_PURGE_UNKNOWN_ERR = 1379 RELAY_LOG_INIT = 1380 NO_BINARY_LOGGING = 1381 RESERVED_SYNTAX = 1382 WSAS_FAILED = 1383 DIFF_GROUPS_PROC = 1384 NO_GROUP_FOR_PROC = 1385 ORDER_WITH_PROC = 1386 LOGGING_PROHIBIT_CHANGING_OF = 1387 NO_FILE_MAPPING = 1388 WRONG_MAGIC = 1389 PS_MANY_PARAM = 1390 KEY_PART_0 = 1391 VIEW_CHECKSUM = 1392 VIEW_MULTIUPDATE = 1393 VIEW_NO_INSERT_FIELD_LIST = 1394 VIEW_DELETE_MERGE_VIEW = 1395 CANNOT_USER = 1396 XAER_NOTA = 1397 XAER_INVAL = 1398 XAER_RMFAIL = 1399 XAER_OUTSIDE = 1400 XAER_RMERR = 1401 XA_RBROLLBACK = 1402 NONEXISTING_PROC_GRANT = 1403 PROC_AUTO_GRANT_FAIL = 1404 PROC_AUTO_REVOKE_FAIL = 1405 DATA_TOO_LONG = 1406 SP_BAD_SQLSTATE = 1407 STARTUP = 1408 LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR = 1409 CANT_CREATE_USER_WITH_GRANT = 1410 WRONG_VALUE_FOR_TYPE = 1411 TABLE_DEF_CHANGED = 1412 SP_DUP_HANDLER = 1413 SP_NOT_VAR_ARG = 1414 SP_NO_RETSET = 1415 CANT_CREATE_GEOMETRY_OBJECT = 1416 FAILED_ROUTINE_BREAK_BINLOG = 1417 BINLOG_UNSAFE_ROUTINE = 1418 BINLOG_CREATE_ROUTINE_NEED_SUPER = 1419 EXEC_STMT_WITH_OPEN_CURSOR = 1420 STMT_HAS_NO_OPEN_CURSOR = 1421 COMMIT_NOT_ALLOWED_IN_SF_OR_TRG = 1422 NO_DEFAULT_FOR_VIEW_FIELD = 1423 SP_NO_RECURSION = 1424 TOO_BIG_SCALE = 1425 TOO_BIG_PRECISION = 1426 M_BIGGER_THAN_D = 1427 WRONG_LOCK_OF_SYSTEM_TABLE = 1428 CONNECT_TO_FOREIGN_DATA_SOURCE = 1429 QUERY_ON_FOREIGN_DATA_SOURCE = 1430 FOREIGN_DATA_SOURCE_DOESNT_EXIST = 1431 FOREIGN_DATA_STRING_INVALID_CANT_CREATE = 1432 FOREIGN_DATA_STRING_INVALID = 1433 CANT_CREATE_FEDERATED_TABLE = 1434 TRG_IN_WRONG_SCHEMA = 1435 STACK_OVERRUN_NEED_MORE = 1436 TOO_LONG_BODY = 1437 WARN_CANT_DROP_DEFAULT_KEYCACHE = 1438 TOO_BIG_DISPLAYWIDTH = 1439 XAER_DUPID = 1440 DATETIME_FUNCTION_OVERFLOW = 1441 CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG = 1442 VIEW_PREVENT_UPDATE = 1443 PS_NO_RECURSION = 1444 SP_CANT_SET_AUTOCOMMIT = 1445 MALFORMED_DEFINER = 1446 VIEW_FRM_NO_USER = 1447 VIEW_OTHER_USER = 1448 NO_SUCH_USER = 1449 FORBID_SCHEMA_CHANGE = 1450 ROW_IS_REFERENCED_2 = 1451 NO_REFERENCED_ROW_2 = 1452 SP_BAD_VAR_SHADOW = 1453 TRG_NO_DEFINER = 1454 OLD_FILE_FORMAT = 1455 SP_RECURSION_LIMIT = 1456 SP_PROC_TABLE_CORRUPT = 1457 ERROR_LAST = 1457 ================================================ FILE: dev_server/sae/_restful_mysql/constants/FIELD_TYPE.py ================================================ """MySQL FIELD_TYPE Constants These constants represent the various column (field) types that are supported by MySQL. """ DECIMAL = 0 TINY = 1 SHORT = 2 LONG = 3 FLOAT = 4 DOUBLE = 5 NULL = 6 TIMESTAMP = 7 LONGLONG = 8 INT24 = 9 DATE = 10 TIME = 11 DATETIME = 12 YEAR = 13 NEWDATE = 14 VARCHAR = 15 BIT = 16 NEWDECIMAL = 246 ENUM = 247 SET = 248 TINY_BLOB = 249 MEDIUM_BLOB = 250 LONG_BLOB = 251 BLOB = 252 VAR_STRING = 253 STRING = 254 GEOMETRY = 255 CHAR = TINY INTERVAL = ENUM ================================================ FILE: dev_server/sae/_restful_mysql/constants/FLAG.py ================================================ """MySQL FLAG Constants These flags are used along with the FIELD_TYPE to indicate various properties of columns in a result set. """ NOT_NULL = 1 PRI_KEY = 2 UNIQUE_KEY = 4 MULTIPLE_KEY = 8 BLOB = 16 UNSIGNED = 32 ZEROFILL = 64 BINARY = 128 ENUM = 256 AUTO_INCREMENT = 512 TIMESTAMP = 1024 SET = 2048 NUM = 32768 PART_KEY = 16384 GROUP = 32768 UNIQUE = 65536 ================================================ FILE: dev_server/sae/_restful_mysql/constants/REFRESH.py ================================================ """MySQL REFRESH Constants These constants seem to mostly deal with things internal to the MySQL server. Forget you saw this. """ GRANT = 1 LOG = 2 TABLES = 4 HOSTS = 8 STATUS = 16 THREADS = 32 SLAVE = 64 MASTER = 128 READ_LOCK = 16384 FAST = 32768 ================================================ FILE: dev_server/sae/_restful_mysql/constants/__init__.py ================================================ __all__ = ['CR', 'FIELD_TYPE','CLIENT','REFRESH','ER','FLAG'] ================================================ FILE: dev_server/sae/_restful_mysql/converters.py ================================================ """MySQLdb type conversion module This module handles all the type conversions for MySQL. If the default type conversions aren't what you need, you can make your own. The dictionary conversions maps some kind of type to a conversion function which returns the corresponding value: Key: FIELD_TYPE.* (from MySQLdb.constants) Conversion function: Arguments: string Returns: Python object Key: Python type object (from types) or class Conversion function: Arguments: Python object of indicated type or class AND conversion dictionary Returns: SQL literal value Notes: Most conversion functions can ignore the dictionary, but it is a required parameter. It is necessary for converting things like sequences and instances. Don't modify conversions if you can avoid it. Instead, make copies (with the copy() method), modify the copies, and then pass them to MySQL.connect(). """ from _mysql import string_literal, escape_sequence, escape_dict, escape, NULL from constants import FIELD_TYPE, FLAG from times import * import types import array try: set except NameError: from sets import Set as set def Bool2Str(s, d): return str(int(s)) def Str2Set(s): return set([ i for i in s.split(',') if i ]) def Set2Str(s, d): return string_literal(','.join(s), d) def Thing2Str(s, d): """Convert something into a string via str().""" return str(s) def Unicode2Str(s, d): """Convert a unicode object to a string using the default encoding. This is only used as a placeholder for the real function, which is connection-dependent.""" return s.encode() Long2Int = Thing2Str def Float2Str(o, d): return '%.15g' % o def None2NULL(o, d): """Convert None to NULL.""" return NULL # duh def Thing2Literal(o, d): """Convert something into a SQL string literal. If using MySQL-3.23 or newer, string_literal() is a method of the _mysql.MYSQL object, and this function will be overridden with that method when the connection is created.""" return string_literal(o, d) def Instance2Str(o, d): """ Convert an Instance to a string representation. If the __str__() method produces acceptable output, then you don't need to add the class to conversions; it will be handled by the default converter. If the exact class is not found in d, it will use the first class it can find for which o is an instance. """ if d.has_key(o.__class__): return d[o.__class__](o, d) cl = filter(lambda x,o=o: type(x) is types.ClassType and isinstance(o, x), d.keys()) if not cl and hasattr(types, 'ObjectType'): cl = filter(lambda x,o=o: type(x) is types.TypeType and isinstance(o, x) and d[x] is not Instance2Str, d.keys()) if not cl: return d[types.StringType](o,d) d[o.__class__] = d[cl[0]] return d[cl[0]](o, d) def char_array(s): return array.array('c', s) def array2Str(o, d): return Thing2Literal(o.tostring(), d) conversions = { types.IntType: Thing2Str, types.LongType: Long2Int, types.FloatType: Float2Str, types.NoneType: None2NULL, types.TupleType: escape_sequence, types.ListType: escape_sequence, types.DictType: escape_dict, types.InstanceType: Instance2Str, array.ArrayType: array2Str, types.StringType: Thing2Literal, # default types.UnicodeType: Unicode2Str, types.ObjectType: Instance2Str, types.BooleanType: Bool2Str, DateTimeType: DateTime2literal, DateTimeDeltaType: DateTimeDelta2literal, set: Set2Str, FIELD_TYPE.TINY: int, FIELD_TYPE.SHORT: int, FIELD_TYPE.LONG: long, FIELD_TYPE.FLOAT: float, FIELD_TYPE.DOUBLE: float, FIELD_TYPE.DECIMAL: float, FIELD_TYPE.NEWDECIMAL: float, FIELD_TYPE.LONGLONG: long, FIELD_TYPE.INT24: int, FIELD_TYPE.YEAR: int, FIELD_TYPE.SET: Str2Set, FIELD_TYPE.TIMESTAMP: mysql_timestamp_converter, FIELD_TYPE.DATETIME: DateTime_or_None, FIELD_TYPE.TIME: TimeDelta_or_None, FIELD_TYPE.DATE: Date_or_None, FIELD_TYPE.BLOB: [ (FLAG.BINARY, str), ], FIELD_TYPE.STRING: [ (FLAG.BINARY, str), ], FIELD_TYPE.VAR_STRING: [ (FLAG.BINARY, str), ], FIELD_TYPE.VARCHAR: [ (FLAG.BINARY, str), ], } try: from decimal import Decimal conversions[FIELD_TYPE.DECIMAL] = Decimal conversions[FIELD_TYPE.NEWDECIMAL] = Decimal except ImportError: pass ================================================ FILE: dev_server/sae/_restful_mysql/cursors.py ================================================ """MySQLdb Cursors This module implements Cursors of various types for MySQLdb. By default, MySQLdb uses the Cursor class. """ import re import sys from types import ListType, TupleType, UnicodeType restr = (r"\svalues\s*" r"(\(((?= len(self._rows): return None result = self._rows[self.rownumber] self.rownumber = self.rownumber+1 return result def fetchmany(self, size=None): """Fetch up to size rows from the cursor. Result set may be smaller than size. If size is not defined, cursor.arraysize is used.""" self._check_executed() end = self.rownumber + (size or self.arraysize) result = self._rows[self.rownumber:end] self.rownumber = min(end, len(self._rows)) return result def fetchall(self): """Fetchs all available rows from the cursor.""" self._check_executed() if self.rownumber: result = self._rows[self.rownumber:] else: result = self._rows self.rownumber = len(self._rows) return result def scroll(self, value, mode='relative'): """Scroll the cursor in the result set to a new position according to mode. If mode is 'relative' (default), value is taken as offset to the current position in the result set, if set to 'absolute', value states an absolute target position.""" self._check_executed() if mode == 'relative': r = self.rownumber + value elif mode == 'absolute': r = value else: self.errorhandler(self, ProgrammingError, "unknown scroll mode %s" % `mode`) if r < 0 or r >= len(self._rows): self.errorhandler(self, IndexError, "out of range") self.rownumber = r def __iter__(self): self._check_executed() result = self.rownumber and self._rows[self.rownumber:] or self._rows return iter(result) class CursorUseResultMixIn(object): """This is a MixIn class which causes the result set to be stored in the server and sent row-by-row to client side, i.e. it uses mysql_use_result(). You MUST retrieve the entire result set and close() the cursor before additional queries can be peformed on the connection.""" _defer_warnings = True def _get_result(self): return self._get_db().use_result() def fetchone(self): """Fetches a single row from the cursor.""" self._check_executed() r = self._fetch_row(1) if not r: self._warning_check() return None self.rownumber = self.rownumber + 1 return r[0] def fetchmany(self, size=None): """Fetch up to size rows from the cursor. Result set may be smaller than size. If size is not defined, cursor.arraysize is used.""" self._check_executed() r = self._fetch_row(size or self.arraysize) self.rownumber = self.rownumber + len(r) if not r: self._warning_check() return r def fetchall(self): """Fetchs all available rows from the cursor.""" self._check_executed() r = self._fetch_row(0) self.rownumber = self.rownumber + len(r) self._warning_check() return r def __iter__(self): return self def next(self): row = self.fetchone() if row is None: raise StopIteration return row class CursorTupleRowsMixIn(object): """This is a MixIn class that causes all rows to be returned as tuples, which is the standard form required by DB API.""" _fetch_type = 0 class CursorDictRowsMixIn(object): """This is a MixIn class that causes all rows to be returned as dictionaries. This is a non-standard feature.""" _fetch_type = 1 def fetchoneDict(self): """Fetch a single row as a dictionary. Deprecated: Use fetchone() instead. Will be removed in 1.3.""" from warnings import warn warn("fetchoneDict() is non-standard and will be removed in 1.3", DeprecationWarning, 2) return self.fetchone() def fetchmanyDict(self, size=None): """Fetch several rows as a list of dictionaries. Deprecated: Use fetchmany() instead. Will be removed in 1.3.""" from warnings import warn warn("fetchmanyDict() is non-standard and will be removed in 1.3", DeprecationWarning, 2) return self.fetchmany(size) def fetchallDict(self): """Fetch all available rows as a list of dictionaries. Deprecated: Use fetchall() instead. Will be removed in 1.3.""" from warnings import warn warn("fetchallDict() is non-standard and will be removed in 1.3", DeprecationWarning, 2) return self.fetchall() class CursorOldDictRowsMixIn(CursorDictRowsMixIn): """This is a MixIn class that returns rows as dictionaries with the same key convention as the old Mysqldb (MySQLmodule). Don't use this.""" _fetch_type = 2 class Cursor(CursorStoreResultMixIn, CursorTupleRowsMixIn, BaseCursor): """This is the standard Cursor class that returns rows as tuples and stores the result set in the client.""" class DictCursor(CursorStoreResultMixIn, CursorDictRowsMixIn, BaseCursor): """This is a Cursor class that returns rows as dictionaries and stores the result set in the client.""" class SSCursor(CursorUseResultMixIn, CursorTupleRowsMixIn, BaseCursor): """This is a Cursor class that returns rows as tuples and stores the result set in the server.""" class SSDictCursor(CursorUseResultMixIn, CursorDictRowsMixIn, BaseCursor): """This is a Cursor class that returns rows as dictionaries and stores the result set in the server.""" ================================================ FILE: dev_server/sae/_restful_mysql/monkey.py ================================================ # Copyright (C) 2012-2013 SINA, All rights reserved. def patch(): import sys if 'MySQLdb' in sys.modules: import warnings warnings.warn('MySQLdb has alreay been imported', Warning) modules_to_replace = ( 'MySQLdb', 'MySQLdb.release', 'MySQLdb.connections', 'MySQLdb.cursors', 'MySQLdb.converters', 'MySQLdb.constants', 'MySQLdb.constants.CLIENT', 'MySQLdb.constants.FIELD_TYPE', 'MySQLdb.constants.FLAG', ) for name in modules_to_replace: if name in sys.modules: sys.modules.pop(name) import sae._restful_mysql from sae._restful_mysql import _mysql, _mysql_exceptions sys.modules['MySQLdb'] = sae._restful_mysql sys.modules['_mysql'] = _mysql sys.modules['_mysql_exceptions'] = _mysql_exceptions ================================================ FILE: dev_server/sae/_restful_mysql/release.py ================================================ __author__ = "Andy Dustman " version_info = (1,2,3,'final',0) __version__ = "1.2.3" ================================================ FILE: dev_server/sae/_restful_mysql/times.py ================================================ """times module This module provides some Date and Time classes for dealing with MySQL data. Use Python datetime module to handle date and time columns.""" import math from time import localtime from datetime import date, datetime, time, timedelta from _mysql import string_literal Date = date Time = time TimeDelta = timedelta Timestamp = datetime DateTimeDeltaType = timedelta DateTimeType = datetime def DateFromTicks(ticks): """Convert UNIX ticks into a date instance.""" return date(*localtime(ticks)[:3]) def TimeFromTicks(ticks): """Convert UNIX ticks into a time instance.""" return time(*localtime(ticks)[3:6]) def TimestampFromTicks(ticks): """Convert UNIX ticks into a datetime instance.""" return datetime(*localtime(ticks)[:6]) format_TIME = format_DATE = str def format_TIMEDELTA(v): seconds = int(v.seconds) % 60 minutes = int(v.seconds / 60) % 60 hours = int(v.seconds / 3600) % 24 return '%d %d:%d:%d' % (v.days, hours, minutes, seconds) def format_TIMESTAMP(d): return d.strftime("%Y-%m-%d %H:%M:%S") def DateTime_or_None(s): if ' ' in s: sep = ' ' elif 'T' in s: sep = 'T' else: return Date_or_None(s) try: d, t = s.split(sep, 1) return datetime(*[ int(x) for x in d.split('-')+t.split(':') ]) except: return Date_or_None(s) def TimeDelta_or_None(s): try: h, m, s = s.split(':') h, m, s = int(h), int(m), float(s) td = timedelta(hours=abs(h), minutes=m, seconds=int(s), microseconds=int(math.modf(s)[0] * 1000000)) if h < 0: return -td else: return td except ValueError: # unpacking or int/float conversion failed return None def Time_or_None(s): try: h, m, s = s.split(':') h, m, s = int(h), int(m), float(s) return time(hour=h, minute=m, second=int(s), microsecond=int(math.modf(s)[0] * 1000000)) except ValueError: return None def Date_or_None(s): try: return date(*[ int(x) for x in s.split('-',2)]) except: return None def DateTime2literal(d, c): """Format a DateTime object as an ISO timestamp.""" return string_literal(format_TIMESTAMP(d),c) def DateTimeDelta2literal(d, c): """Format a DateTimeDelta object as a time.""" return string_literal(format_TIMEDELTA(d),c) def mysql_timestamp_converter(s): """Convert a MySQL TIMESTAMP to a Timestamp object.""" # MySQL>4.1 returns TIMESTAMP in the same format as DATETIME if s[4] == '-': return DateTime_or_None(s) s = s + "0"*(14-len(s)) # padding parts = map(int, filter(None, (s[:4],s[4:6],s[6:8], s[8:10],s[10:12],s[12:14]))) try: return Timestamp(*parts) except: return None ================================================ FILE: dev_server/sae/channel.js ================================================ (function(){var COMPILED=!0,goog=goog||{};goog.global=this;goog.exportPath_=function(a,b,c){a=a.split(".");c=c||goog.global;a[0]in c||!c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)a.length||void 0===b?c=c[d]?c[d]:c[d]={}:c[d]=b};goog.define=function(a,b){var c=b;COMPILED||goog.global.CLOSURE_DEFINES&&Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_DEFINES,a)&&(c=goog.global.CLOSURE_DEFINES[a]);goog.exportPath_(a,c)};goog.DEBUG=!0;goog.LOCALE="en";goog.TRUSTED_SITE=!0; goog.provide=function(a){if(!COMPILED){if(goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');delete goog.implicitNamespaces_[a];for(var b=a;(b=b.substring(0,b.lastIndexOf(".")))&&!goog.getObjectByName(b);)goog.implicitNamespaces_[b]=!0}goog.exportPath_(a)};goog.setTestOnly=function(a){if(COMPILED&&!goog.DEBUG)throw a=a||"",Error("Importing test-only code into non-debug environment"+a?": "+a:".");}; COMPILED||(goog.isProvided_=function(a){return!goog.implicitNamespaces_[a]&&!!goog.getObjectByName(a)},goog.implicitNamespaces_={});goog.getObjectByName=function(a,b){for(var c=a.split("."),d=b||goog.global,e;e=c.shift();)if(goog.isDefAndNotNull(d[e]))d=d[e];else return null;return d};goog.globalize=function(a,b){var c=b||goog.global,d;for(d in a)c[d]=a[d]}; goog.addDependency=function(a,b,c){if(goog.DEPENDENCIES_ENABLED){var d;a=a.replace(/\\/g,"/");for(var e=goog.dependencies_,f=0;d=b[f];f++)e.nameToPath[d]=a,a in e.pathToNames||(e.pathToNames[a]={}),e.pathToNames[a][d]=!0;for(d=0;b=c[d];d++)a in e.requires||(e.requires[a]={}),e.requires[a][b]=!0}};goog.ENABLE_DEBUG_LOADER=!0; goog.require=function(a){if(!COMPILED&&!goog.isProvided_(a)){if(goog.ENABLE_DEBUG_LOADER){var b=goog.getPathFromDeps_(a);if(b){goog.included_[b]=!0;goog.writeScripts_();return}}a="goog.require could not find: "+a;goog.global.console&&goog.global.console.error(a);throw Error(a);}};goog.basePath="";goog.nullFunction=function(){};goog.identityFunction=function(a,b){return a};goog.abstractMethod=function(){throw Error("unimplemented abstract method");}; goog.addSingletonGetter=function(a){a.getInstance=function(){if(a.instance_)return a.instance_;goog.DEBUG&&(goog.instantiatedSingletons_[goog.instantiatedSingletons_.length]=a);return a.instance_=new a}};goog.instantiatedSingletons_=[];goog.DEPENDENCIES_ENABLED=!COMPILED&&goog.ENABLE_DEBUG_LOADER; goog.DEPENDENCIES_ENABLED&&(goog.included_={},goog.dependencies_={pathToNames:{},nameToPath:{},requires:{},visited:{},written:{}},goog.inHtmlDocument_=function(){var a=goog.global.document;return"undefined"!=typeof a&&"write"in a},goog.findBasePath_=function(){if(goog.global.CLOSURE_BASE_PATH)goog.basePath=goog.global.CLOSURE_BASE_PATH;else if(goog.inHtmlDocument_())for(var a=goog.global.document.getElementsByTagName("script"),b=a.length-1;0<=b;--b){var c=a[b].src,d=c.lastIndexOf("?"),d=-1==d?c.length: d;if("base.js"==c.substr(d-7,7)){goog.basePath=c.substr(0,d-7);break}}},goog.importScript_=function(a){var b=goog.global.CLOSURE_IMPORT_SCRIPT||goog.writeScriptTag_;!goog.dependencies_.written[a]&&b(a)&&(goog.dependencies_.written[a]=!0)},goog.writeScriptTag_=function(a){if(goog.inHtmlDocument_()){var b=goog.global.document;if("complete"==b.readyState){if(/\bdeps.js$/.test(a))return!1;throw Error('Cannot write "'+a+'" after document load');}b.write(' .. js:class:: sae.Channel(url) :param string url: 服务端create_channel()返回的url地址 .. js:attribute:: onopen 设置客户端连接上服务端时的回调函数。 .. js:attribute:: onmessage 设置客户端收到消息时的回调函数。该函数接受一个参数:一个messagae对象,其中的data字段为服务端send_message接口发送的消息内容。 .. js:attribute:: onerror 设置客户端和服务端连接出现错误时的回调函数。 .. js:attribute:: onclose 设置客户端关闭和服务端的连接时的回调函数。 服务使用示例 ~~~~~~~~~~~~~~ 下面我们使用 `TicTacToe(井字棋)`_ 游戏来示范channel服务的使用方法: .. _TicTacToe(井字棋): http://zh.wikipedia.org/wiki/%E4%BA%95%E5%AD%97%E6%A3%8B 完整代码:https://github.com/sinacloud/sae-channel-examples/tree/master/python **channel的创建和连接** 首先,当用户A打开TicTacToe游戏的主页时,TicTacToe服务端的程序会: + 调用 `create_channel` 创建为用户A创建一个channel,并将该channel的url嵌入到返回给用户的html页面代码中。 + 生成一个加入游戏的连接,用户通过将此连接发送给其它用户B,其它用户B可以通过此连接加入用户A创建的游戏。 每个页面对应的channel的name应该是独一无二的,比如可以使用用户id的字符串作为channel的name。 游戏的主页的html代码模板大致如下所示,其中 `{{ url }}` 和 `{{ game_link }}` 分别为上面生成的channel url和游戏加入连接。 :: ... ... 游戏的js客户端使用 `sae.Channel` 来创建一条channel连接,并且设置channel的onopen/onmessage/onerror/onclose的callback函数。 **使用channel来推送游戏状态信息** 当用户B点击用户A发过来的连接打开了游戏页面时,游戏的javascript客户端通过 `sendMessage` 函数通知服务端。 :: onOpened = function() { connected = true; sendMessage('opened'); updateBoard(); }; sendMessage = function(path, opt_param) { path += '?g=' + state.game_key; if (opt_param) { path += '&' + opt_param; } var xhr = new XMLHttpRequest(); xhr.open('POST', path, true); xhr.send(); }; 服务端更新当前游戏的状态,并且通过channel的 `send_message` 将游戏的新的状态发送给用户A和用户B的channel客户端。客户端接受到消息后更新游戏页面。此后用户A和用户B交替走棋,客户端通过 `sendMessage` 将用户的走法发送给服务端。 :: moveInSquare = function(id) { if (isMyMove() && state.board[id] == ' ') { sendMessage('/move', 'i=' + id); } } 服务收到消息后更新游戏的状态,再通过 `send_message` 将更新后的状态发送给用户A和B,如此往复直到游戏结束为止。 :: class MovePage(tornado.web.RequestHandler): def post(self): game_key = self.get_argument('g') game = Game.get_by_key_name(game_key) user = self.get_secure_cookie('u') if game and user: id = int(self.get_argument('i')) GameUpdater(game).make_move(id, user) class GameUpdater(): game = None def __init__(self, game): self.game = game def get_game_message(self): gameUpdate = { 'board': self.game.board, 'userX': self.game.userX, 'userO': '' if not self.game.userO else self.game.userO, 'moveX': self.game.moveX, 'winner': self.game.winner, 'winningBoard': self.game.winning_board } return json.dumps(gameUpdate) def send_update(self): message = self.get_game_message() channel.send_message(self.game.userX + self.game.key_name, message) if self.game.userO: channel.send_message(self.game.userO + self.game.key_name, message) def check_win(self): if self.game.moveX: # O just moved, check for O wins wins = Wins().o_wins potential_winner = self.game.userO else: # X just moved, check for X wins wins = Wins().x_wins potential_winner = self.game.userX for win in wins: if win.match(self.game.board): self.game.winner = potential_winner self.game.winning_board = win.pattern return def make_move(self, position, user): if position >= 0 and user == self.game.userX or user == self.game.userO: if self.game.moveX == (user == self.game.userX): boardList = list(self.game.board) if (boardList[position] == ' '): boardList[position] = 'X' if self.game.moveX else 'O' self.game.board = "".join(boardList) self.game.moveX = not self.game.moveX self.check_win() self.game.put() self.send_update() return GameUpdater类检查move的请求是否合法,如果合法则更新游戏的状态并且通知游戏双方新的游戏状态。 .. note:: 1. 每个html页面最多可以建立1个channel连接。 2. 每个创建的channel只允许一个channel客户端连接。 中文分词 ------------------- **分词服务请求** SAE分词服务请求采用以下形式的HTTP网址: :: http://segment.sae.sina.com.cn/urlclient.php?parameters parameters为请求参数,多个参数之间使用&分割,以下列出了这些参数和其可能的值。 * encoding: 请求分词的文本的编码,可以为: GB18030、UTF-8、UCS-2。 * word_tag: 可选。是否返回词性数据。0表示不返回,1表示返回。 请求分词的文本以post的形式提交。 * context: 请求分词的文本。目前限制文本大小最大为10KB。 **分词服务响应** 分词服务的响应数据为json格式,格式如下: :: [ {"word":"采莲","word_tag":"171","index":"1"}, {"word":"赋","word_tag":"170","index":"2"} ] 响应数据为一个list,list中每个元素为一个dict,每个dict中包含以下数据: * index: 序列号,按在请求文本中的位置依次递增。 * word: 单词 * word_tag: 单词的词性,仅当输入parameters里word_tag为1时包含该项。 词性代码: :: 0 POSTAG_ID_UNKNOW 未知 10 POSTAG_ID_A 形容词 20 POSTAG_ID_B 区别词 30 POSTAG_ID_C 连词 31 POSTAG_ID_C_N 体词连接 32 POSTAG_ID_C_Z 分句连接 40 POSTAG_ID_D 副词 41 POSTAG_ID_D_B 副词("不") 42 POSTAG_ID_D_M 副词("没") 50 POSTAG_ID_E 叹词 60 POSTAG_ID_F 方位词 61 POSTAG_ID_F_S 方位短语(处所词+方位词) 62 POSTAG_ID_F_N 方位短语(名词+方位词“地上”) 63 POSTAG_ID_F_V 方位短语(动词+方位词“取前”) 64 POSTAG_ID_F_Z 方位短语(动词+方位词“取前”) 70 POSTAG_ID_H 前接成分 71 POSTAG_ID_H_M 数词前缀(“数”---数十) 72 POSTAG_ID_H_T 时间词前缀(“公元”“明永乐”) 73 POSTAG_ID_H_NR 姓氏 74 POSTAG_ID_H_N 姓氏 80 POSTAG_ID_K 后接成分 81 POSTAG_ID_K_M 数词后缀(“来”--,十来个) 82 POSTAG_ID_K_T 时间词后缀(“初”“末”“时”) 83 POSTAG_ID_K_N 名词后缀(“们”) 84 POSTAG_ID_K_S 处所词后缀(“苑”“里”) 85 POSTAG_ID_K_Z 状态词后缀(“然”) 86 POSTAG_ID_K_NT 状态词后缀(“然”) 87 POSTAG_ID_K_NS 状态词后缀(“然”) 90 POSTAG_ID_M 数词 95 POSTAG_ID_N 名词 96 POSTAG_ID_N_RZ 人名(“毛泽东”) 97 POSTAG_ID_N_T 机构团体(“团”的声母为t,名词代码n和t并在一起。“公司”) 98 POSTAG_ID_N_TA .... 99 POSTAG_ID_N_TZ 机构团体名("北大") 100 POSTAG_ID_N_Z 其他专名(“专”的声母的第1个字母为z,名词代码n和z并在一起。) 101 POSTAG_ID_NS 名处词 102 POSTAG_ID_NS_Z 地名(名处词专指:“中国”) 103 POSTAG_ID_N_M n-m,数词开头的名词(三个学生) 104 POSTAG_ID_N_RB n-rb,以区别词/代词开头的名词(该学校,该生) 107 POSTAG_ID_O 拟声词 108 POSTAG_ID_P 介词 110 POSTAG_ID_Q 量词 111 POSTAG_ID_Q_V 动量词(“趟”“遍”) 112 POSTAG_ID_Q_T 时间量词(“年”“月”“期”) 113 POSTAG_ID_Q_H 货币量词(“元”“美元”“英镑”) 120 POSTAG_ID_R 代词 121 POSTAG_ID_R_D 副词性代词(“怎么”) 122 POSTAG_ID_R_M 数词性代词(“多少”) 123 POSTAG_ID_R_N 名词性代词(“什么”“谁”) 124 POSTAG_ID_R_S 处所词性代词(“哪儿”) 125 POSTAG_ID_R_T 时间词性代词(“何时”) 126 POSTAG_ID_R_Z 谓词性代词(“怎么样”) 127 POSTAG_ID_R_B 区别词性代词(“某”“每”) 130 POSTAG_ID_S 处所词(取英语space的第1个字母。“东部”) 131 POSTAG_ID_S_Z 处所词(取英语space的第1个字母。“东部”) 132 POSTAG_ID_T 时间词(取英语time的第1个字母) 133 POSTAG_ID_T_Z 时间专指(“唐代”“西周”) 140 POSTAG_ID_U 助词 141 POSTAG_ID_U_N 定语助词(“的”) 142 POSTAG_ID_U_D 状语助词(“地”) 143 POSTAG_ID_U_C 补语助词(“得”) 144 POSTAG_ID_U_Z 谓词后助词(“了、着、过”) 145 POSTAG_ID_U_S 体词后助词(“等、等等”) 146 POSTAG_ID_U_SO 助词(“所”) 150 POSTAG_ID_W 标点符号 151 POSTAG_ID_W_D 顿号(“、”) 152 POSTAG_ID_W_SP 句号(“。”) 153 POSTAG_ID_W_S 分句尾标点(“,”“;”) 154 POSTAG_ID_W_L 搭配型标点左部 155 POSTAG_ID_W_R 搭配型标点右部(“》”“]”“)”) 156 POSTAG_ID_W_H 中缀型符号 160 POSTAG_ID_Y 语气词(取汉字“语”的声母。“吗”“吧”“啦”) 170 POSTAG_ID_V 及物动词(取英语动词verb的第一个字母。) 171 POSTAG_ID_V_O 不及物谓词(谓宾结构“剃头”) 172 POSTAG_ID_V_E 动补结构动词(“取出”“放到”) 173 POSTAG_ID_V_SH 动词“是” 174 POSTAG_ID_V_YO 动词“有” 175 POSTAG_ID_V_Q 趋向动词(“来”“去”“进来”) 176 POSTAG_ID_V_A 助动词(“应该”“能够”) 180 POSTAG_ID_Z 状态词(不及物动词,v-o、sp之外的不及物动词) 190 POSTAG_ID_X 语素字 191 POSTAG_ID_X_N 名词语素(“琥”) 192 POSTAG_ID_X_V 动词语素(“酹”) 193 POSTAG_ID_X_S 处所词语素(“中”“日”“美”) 194 POSTAG_ID_X_T 时间词语素(“唐”“宋”“元”) 195 POSTAG_ID_X_Z 状态词语素(“伟”“芳”) 196 POSTAG_ID_X_B 状态词语素(“伟”“芳”) 200 POSTAG_ID_SP 不及物谓词(主谓结构“腰酸”“头疼”) 201 POSTAG_ID_MQ 数量短语(“叁个”) 202 POSTAG_ID_RQ 代量短语(“这个”) 210 POSTAG_ID_AD 副形词(直接作状语的形容词) 211 POSTAG_ID_AN 名形词(具有名词功能的形容词) 212 POSTAG_ID_VD 副动词(直接作状语的动词) 213 POSTAG_ID_VN 名动词(指具有名词功能的动词) 230 POSTAG_ID_SPACE 空格 例: :: chinese_text = """ 这里填上需要分词的文本 """ _SEGMENT_BASE_URL = 'http://segment.sae.sina.com.cn/urlclient.php' payload = urllib.urlencode([('context', chinese_text),]) args = urllib.urlencode([('word_tag', 1), ('encoding', 'UTF-8'),]) url = _SEGMENT_BASE_URL + '?' + args result = urllib2.urlopen(url, payload).read() 短信 ------------------ **短信服务请求** SAE短信服务请求采用以下形式的HTTP网址: :: http://inno.smsinter.sina.com.cn/sae_sms_service/sendsms.php 参数采用POST的方法提交,以下列出了这些参数和其可能的值。 * mobile: 对方的手机号码。 * msg: 短信发送的内容。 * encoding: 可选。短信发送内容的编码格式,可以为:GB2312、UTF-8,默认为GB2312。 **短信服务响应** 短信服务的响应为json格式,格式如下: :: { "sms": { "encoding": "GB2312", "mobile": "18911978203", "msg": "hello....." }, "status": "\\u77ed\\u4fe1\\u63d0\\u4ea4\\u6210\\u529f" } 响应数据为一个dict,dict中包含以下数据: * sms: 短信服务请求的参数。 * status:短信发送的状态。 .. warning:: 短信接口默认msg参数的编码格式为GB2312,如果短信的内容包含中文,请务必正确的编码msg或者选择正确的encoding参数。 ================================================ FILE: docs/static/memcache.html ================================================ Python: module memcache
 
 
memcache (version 1.48)
index
/tmp/python-memcached-1.48/memcache.py

client module for memcached (memory cache daemon)
 
Overview
========
 
See U{the MemCached homepage<http://www.danga.com/memcached>} for more about memcached.
 
Usage summary
=============
 
This should give you a feel for how this module operates::
 
    import memcache
    mc = memcache.Client(['127.0.0.1:11211'], debug=0)
 
    mc.set("some_key", "Some value")
    value = mc.get("some_key")
 
    mc.set("another_key", 3)
    mc.delete("another_key")
 
    mc.set("key", "1")   # note that the key used for incr/decr must be a string.
    mc.incr("key")
    mc.decr("key")
 
The standard way to use memcache with a database is like this::
 
    key = derive_key(obj)
    obj = mc.get(key)
    if not obj:
        obj = backend_api.get(...)
        mc.set(key, obj)
 
    # we now have obj, and future passes through this code
    # will use the object from the cache.
 
Detailed Documentation
======================
 
More detailed documentation is available in the L{Client} class.

 
Modules
       
os
cPickle
re
socket
sys
time

 
Classes
       
thread._local(__builtin__.object)
Client

 
class Client(thread._local)
    Object representing a pool of memcache servers.
 
See L{memcache} for an overview.
 
In all cases where a key is used, the key can be either:
    1. A simple hashable type (string, integer, etc.).
    2. A tuple of C{(hashvalue, key)}.  This is useful if you want to avoid
    making this module calculate a hash value.  You may prefer, for
    example, to keep all of a given user's objects on the same memcache
    server, so you could use the user's unique id as the hash value.
 
@group Setup: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog
@group Insertion: set, add, replace, set_multi
@group Retrieval: get, get_multi
@group Integers: incr, decr
@group Removal: delete, delete_multi
@sort: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog,           set, set_multi, add, replace, get, get_multi, incr, decr, delete, delete_multi
 
 
Method resolution order:
Client
thread._local
__builtin__.object

Methods defined here:
__init__(self, servers, debug=0, pickleProtocol=0, pickler=<built-in function Pickler>, unpickler=<built-in function Unpickler>, pload=None, pid=None, server_max_key_length=250, server_max_value_length=1048576, dead_retry=30, socket_timeout=3, cache_cas=False)
Create a new Client object with the given list of servers.
 
@param servers: C{servers} is passed to L{set_servers}.
@param debug: whether to display error messages when a server can't be
contacted.
@param pickleProtocol: number to mandate protocol used by (c)Pickle.
@param pickler: optional override of default Pickler to allow subclassing.
@param unpickler: optional override of default Unpickler to allow subclassing.
@param pload: optional persistent_load function to call on pickle loading.
Useful for cPickle since subclassing isn't allowed.
@param pid: optional persistent_id function to call on pickle storing.
Useful for cPickle since subclassing isn't allowed.
@param dead_retry: number of seconds before retrying a blacklisted
server. Default to 30 s.
@param socket_timeout: timeout in seconds for all calls to a server. Defaults
to 3 seconds.
@param cache_cas: (default False) If true, cas operations will be
cached.  WARNING: This cache is not expired internally, if you have
a long-running process you will need to expire it manually via
"client.reset_cas(), or the cache can grow unlimited.
@param server_max_key_length: (default SERVER_MAX_KEY_LENGTH)
Data that is larger than this will not be sent to the server.
@param server_max_value_length: (default SERVER_MAX_VALUE_LENGTH)
Data that is larger than this will not be sent to the server.
add(self, key, val, time=0, min_compress_len=0)
Add new key with value.
 
Like L{set}, but only stores in memcache if the key doesn't already exist.
 
@return: Nonzero on success.
@rtype: int
append(self, key, val, time=0, min_compress_len=0)
Append the value to the end of the existing key's value.
 
Only stores in memcache if key already exists.
Also see L{prepend}.
 
@return: Nonzero on success.
@rtype: int
cas(self, key, val, time=0, min_compress_len=0)
Sets a key to a given value in the memcache if it hasn't been
altered since last fetched. (See L{gets}).
 
The C{key} can optionally be an tuple, with the first element
being the server hash value and the second being the key.
If you want to avoid making this module calculate a hash value.
You may prefer, for example, to keep all of a given user's objects
on the same memcache server, so you could use the user's unique
id as the hash value.
 
@return: Nonzero on success.
@rtype: int
@param time: Tells memcached the time which this value should expire,
either as a delta number of seconds, or an absolute unix
time-since-the-epoch value. See the memcached protocol docs section
"Storage Commands" for more info on <exptime>. We default to
0 == cache forever.
@param min_compress_len: The threshold length to kick in
auto-compression of the value using the zlib.compress() routine. If
the value being cached is a string, then the length of the string is
measured, else if the value is an object, then the length of the
pickle result is measured. If the resulting attempt at compression
yeilds a larger string than the input, then it is discarded. For
backwards compatability, this parameter defaults to 0, indicating
don't ever try to compress.
check_key(self, key, key_extra_len=0)
Checks sanity of key.  Fails if:
Key length is > SERVER_MAX_KEY_LENGTH (Raises MemcachedKeyLength).
Contains control characters  (Raises MemcachedKeyCharacterError).
Is not a string (Raises MemcachedStringEncodingError)
Is an unicode string (Raises MemcachedStringEncodingError)
Is not a string (Raises MemcachedKeyError)
Is None (Raises MemcachedKeyError)
debuglog(self, str)
decr(self, key, delta=1)
Like L{incr}, but decrements.  Unlike L{incr}, underflow is checked and
new values are capped at 0.  If server value is 1, a decrement of 2
returns 0, not -1.
 
@param delta: Integer amount to decrement by (should be zero or greater).
@return: New value after decrementing.
@rtype: int
delete(self, key, time=0)
Deletes a key from the memcache.
 
@return: Nonzero on success.
@param time: number of seconds any subsequent set / update commands
should fail. Defaults to None for no delay.
@rtype: int
delete_multi(self, keys, time=0, key_prefix='')
Delete multiple keys in the memcache doing just one query.
 
>>> notset_keys = mc.set_multi({'key1' : 'val1', 'key2' : 'val2'})
>>> mc.get_multi(['key1', 'key2']) == {'key1' : 'val1', 'key2' : 'val2'}
1
>>> mc.delete_multi(['key1', 'key2'])
1
>>> mc.get_multi(['key1', 'key2']) == {}
1
 
 
This method is recommended over iterated regular L{delete}s as it reduces total latency, since
your app doesn't have to wait for each round-trip of L{delete} before sending
the next one.
 
@param keys: An iterable of keys to clear
@param time: number of seconds any subsequent set / update commands should fail. Defaults to 0 for no delay.
@param key_prefix:  Optional string to prepend to each key when sending to memcache.
    See docs for L{get_multi} and L{set_multi}.
 
@return: 1 if no failure in communication with any memcacheds.
@rtype: int
disconnect_all(self)
flush_all(self)
Expire all data currently in the memcache servers.
forget_dead_hosts(self)
Reset every host in the pool to an "alive" state.
get(self, key)
Retrieves a key from the memcache.
 
@return: The value or None.
get_multi(self, keys, key_prefix='')
Retrieves multiple keys from the memcache doing just one query.
 
>>> success = mc.set("foo", "bar")
>>> success = mc.set("baz", 42)
>>> mc.get_multi(["foo", "baz", "foobar"]) == {"foo": "bar", "baz": 42}
1
>>> mc.set_multi({'k1' : 1, 'k2' : 2}, key_prefix='pfx_') == []
1
 
This looks up keys 'pfx_k1', 'pfx_k2', ... . Returned dict will just have unprefixed keys 'k1', 'k2'.
>>> mc.get_multi(['k1', 'k2', 'nonexist'], key_prefix='pfx_') == {'k1' : 1, 'k2' : 2}
1
 
get_mult [ and L{set_multi} ] can take str()-ables like ints / longs as keys too. Such as your db pri key fields.
They're rotored through str() before being passed off to memcache, with or without the use of a key_prefix.
In this mode, the key_prefix could be a table name, and the key itself a db primary key number.
 
>>> mc.set_multi({42: 'douglass adams', 46 : 'and 2 just ahead of me'}, key_prefix='numkeys_') == []
1
>>> mc.get_multi([46, 42], key_prefix='numkeys_') == {42: 'douglass adams', 46 : 'and 2 just ahead of me'}
1
 
This method is recommended over regular L{get} as it lowers the number of
total packets flying around your network, reducing total latency, since
your app doesn't have to wait for each round-trip of L{get} before sending
the next one.
 
See also L{set_multi}.
 
@param keys: An array of keys.
@param key_prefix: A string to prefix each key when we communicate with memcache.
    Facilitates pseudo-namespaces within memcache. Returned dictionary keys will not have this prefix.
@return:  A dictionary of key/value pairs that were available. If key_prefix was provided, the keys in the retured dictionary will not have it present.
get_slabs(self)
get_stats(self, stat_args=None)
Get statistics from each of the servers.
 
@param stat_args: Additional arguments to pass to the memcache
    "stats" command.
 
@return: A list of tuples ( server_identifier, stats_dictionary ).
    The dictionary contains a number of name/value pairs specifying
    the name of the status field and the string value associated with
    it.  The values are not converted from strings.
gets(self, key)
Retrieves a key from the memcache. Used in conjunction with 'cas'.
 
@return: The value or None.
incr(self, key, delta=1)
Sends a command to the server to atomically increment the value
for C{key} by C{delta}, or by 1 if C{delta} is unspecified.
Returns None if C{key} doesn't exist on server, otherwise it
returns the new value after incrementing.
 
Note that the value for C{key} must already exist in the memcache,
and it must be the string representation of an integer.
 
>>> mc.set("counter", "20")  # returns 1, indicating success
1
>>> mc.incr("counter")
21
>>> mc.incr("counter")
22
 
Overflow on server is not checked.  Be aware of values approaching
2**32.  See L{decr}.
 
@param delta: Integer amount to increment by (should be zero or greater).
@return: New value after incrementing.
@rtype: int
prepend(self, key, val, time=0, min_compress_len=0)
Prepend the value to the beginning of the existing key's value.
 
Only stores in memcache if key already exists.
Also see L{append}.
 
@return: Nonzero on success.
@rtype: int
replace(self, key, val, time=0, min_compress_len=0)
Replace existing key with value.
 
Like L{set}, but only stores in memcache if the key already exists.
The opposite of L{add}.
 
@return: Nonzero on success.
@rtype: int
reset_cas(self)
Reset the cas cache.  This is only used if the Client() object
was created with "cache_cas=True".  If used, this cache does not
expire internally, so it can grow unbounded if you do not clear it
yourself.
set(self, key, val, time=0, min_compress_len=0)
Unconditionally sets a key to a given value in the memcache.
 
The C{key} can optionally be an tuple, with the first element
being the server hash value and the second being the key.
If you want to avoid making this module calculate a hash value.
You may prefer, for example, to keep all of a given user's objects
on the same memcache server, so you could use the user's unique
id as the hash value.
 
@return: Nonzero on success.
@rtype: int
@param time: Tells memcached the time which this value should expire, either
as a delta number of seconds, or an absolute unix time-since-the-epoch
value. See the memcached protocol docs section "Storage Commands"
for more info on <exptime>. We default to 0 == cache forever.
@param min_compress_len: The threshold length to kick in auto-compression
of the value using the zlib.compress() routine. If the value being cached is
a string, then the length of the string is measured, else if the value is an
object, then the length of the pickle result is measured. If the resulting
attempt at compression yeilds a larger string than the input, then it is
discarded. For backwards compatability, this parameter defaults to 0,
indicating don't ever try to compress.
set_multi(self, mapping, time=0, key_prefix='', min_compress_len=0)
Sets multiple keys in the memcache doing just one query.
 
>>> notset_keys = mc.set_multi({'key1' : 'val1', 'key2' : 'val2'})
>>> mc.get_multi(['key1', 'key2']) == {'key1' : 'val1', 'key2' : 'val2'}
1
 
 
This method is recommended over regular L{set} as it lowers the number of
total packets flying around your network, reducing total latency, since
your app doesn't have to wait for each round-trip of L{set} before sending
the next one.
 
@param mapping: A dict of key/value pairs to set.
@param time: Tells memcached the time which this value should expire, either
as a delta number of seconds, or an absolute unix time-since-the-epoch
value. See the memcached protocol docs section "Storage Commands"
for more info on <exptime>. We default to 0 == cache forever.
@param key_prefix:  Optional string to prepend to each key when sending to memcache. Allows you to efficiently stuff these keys into a pseudo-namespace in memcache:
    >>> notset_keys = mc.set_multi({'key1' : 'val1', 'key2' : 'val2'}, key_prefix='subspace_')
    >>> len(notset_keys) == 0
    True
    >>> mc.get_multi(['subspace_key1', 'subspace_key2']) == {'subspace_key1' : 'val1', 'subspace_key2' : 'val2'}
    True
 
    Causes key 'subspace_key1' and 'subspace_key2' to be set. Useful in conjunction with a higher-level layer which applies namespaces to data in memcache.
    In this case, the return result would be the list of notset original keys, prefix not applied.
 
@param min_compress_len: The threshold length to kick in auto-compression
of the value using the zlib.compress() routine. If the value being cached is
a string, then the length of the string is measured, else if the value is an
object, then the length of the pickle result is measured. If the resulting
attempt at compression yeilds a larger string than the input, then it is
discarded. For backwards compatability, this parameter defaults to 0,
indicating don't ever try to compress.
@return: List of keys which failed to be stored [ memcache out of memory, etc. ].
@rtype: list
set_servers(self, servers)
Set the pool of servers used by this client.
 
@param servers: an array of servers.
Servers can be passed in two forms:
    1. Strings of the form C{"host:port"}, which implies a default weight of 1.
    2. Tuples of the form C{("host:port", weight)}, where C{weight} is
    an integer weight value.

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)

Data and other attributes defined here:
MemcachedKeyCharacterError = <class 'memcache.MemcachedKeyCharacterError'>
MemcachedKeyError = <class 'memcache.MemcachedKeyError'>
MemcachedKeyLengthError = <class 'memcache.MemcachedKeyLengthError'>
MemcachedKeyNoneError = <class 'memcache.MemcachedKeyNoneError'>
MemcachedKeyTypeError = <class 'memcache.MemcachedKeyTypeError'>
MemcachedStringEncodingError = <class 'memcache.MemcachedStringEncodingError'>

Methods inherited from thread._local:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value

Data and other attributes inherited from thread._local:
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T

 
Functions
       
StringIO(...)
StringIO([s]) -- Return a StringIO-like stream for reading or writing
cmemcache_hash(key)
compress(...)
compress(string[, level]) -- Returned compressed string.
 
Optional arg level is the compression level, in 1-9.
crc32(...)
(data, oldcrc = 0) -> newcrc. Compute CRC-32 incrementally
decompress(...)
decompress(string[, wbits[, bufsize]]) -- Return decompressed string.
 
Optional arg wbits is the window buffer size.  Optional arg bufsize is
the initial output buffer size.
serverHashFunction = cmemcache_hash(key)
useOldServerHashFunction()
Use the old python-memcache server hash function.

 
Data
        SERVER_MAX_KEY_LENGTH = 250
SERVER_MAX_VALUE_LENGTH = 1048576
__author__ = 'Sean Reifschneider <jafo-memcached@tummy.com>'
__copyright__ = 'Copyright (C) 2003 Danga Interactive'
__license__ = 'Python Software Foundation License'
__version__ = '1.48'

 
Author
        Sean Reifschneider <jafo-memcached@tummy.com>
================================================ FILE: docs/theme/nature/layout.html ================================================ {% extends "basic/layout.html" %} {% set script_files = script_files + ["_static/sae.js"] %} ================================================ FILE: docs/theme/nature/static/nature.css_t ================================================ /* * nature.css_t * ~~~~~~~~~~~~ * * Sphinx stylesheet -- nature theme. * * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: Arial, sans-serif; font-size: 100%; background-color: #111; color: #555; margin: 0; padding: 0; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 {{ theme_sidebarwidth|toint }}px; } hr { border: 1px solid #B1B4B6; } div.document { background-color: #eee; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; font-size: 0.9em; } div.footer { color: #555; width: 100%; padding: 13px 0; text-align: center; font-size: 75%; } div.footer a { color: #444; text-decoration: underline; } div.related { background-color: #6BA81E; line-height: 32px; color: #fff; text-shadow: 0px 1px 0 #444; font-size: 0.9em; } div.related a { color: #E2F3CC; } div.sphinxsidebar { font-size: 0.75em; line-height: 1.5em; } div.sphinxsidebarwrapper{ padding: 20px 0; } div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: Arial, sans-serif; color: #222; font-size: 1.2em; font-weight: normal; margin: 0; padding: 5px 10px; background-color: #ddd; text-shadow: 1px 1px 0 white } div.sphinxsidebar h4{ font-size: 1.1em; } div.sphinxsidebar h3 a { color: #444; } div.sphinxsidebar p { color: #888; padding: 5px 20px; } div.sphinxsidebar p.topless { } div.sphinxsidebar ul { margin: 10px 20px; padding: 0; color: #000; } div.sphinxsidebar a { color: #444; } div.sphinxsidebar input { border: 1px solid #ccc; font-family: sans-serif; font-size: 1em; } div.sphinxsidebar input[type=text]{ margin-left: 20px; } /* -- body styles ----------------------------------------------------------- */ a { color: #005B81; text-decoration: none; } a:hover { color: #E32E00; text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: Arial, sans-serif; background-color: #BED4EB; font-weight: normal; color: #212224; margin: 30px 0px 10px 0px; padding: 5px 0 5px 10px; text-shadow: 0px 1px 0 white } div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } div.body h2 { font-size: 150%; background-color: #C8D5E3; } div.body h3 { font-size: 120%; background-color: #D8DEE3; } div.body h4 { font-size: 110%; background-color: #D8DEE3; } div.body h5 { font-size: 100%; background-color: #D8DEE3; } div.body h6 { font-size: 100%; background-color: #D8DEE3; } a.headerlink { color: #c60f0f; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } a.headerlink:hover { background-color: #c60f0f; color: white; } div.body p, div.body dd, div.body li { line-height: 1.5em; } div.admonition p.admonition-title + p { display: inline; } div.highlight{ background-color: white; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } div.warning { background-color: #ffe4e4; border: 1px solid #f66; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre { padding: 10px; background-color: White; color: #222; line-height: 1.2em; border: 1px solid #C6C9CB; font-size: 1.1em; margin: 1.5em 0 1.5em 0; -webkit-box-shadow: 1px 1px 1px #d8d8d8; -moz-box-shadow: 1px 1px 1px #d8d8d8; } tt { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ font-size: 1.1em; font-family: monospace; } .viewcode-back { font-family: Arial, sans-serif; } div.viewcode-block:target { background-color: #f4debf; border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; } div.comment { position:absolute; left: -9999px; top: -9999px; } div.comment a.email_link { display: block; width: 16px; height: 16px; cursor: pointer; color: white; text-decoration:none; background: transparent url(./comment_white_yellow.gif) no-repeat -16px 0; } div.comment a.email_link:hover { background-position:0 0; } ================================================ FILE: docs/theme/nature/static/sae.js ================================================ DESELEMENT = "h2,h3,h4"; //"h1,h2,h3,h4,ul,div.section p,div.highlight-python"; function strip_tags(st) { return st.replace(/<[^>]+>?[^<]*>/g, ''); } $(document).ready(function() { $("div.body > div.section").find(DESELEMENT).each(function() { if (!$(this).prev("div.comment").length) { var cmt = $('

'); $(this).before(cmt); cmt.offset({ //left: $(this).parents('.section').offset().left - 10, left: $(this).offset().left - 10, top: $(this).offset().top - 5 }); } }); $("a.email_link").hover(function() { if ($(this).attr("href") == null||$(this).attr("href") == '') { var body = $(this).parent("div.comment").next().html(); body = strip_tags(body).replace(/¶/g, ''); if (body.length > 100) { body = body.substring(0, 100)+"..."; } $(this).attr("href" , "https://github.com/SAEPython/saepythondevguide/issues/new?title={文档}" + encodeURIComponent(body)); $(this).attr("target", "_blank"); } }, function(){ }); }); ================================================ FILE: docs/theme/nature/theme.conf ================================================ [theme] inherit = basic stylesheet = nature.css pygments_style = tango ================================================ FILE: docs/tools.rst ================================================ 相关工具 ============== 代码部署 ------------ SAE Python使用SVN作为部署工具。使用SVN部署代码到SAE需要遵循以下规则: SVN根目录下只允许存在以正整数命名的目录,不允许有文件存在, 这些目录为应用的版本目录,每个版本目录下才可以放应用对应版本的代码。 以应用longtalk为例,这个应用有6个版本: :: jaime@westeros:~/longtalk$ ls 1 2 3 4 5 6 jaime@westeros:~/longtalk/1$ ls index.wsgi myapp.py SVN限制: - 文件名或目录名不允许含有以下字符:",*,?,<,>,|,另外文件或文件名的开始与结束也不允许有空格。 - 上传单个文件大小不超过20M - 单个目录下的文 件个数不能超过2000个 - 每个应用代码总大小不超过100M - 单个版本代码总大小不超过50M .. warning:: 1. 不要使用svn cp,mv,目前还不支持这两个操作。 2. 建议使用命令行工具中的saecloud deploy命令来部署代码。 本地开发环境 -------------- 本地开发环境仅为应用开发便利之用,对sae python环境的模拟并不完全。 安装 ~~~~~~~~~ 直接使用 `pip` 或者 `easy_install` 安装 `sae-python-dev` 包即可。 或者可以选择从github下载源码安装。 :: $ git clone https://github.com/sinacloud/sae-python-dev-guide.git $ cd sae-python-dev-guide/dev_server $ python setup.py install 基本使用 ~~~~~~~~~~ 进入应用的本地开发目录,也就是index.wsgi和config.yaml所在的目录。运行如下的命令启动测试server: :: $ dev_server.py MySQL config not found: app.py Start development server on http://localhost:8080/ 访问 http://localhost:8080 端口就可以访问你的应用了。 使用MySQL服务 ~~~~~~~~~~~~~~ 首先配置好MySQL本地开发server。然后使用 `--mysql` 参数运行dev_server.py。 :: $ dev_server.py --mysql=user:password@host:port 现在你可以在应用代码中像在SAE线上环境一样使用MySQL服务了。 dev_server.py默认使用名为 `app_应用名` 的数据库。 使用storage服务 ~~~~~~~~~~~~~~~~ 使用 `--storage-path` 参数运行dev_server.py。 :: $ dev_server.py --storage-path=/path/to/local/storage/data 本地的storage服务使用以下的目录结构来模拟线上的storage。 :: storage-path/ domain1/ key1 key2 domain2/ domain3/ --storage-path配置的路径下每个子文件夹会映射为storage中的一个domain, 而每个子文件夹下的文件映射为domain下的一个key,其内容为对应key的数据。 .. note:: 为方便调试,dev_server自带的sae.storage在某个domain不存在的情况下会自动创建该domain。 线上环境中的domain需要在sae后台面板中手动创建。 使用pylibmc ~~~~~~~~~~~~~ dev_server自带了一个dummy pylibmc,所以无须安装pylibmc就可以直接使用memcache服务了。 该模块将所有的数据存贮在内存中,dev_server.py进程结束时,所有的数据都会丢失。 使用kvdb ~~~~~~~~~~~~~ kvdb默认数据存在内存中,dev_server.py进程结束时,数据会全部丢失,如果需要保存数据, 请使用如下命令行启动dev_server.py。 :: $ dev_server.py --kvdb-file=/path/to/kvdb/local/file 命令行工具saecloud -------------------- 部署代码 ~~~~~~~~~~ 进入应用目录(也就是config.yaml和index.wsgi所在的目录)。 :: $ cat config.yaml name: memorystone version: 2 $ saecloud deploy saecloud从config.yaml文件获得信息,判断将要把代码部署到哪个应用的哪个版本。上面的命令会将应用部署到memorystone的版本2上。 saecloud deploy命令接受一个可选参数: app代码所在路径,默认为当前目录'.'。 .. note:: 1. 删除应用版本目前仍然只能在前端管理界面中操作。 2. 如果代码量较大,则上传时间较慢,请耐心等待 3. 不推荐混合使用saecloud deploy和svn,虽然saecloud deploy部署之前会自动更新代码,但是如果有代码冲突则会导致本地状态不一致。解决办法为删除本地cache目录: `rm -rf ~/.saecloud` 导出应用代码 ~~~~~~~~~~~~~~ 导出memorystone应用版本2到本地目录: :: $ saecloud export memorystone 2 --username fooxxx@gmail.com --password barxxx Exporting to memorystone 第一个参数为应用名字,第二个参数为版本,可选,默认为版本1。 第一次使用时,请指定你的代码访问帐号信息:username 安全邮箱, password。之后的命令不用在输入此信息。 .. note:: `deploy` 和 `export` 命令需要用到svn,请先安装svn命令行工具。 windows用户可以在这里下载:http://sourceforge.net/projects/win32svn/ .. _howto-use-saecloud-install: 安装依赖的第三方包 ~~~~~~~~~~~~~~~~~~ 在应用目录中执行下面的命令安装依赖的第三方包。 :: saecloud install package [package ... ] 如果应用的依赖关系比较多,也可以这些依赖关系写到依赖文件中,例如: :: Framework==0.9.4 Library>=0.2 假设上面的依赖文件的文件名为requirements.txt,你可以执行下面的命令安装所有的依赖包。 :: saecloud install -r requirements.txt 该命令会安装依赖包到应用目录下名为 `site-packages` 的目录里。如果文件比较多的话,推荐压缩site-packages目录。 :: cd site-packages/ zip -r ../site-packages.zip . 修改index.wsgi文件,在导入其它模块之前,将 `site-packages` 目录或者 `site-packages.zip` 添加到module的搜索路径中。 :: import os import sys root = os.path.dirname(__file__) # 两者取其一 sys.path.insert(0, os.path.join(root, 'site-packages')) sys.path.insert(0, os.path.join(root, 'site-packages.zip')) 这样就可以在应用中使用这些依赖包了。 .. tip:: 安装指定版本的package:saecloud install package==version .. _cloudsql.py: cloudsql.py ------------- cloudsql.py是SAE MySQL服务的一个命令行客户端,用户可以使用cloudsql.py来直接操作应用的线上数据库。 :: alan@sina:~/python$ cloudsql.py -u ACCESSKEY -p SECRETKEY APP_NAME SAE MySQL Client Type "help" or "?" for help. Connecting to Cloud SQL database "app_shellpy" on host w.rdc.sae.sina.com.cn. Using readline for history management. Loading history file "/home/alan/.saecloud/app_shellpy.hist" mysql> 如果想要在代码中直接操作线上的数据库,在 `import MySQLdb` (并不一定要安装MySQLdb包)之前执行以下的代码即可: :: # 只在本地开发环境中执行 import os if 'SERVER_SOFTWARE' not in os.environ: from sae._restful_mysql import monkey monkey.patch() 可用插件 -------------- SAE Python Shell ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SAE Python Shell是一个wsgi中间件,提供了一个在线的interactive shell,便于在线调 试app,查看系统信息等。(由 shellpy_ 修改而来)。 .. _shellpy: http://code.google.com/p/google-app-engine-samples/source/browse/trunk/shell/shell.py .. py:class:: ShellMiddleware(app, password=None) :module: sae.ext.shell app: 你的应用callable password: 可选,登录shell时需要输入的口令,用于保护shell不被非法访问。 使用步骤: - 该插件需要使用 `memcache` 服务,请事先开启。 - 修改index.wsgi,启用shell插件,示例如下:: import sae from sae.ext.shell import ShellMiddleware def app(environ, start_response): status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return ["Hello, world!"] application = sae.create_wsgi_app(ShellMiddleware(app)) - 访问地址 https://.sinaapp.com/_sae/shell ,根据提示输入你设置的口令 - 或者你也可以在命令行下面使用 `saecloud shell [-p PASSWORD]` 来访问在线shell。 :: alan@sina:~/shellpy$ saecloud shell pylabs -proot Python 2.7.3 (default, Mar 27 2013, 18:11:21) [GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] Type "help", "copyright", "credits" or "license" for more information. >>> .. warning:: 测试期间请谨慎使用,建议不使用时从源码中注释掉此shell。 ================================================ FILE: examples/apibus/apibus_handler.py ================================================ #-*-coding: utf8 -*- """ SAE API auth handler for urllib2 and requests urllib2: >>> import urllib2 >>> apibus_handler = SaeApibusAuthHandler(ACCESSKEY, SECRETKEY) >>> opener = urllib2.build_opener(apibus_handler) >>> print opener.open('http://g.sae.sina.com.cn/log/http/2015-06-18/1-access.log').read() requests: >>> import requests >>> print requests.get('http://g.sae.sina.com.cn/log/http/2015-06-18/1-access.log?head/0/10|fields/ /1/2/3/4', auth=SaeApibusAuth(ACCESSKEY, SECRETKEY)).content """ import hmac import base64 import hashlib import time import urllib from urllib2 import BaseHandler, Request _APIBUS_URL_PREFIX = 'http://g.sae.sina.com.cn/' class SaeApibusAuthHandler(BaseHandler): # apibus handler must be in front handler_order = 100 def __init__(self, accesskey, secretkey): self.accesskey = accesskey self.secretkey = secretkey def http_request(self, req): orig_url = req.get_full_url() if not orig_url.startswith(_APIBUS_URL_PREFIX): return req timestamp = str(int(time.time())) headers = [ ('x-sae-timestamp', timestamp), ('x-sae-accesskey', self.accesskey), ] req.headers.update(headers) method = req.get_method() resource = urllib.unquote(req.get_full_url()[len(_APIBUS_URL_PREFIX)-1:]) sae_headers = [(k.lower(), v.lower()) for k, v in req.headers.items() if k.lower().startswith('x-sae-')] req.add_header('Authorization', _signature(self.secretkey, method, resource, sae_headers)) return req https_request = http_request try: from requests.auth import AuthBase class SaeApibusAuth(AuthBase): """Attaches HTTP Basic Authentication to the given Request object.""" def __init__(self, accesskey, secretkey): self.accesskey = accesskey self.secretkey = secretkey def __call__(self, r): timestamp = str(int(time.time())) r.headers['x-sae-timestamp'] = timestamp r.headers['x-sae-accesskey'] = self.accesskey resource = urllib.unquote(r.url[len(_APIBUS_URL_PREFIX)-1:]) #resource = r.url[len(_APIBUS_URL_PREFIX)-1:] sae_headers = [(k.lower(), v.lower()) for k, v in r.headers.items() if k.lower().startswith('x-sae-')] r.headers['Authorization'] = _signature(self.secretkey, r.method, resource, sae_headers) return r except ImportError: # requests was not present! pass def _signature(secret, method, resource, headers): msgToSign = "\n".join([ method, resource, "\n".join([(k + ":" + v) for k, v in sorted(headers)]), ]) return "SAEV1_HMAC_SHA256 " + base64.b64encode(hmac.new(secret, msgToSign, hashlib.sha256).digest()) ================================================ FILE: examples/bottle/README ================================================ Hello, Bottle! ================================================ FILE: examples/bottle/index.wsgi ================================================ from bottle import Bottle, run import sae app = Bottle() @app.route('/') def hello(): return "Hello, world! - Bottle" application = sae.create_wsgi_app(app) ================================================ FILE: examples/django/1.2.7/README ================================================ Hello, Django! ================================================ FILE: examples/django/1.2.7/config.yaml ================================================ name: pylabs version: 9 ================================================ FILE: examples/django/1.2.7/index.wsgi ================================================ import sys import os.path # manage.py is automatically created in each Django project. manage.py is a thin # wrapper around django-admin.py that takes care of two things for you before # delegating to django-admin.py: # # It puts your project's package on sys.path. # It sets the DJANGO_SETTINGS_MODULE environment variable so that it points to # your project's settings.py file. # # ref: https://docs.djangoproject.com/en/1.4/ref/django-admin/ os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' sys.path.append(os.path.join(os.path.dirname(__file__), 'mysite')) import sae import django.core.handlers.wsgi application = sae.create_wsgi_app(django.core.handlers.wsgi.WSGIHandler()) ================================================ FILE: examples/django/1.2.7/mysite/__init__.py ================================================ ================================================ FILE: examples/django/1.2.7/mysite/demo/__init__.py ================================================ ================================================ FILE: examples/django/1.2.7/mysite/demo/models.py ================================================ from django.db import models # Create your models here. class Demo(models.Model): text = models.CharField(max_length=256) ================================================ FILE: examples/django/1.2.7/mysite/demo/tests.py ================================================ """ This file demonstrates two different styles of tests (one doctest and one unittest). These will both pass when you run "manage.py test". Replace these with more appropriate tests for your application. """ from django.test import TestCase class SimpleTest(TestCase): def test_basic_addition(self): """ Tests that 1 + 1 always equals 2. """ self.failUnlessEqual(1 + 1, 2) __test__ = {"doctest": """ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} ================================================ FILE: examples/django/1.2.7/mysite/demo/views.py ================================================ # Create your views here. from django.http import HttpResponse from django.template import Template, Context from django.core.context_processors import csrf from demo.models import Demo def showdemo(request): if request.method == 'POST': d = Demo(text=request.POST.get('text', '')) d.save() messages = Demo.objects.all() t = Template(""" {{ xxxx }} {% for m in messages %}

{{ m.text }}

{% endfor %}
{% csrf_token %}
"""); d = {'messages': messages} d.update(csrf(request)) return HttpResponse(t.render(Context(d))) ================================================ FILE: examples/django/1.2.7/mysite/manage.py ================================================ #!/usr/bin/env python from django.core.management import execute_manager try: import settings # Assumed to be in the same directory. except ImportError: import sys sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) sys.exit(1) if __name__ == "__main__": execute_manager(settings) ================================================ FILE: examples/django/1.2.7/mysite/settings.py ================================================ # Django settings for mysite project. DEBUG = True TEMPLATE_DEBUG = DEBUG ADMINS = ( # ('Your Name', 'your_email@domain.com'), ) MANAGERS = ADMINS from sae.const import (MYSQL_HOST, MYSQL_HOST_S, MYSQL_PORT, MYSQL_USER, MYSQL_PASS, MYSQL_DB ) DATABASES = { 'default': { 'ENGINE': 'mysql', 'NAME': MYSQL_DB, 'USER': MYSQL_USER, 'PASSWORD': MYSQL_PASS, 'HOST': MYSQL_HOST, 'PORT': MYSQL_PORT, } } # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # although not all choices may be available on all operating systems. # On Unix systems, a value of None will cause Django to use the same # timezone as the operating system. # If running in a Windows environment this must be set to the same as your # system time zone. TIME_ZONE = 'America/Chicago' # Language code for this installation. All choices can be found here: # http://www.i18nguy.com/unicode/language-identifiers.html LANGUAGE_CODE = 'en-us' SITE_ID = 1 # If you set this to False, Django will make some optimizations so as not # to load the internationalization machinery. USE_I18N = True # If you set this to False, Django will not format dates, numbers and # calendars according to the current locale USE_L10N = True # Absolute filesystem path to the directory that will hold user-uploaded files. # Example: "/home/media/media.lawrence.com/" MEDIA_ROOT = '' # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash if there is a path component (optional in other cases). # Examples: "http://media.lawrence.com", "http://example.com/media/" MEDIA_URL = '' # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a # trailing slash. # Examples: "http://foo.com/media/", "/media/". ADMIN_MEDIA_PREFIX = '/static/' # Make this unique, and don't share it with anybody. SECRET_KEY = 'xr45ymz8fs5wn*039+l462qwg7)7_yg$u7g6osv*3pynsr3#0#' # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', # 'django.template.loaders.eggs.Loader', ) MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', ) ROOT_URLCONF = 'mysite.urls' TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ) INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'mysite.demo', # Uncomment the next line to enable the admin: 'django.contrib.admin', # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', ) ================================================ FILE: examples/django/1.2.7/mysite/urls.py ================================================ from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', # Example: # (r'^mysite/', include('mysite.foo.urls')), (r'^$', 'mysite.views.hello'), (r'^demo/$', 'mysite.demo.views.showdemo'), # Uncomment the admin/doc line below to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: (r'^admin/', include(admin.site.urls)), ) ================================================ FILE: examples/django/1.2.7/mysite/views.py ================================================ from django.http import HttpResponse def hello(request): return HttpResponse("Hello, world! - Django") ================================================ FILE: examples/django/1.2.7/static/css/base.css ================================================ /* DJANGO Admin styles */ body { margin: 0; padding: 0; font-size: 12px; font-family: "Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif; color: #333; background: #fff; } /* LINKS */ a:link, a:visited { color: #5b80b2; text-decoration: none; } a:hover { color: #036; } a img { border: none; } a.section:link, a.section:visited { color: white; text-decoration: none; } /* GLOBAL DEFAULTS */ p, ol, ul, dl { margin: .2em 0 .8em 0; } p { padding: 0; line-height: 140%; } h1,h2,h3,h4,h5 { font-weight: bold; } h1 { font-size: 18px; color: #666; padding: 0 6px 0 0; margin: 0 0 .2em 0; } h2 { font-size: 16px; margin: 1em 0 .5em 0; } h2.subhead { font-weight: normal; margin-top: 0; } h3 { font-size: 14px; margin: .8em 0 .3em 0; color: #666; font-weight: bold; } h4 { font-size: 12px; margin: 1em 0 .8em 0; padding-bottom: 3px; } h5 { font-size: 10px; margin: 1.5em 0 .5em 0; color: #666; text-transform: uppercase; letter-spacing: 1px; } ul li { list-style-type: square; padding: 1px 0; } ul.plainlist { margin-left: 0 !important; } ul.plainlist li { list-style-type: none; } li ul { margin-bottom: 0; } li, dt, dd { font-size: 11px; line-height: 14px; } dt { font-weight: bold; margin-top: 4px; } dd { margin-left: 0; } form { margin: 0; padding: 0; } fieldset { margin: 0; padding: 0; } blockquote { font-size: 11px; color: #777; margin-left: 2px; padding-left: 10px; border-left: 5px solid #ddd; } code, pre { font-family: "Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; background: inherit; color: #666; font-size: 11px; } pre.literal-block { margin: 10px; background: #eee; padding: 6px 8px; } code strong { color: #930; } hr { clear: both; color: #eee; background-color: #eee; height: 1px; border: none; margin: 0; padding: 0; font-size: 1px; line-height: 1px; } /* TEXT STYLES & MODIFIERS */ .small { font-size: 11px; } .tiny { font-size: 10px; } p.tiny { margin-top: -2px; } .mini { font-size: 9px; } p.mini { margin-top: -3px; } .help, p.help { font-size: 10px !important; color: #999; } p img, h1 img, h2 img, h3 img, h4 img, td img { vertical-align: middle; } .quiet, a.quiet:link, a.quiet:visited { color: #999 !important; font-weight: normal !important; } .quiet strong { font-weight: bold !important; } .float-right { float: right; } .float-left { float: left; } .clear { clear: both; } .align-left { text-align: left; } .align-right { text-align: right; } .example { margin: 10px 0; padding: 5px 10px; background: #efefef; } .nowrap { white-space: nowrap; } /* TABLES */ table { border-collapse: collapse; border-color: #ccc; } td, th { font-size: 11px; line-height: 13px; border-bottom: 1px solid #eee; vertical-align: top; padding: 5px; font-family: "Lucida Grande", Verdana, Arial, sans-serif; } th { text-align: left; font-size: 12px; font-weight: bold; } thead th, tfoot td { color: #666; padding: 2px 5px; font-size: 11px; background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; border-left: 1px solid #ddd; border-bottom: 1px solid #ddd; } tfoot td { border-bottom: none; border-top: 1px solid #ddd; } thead th:first-child, tfoot td:first-child { border-left: none !important; } thead th.optional { font-weight: normal !important; } fieldset table { border-right: 1px solid #eee; } tr.row-label td { font-size: 9px; padding-top: 2px; padding-bottom: 0; border-bottom: none; color: #666; margin-top: -1px; } tr.alt { background: #f6f6f6; } .row1 { background: #EDF3FE; } .row2 { background: white; } /* SORTABLE TABLES */ thead th a:link, thead th a:visited { color: #666; display: block; } table thead th.sorted { background-position: bottom left !important; } table thead th.sorted a { padding-right: 13px; } table thead th.ascending a { background: url(../img/admin/arrow-up.gif) right .4em no-repeat; } table thead th.descending a { background: url(../img/admin/arrow-down.gif) right .4em no-repeat; } /* ORDERABLE TABLES */ table.orderable tbody tr td:hover { cursor: move; } table.orderable tbody tr td:first-child { padding-left: 14px; background-image: url(../img/admin/nav-bg-grabber.gif); background-repeat: repeat-y; } table.orderable-initalized .order-cell, body>tr>td.order-cell { display: none; } /* FORM DEFAULTS */ input, textarea, select, .form-row p { margin: 2px 0; padding: 2px 3px; vertical-align: middle; font-family: "Lucida Grande", Verdana, Arial, sans-serif; font-weight: normal; font-size: 11px; } textarea { vertical-align: top !important; } input[type=text], input[type=password], textarea, select, .vTextField { border: 1px solid #ccc; } /* FORM BUTTONS */ .button, input[type=submit], input[type=button], .submit-row input { background: white url(../img/admin/nav-bg.gif) bottom repeat-x; padding: 3px 5px; color: black; border: 1px solid #bbb; border-color: #ddd #aaa #aaa #ddd; } .button:active, input[type=submit]:active, input[type=button]:active { background-image: url(../img/admin/nav-bg-reverse.gif); background-position: top; } .button.default, input[type=submit].default, .submit-row input.default { border: 2px solid #5b80b2; background: #7CA0C7 url(../img/admin/default-bg.gif) bottom repeat-x; font-weight: bold; color: white; float: right; } .button.default:active, input[type=submit].default:active { background-image: url(../img/admin/default-bg-reverse.gif); background-position: top; } /* MODULES */ .module { border: 1px solid #ccc; margin-bottom: 5px; background: white; } .module p, .module ul, .module h3, .module h4, .module dl, .module pre { padding-left: 10px; padding-right: 10px; } .module blockquote { margin-left: 12px; } .module ul, .module ol { margin-left: 1.5em; } .module h3 { margin-top: .6em; } .module h2, .module caption, .inline-group h2 { margin: 0; padding: 2px 5px 3px 5px; font-size: 11px; text-align: left; font-weight: bold; background: #7CA0C7 url(../img/admin/default-bg.gif) top left repeat-x; color: white; } .module table { border-collapse: collapse; } /* MESSAGES & ERRORS */ ul.messagelist { padding: 0 0 5px 0; margin: 0; } ul.messagelist li { font-size: 12px; display: block; padding: 4px 5px 4px 25px; margin: 0 0 3px 0; border-bottom: 1px solid #ddd; color: #666; background: #ffc url(../img/admin/icon_success.gif) 5px .3em no-repeat; } ul.messagelist li.warning{ background-image: url(../img/admin/icon_alert.gif); } ul.messagelist li.error{ background-image: url(../img/admin/icon_error.gif); } .errornote { font-size: 12px !important; display: block; padding: 4px 5px 4px 25px; margin: 0 0 3px 0; border: 1px solid red; color: red; background: #ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat; } ul.errorlist { margin: 0 !important; padding: 0 !important; } .errorlist li { font-size: 12px !important; display: block; padding: 4px 5px 4px 25px; margin: 0 0 3px 0; border: 1px solid red; color: white; background: red url(../img/admin/icon_alert.gif) 5px .3em no-repeat; } .errorlist li a { color: white; text-decoration: underline; } td ul.errorlist { margin: 0 !important; padding: 0 !important; } td ul.errorlist li { margin: 0 !important; } .errors { background: #ffc; } .errors input, .errors select, .errors textarea { border: 1px solid red; } div.system-message { background: #ffc; margin: 10px; padding: 6px 8px; font-size: .8em; } div.system-message p.system-message-title { padding: 4px 5px 4px 25px; margin: 0; color: red; background: #ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat; } .description { font-size: 12px; padding: 5px 0 0 12px; } /* BREADCRUMBS */ div.breadcrumbs { background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; padding: 2px 8px 3px 8px; font-size: 11px; color: #999; border-top: 1px solid white; border-bottom: 1px solid #ccc; text-align: left; } /* ACTION ICONS */ .addlink { padding-left: 12px; background: url(../img/admin/icon_addlink.gif) 0 .2em no-repeat; } .changelink { padding-left: 12px; background: url(../img/admin/icon_changelink.gif) 0 .2em no-repeat; } .deletelink { padding-left: 12px; background: url(../img/admin/icon_deletelink.gif) 0 .25em no-repeat; } a.deletelink:link, a.deletelink:visited { color: #CC3434; } a.deletelink:hover { color: #993333; } /* OBJECT TOOLS */ .object-tools { font-size: 10px; font-weight: bold; font-family: Arial,Helvetica,sans-serif; padding-left: 0; float: right; position: relative; margin-top: -2.4em; margin-bottom: -2em; } .form-row .object-tools { margin-top: 5px; margin-bottom: 5px; float: none; height: 2em; padding-left: 3.5em; } .object-tools li { display: block; float: left; background: url(../img/admin/tool-left.gif) 0 0 no-repeat; padding: 0 0 0 8px; margin-left: 2px; height: 16px; } .object-tools li:hover { background: url(../img/admin/tool-left_over.gif) 0 0 no-repeat; } .object-tools a:link, .object-tools a:visited { display: block; float: left; color: white; padding: .1em 14px .1em 8px; height: 14px; background: #999 url(../img/admin/tool-right.gif) 100% 0 no-repeat; } .object-tools a:hover, .object-tools li:hover a { background: #5b80b2 url(../img/admin/tool-right_over.gif) 100% 0 no-repeat; } .object-tools a.viewsitelink, .object-tools a.golink { background: #999 url(../img/admin/tooltag-arrowright.gif) top right no-repeat; padding-right: 28px; } .object-tools a.viewsitelink:hover, .object-tools a.golink:hover { background: #5b80b2 url(../img/admin/tooltag-arrowright_over.gif) top right no-repeat; } .object-tools a.addlink { background: #999 url(../img/admin/tooltag-add.gif) top right no-repeat; padding-right: 28px; } .object-tools a.addlink:hover { background: #5b80b2 url(../img/admin/tooltag-add_over.gif) top right no-repeat; } /* OBJECT HISTORY */ table#change-history { width: 100%; } table#change-history tbody th { width: 16em; } /* PAGE STRUCTURE */ #container { position: relative; width: 100%; min-width: 760px; padding: 0; } #content { margin: 10px 15px; } #header { width: 100%; } #content-main { float: left; width: 100%; } #content-related { float: right; width: 18em; position: relative; margin-right: -19em; } #footer { clear: both; padding: 10px; } /* COLUMN TYPES */ .colMS { margin-right: 20em !important; } .colSM { margin-left: 20em !important; } .colSM #content-related { float: left; margin-right: 0; margin-left: -19em; } .colSM #content-main { float: right; } .popup .colM { width: 95%; } .subcol { float: left; width: 46%; margin-right: 15px; } .dashboard #content { width: 500px; } /* HEADER */ #header { background: #417690; color: #ffc; overflow: hidden; } #header a:link, #header a:visited { color: white; } #header a:hover { text-decoration: underline; } #branding h1 { padding: 0 10px; font-size: 18px; margin: 8px 0; font-weight: normal; color: #f4f379; } #branding h2 { padding: 0 10px; font-size: 14px; margin: -8px 0 8px 0; font-weight: normal; color: #ffc; } #user-tools { position: absolute; top: 0; right: 0; padding: 1.2em 10px; font-size: 11px; text-align: right; } /* SIDEBAR */ #content-related h3 { font-size: 12px; color: #666; margin-bottom: 3px; } #content-related h4 { font-size: 11px; } #content-related .module h2 { background: #eee url(../img/admin/nav-bg.gif) bottom left repeat-x; color: #666; } ================================================ FILE: examples/django/1.2.7/static/css/changelists.css ================================================ /* CHANGELISTS */ #changelist { position: relative; width: 100%; } #changelist table { width: 100%; } .change-list .hiddenfields { display:none; } .change-list .filtered table { border-right: 1px solid #ddd; } .change-list .filtered { min-height: 400px; } .change-list .filtered { background: white url(../img/admin/changelist-bg.gif) top right repeat-y !important; } .change-list .filtered table, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { margin-right: 160px !important; width: auto !important; } .change-list .filtered table tbody th { padding-right: 1em; } #changelist .toplinks { border-bottom: 1px solid #ccc !important; } #changelist .paginator { color: #666; border-top: 1px solid #eee; border-bottom: 1px solid #eee; background: white url(../img/admin/nav-bg.gif) 0 180% repeat-x; overflow: hidden; } .change-list .filtered .paginator { border-right: 1px solid #ddd; } /* CHANGELIST TABLES */ #changelist table thead th { white-space: nowrap; vertical-align: middle; } #changelist table thead th.action-checkbox-column { width: 1.5em; text-align: center; } #changelist table tbody td, #changelist table tbody th { border-left: 1px solid #ddd; } #changelist table tbody td:first-child, #changelist table tbody th:first-child { border-left: 0; border-right: 1px solid #ddd; } #changelist table tbody td.action-checkbox { text-align:center; } #changelist table tfoot { color: #666; } /* TOOLBAR */ #changelist #toolbar { padding: 3px; border-bottom: 1px solid #ddd; background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; color: #666; } #changelist #toolbar form input { font-size: 11px; padding: 1px 2px; } #changelist #toolbar form #searchbar { padding: 2px; } #changelist #changelist-search img { vertical-align: middle; } /* FILTER COLUMN */ #changelist-filter { position: absolute; top: 0; right: 0; z-index: 1000; width: 160px; border-left: 1px solid #ddd; background: #efefef; margin: 0; } #changelist-filter h2 { font-size: 11px; padding: 2px 5px; border-bottom: 1px solid #ddd; } #changelist-filter h3 { font-size: 12px; margin-bottom: 0; } #changelist-filter ul { padding-left: 0; margin-left: 10px; } #changelist-filter li { list-style-type: none; margin-left: 0; padding-left: 0; } #changelist-filter a { color: #999; } #changelist-filter a:hover { color: #036; } #changelist-filter li.selected { border-left: 5px solid #ccc; padding-left: 5px; margin-left: -10px; } #changelist-filter li.selected a { color: #5b80b2 !important; } /* DATE DRILLDOWN */ .change-list ul.toplinks { display: block; background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; border-top: 1px solid white; float: left; padding: 0 !important; margin: 0 !important; width: 100%; } .change-list ul.toplinks li { float: left; width: 9em; padding: 3px 6px; font-weight: bold; list-style-type: none; } .change-list ul.toplinks .date-back a { color: #999; } .change-list ul.toplinks .date-back a:hover { color: #036; } /* PAGINATOR */ .paginator { font-size: 11px; padding-top: 10px; padding-bottom: 10px; line-height: 22px; margin: 0; border-top: 1px solid #ddd; } .paginator a:link, .paginator a:visited { padding: 2px 6px; border: solid 1px #ccc; background: white; text-decoration: none; } .paginator a.showall { padding: 0 !important; border: none !important; } .paginator a.showall:hover { color: #036 !important; background: transparent !important; } .paginator .end { border-width: 2px !important; margin-right: 6px; } .paginator .this-page { padding: 2px 6px; font-weight: bold; font-size: 13px; vertical-align: top; } .paginator a:hover { color: white; background: #5b80b2; border-color: #036; } /* ACTIONS */ .filtered .actions { margin-right: 160px !important; border-right: 1px solid #ddd; } #changelist table input { margin: 0; } #changelist table tbody tr.selected { background-color: #FFFFCC; } #changelist .actions { color: #999; padding: 3px; border-top: 1px solid #fff; border-bottom: 1px solid #ddd; background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; } #changelist .actions.selected { background: #fffccf; border-top: 1px solid #fffee8; border-bottom: 1px solid #edecd6; } #changelist .actions span.all, #changelist .actions span.action-counter, #changelist .actions span.clear, #changelist .actions span.question { font-size: 11px; margin: 0 0.5em; display: none; } #changelist .actions:last-child { border-bottom: none; } #changelist .actions select { border: 1px solid #aaa; margin-left: 0.5em; padding: 1px 2px; } #changelist .actions label { font-size: 11px; margin-left: 0.5em; } #changelist #action-toggle { display: none; } #changelist .actions .button { font-size: 11px; padding: 1px 2px; } ================================================ FILE: examples/django/1.2.7/static/css/dashboard.css ================================================ /* DASHBOARD */ .dashboard .module table th { width: 100%; } .dashboard .module table td { white-space: nowrap; } .dashboard .module table td a { display: block; padding-right: .6em; } /* RECENT ACTIONS MODULE */ .module ul.actionlist { margin-left: 0; } ul.actionlist li { list-style-type: none; } ================================================ FILE: examples/django/1.2.7/static/css/forms.css ================================================ @import url('widgets.css'); /* FORM ROWS */ .form-row { overflow: hidden; padding: 8px 12px; font-size: 11px; border-bottom: 1px solid #eee; } .form-row img, .form-row input { vertical-align: middle; } form .form-row p { padding-left: 0; font-size: 11px; } /* FORM LABELS */ form h4 { margin: 0 !important; padding: 0 !important; border: none !important; } label { font-weight: normal !important; color: #666; font-size: 12px; } .required label, label.required { font-weight: bold !important; color: #333 !important; } /* RADIO BUTTONS */ form ul.radiolist li { list-style-type: none; } form ul.radiolist label { float: none; display: inline; } form ul.inline { margin-left: 0; padding: 0; } form ul.inline li { float: left; padding-right: 7px; } /* ALIGNED FIELDSETS */ .aligned label { display: block; padding: 3px 10px 0 0; float: left; width: 8em; } .aligned ul label { display: inline; float: none; width: auto; } .colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { width: 350px; } form .aligned p, form .aligned ul { margin-left: 7em; padding-left: 30px; } form .aligned table p { margin-left: 0; padding-left: 0; } form .aligned p.help { padding-left: 38px; } .aligned .vCheckboxLabel { float: none !important; display: inline; padding-left: 4px; } .colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField { width: 610px; } .checkbox-row p.help { margin-left: 0; padding-left: 0 !important; } fieldset .field-box { float: left; margin-right: 20px; } /* WIDE FIELDSETS */ .wide label { width: 15em !important; } form .wide p { margin-left: 15em; } form .wide p.help { padding-left: 38px; } .colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { width: 450px; } /* COLLAPSED FIELDSETS */ fieldset.collapsed * { display: none; } fieldset.collapsed h2, fieldset.collapsed { display: block !important; } fieldset.collapsed h2 { background-image: url(../img/admin/nav-bg.gif); background-position: bottom left; color: #999; } fieldset.collapsed .collapse-toggle { background: transparent; display: inline !important; } /* MONOSPACE TEXTAREAS */ fieldset.monospace textarea { font-family: "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace; } /* SUBMIT ROW */ .submit-row { padding: 5px 7px; text-align: right; background: white url(../img/admin/nav-bg.gif) 0 100% repeat-x; border: 1px solid #ccc; margin: 5px 0; overflow: hidden; } .submit-row input { margin: 0 0 0 5px; } .submit-row p { margin: 0.3em; } .submit-row p.deletelink-box { float: left; } .submit-row .deletelink { background: url(../img/admin/icon_deletelink.gif) 0 50% no-repeat; padding-left: 14px; } /* CUSTOM FORM FIELDS */ .vSelectMultipleField { vertical-align: top !important; } .vCheckboxField { border: none; } .vDateField, .vTimeField { margin-right: 2px; } .vURLField { width: 30em; } .vLargeTextField, .vXMLLargeTextField { width: 48em; } .flatpages-flatpage #id_content { height: 40.2em; } .module table .vPositiveSmallIntegerField { width: 2.2em; } .vTextField { width: 20em; } .vIntegerField { width: 5em; } .vForeignKeyRawIdAdminField { width: 5em; } /* INLINES */ .inline-group { padding: 0; border: 1px solid #ccc; margin: 10px 0; } .inline-group .aligned label { width: 8em; } .inline-related { position: relative; } .inline-related h3 { margin: 0; color: #666; padding: 3px 5px; font-size: 11px; background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; border-bottom: 1px solid #ddd; } .inline-related h3 span.delete { float: right; } .inline-related h3 span.delete label { margin-left: 2px; font-size: 11px; } .inline-related fieldset { margin: 0; background: #fff; border: none; } .inline-related fieldset.module h3 { margin: 0; padding: 2px 5px 3px 5px; font-size: 11px; text-align: left; font-weight: bold; background: #bcd; color: #fff; } .inline-group .tabular fieldset.module { border: none; border-bottom: 1px solid #ddd; } .inline-related.tabular fieldset.module table { width: 100%; } .last-related fieldset { border: none; } .inline-group .tabular tr.has_original td { padding-top: 2em; } .inline-group .tabular tr td.original { padding: 2px 0 0 0; width: 0; _position: relative; } .inline-group .tabular th.original { width: 0px; padding: 0; } .inline-group .tabular td.original p { position: absolute; left: 0; height: 1.1em; padding: 2px 7px; overflow: hidden; font-size: 9px; font-weight: bold; color: #666; _width: 700px; } .inline-group ul.tools { padding: 0; margin: 0; list-style: none; } .inline-group ul.tools li { display: inline; padding: 0 5px; } .inline-group div.add-row, .inline-group .tabular tr.add-row td { color: #666; padding: 3px 5px; border-bottom: 1px solid #ddd; background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; } .inline-group .tabular tr.add-row td { padding: 4px 5px 3px; border-bottom: none; } .inline-group ul.tools a.add, .inline-group div.add-row a, .inline-group .tabular tr.add-row td a { background: url(../img/admin/icon_addlink.gif) 0 50% no-repeat; padding-left: 14px; font-size: 11px; outline: 0; /* Remove dotted border around link */ } .empty-form { display: none; } ================================================ FILE: examples/django/1.2.7/static/css/ie.css ================================================ /* IE 6 & 7 */ /* Proper fixed width for dashboard in IE6 */ .dashboard #content { *width: 768px; } .dashboard #content-main { *width: 535px; } /* IE 6 ONLY */ /* Keep header from flowing off the page */ #container { _position: static; } /* Put the right sidebars back on the page */ .colMS #content-related { _margin-right: 0; _margin-left: 10px; _position: static; } /* Put the left sidebars back on the page */ .colSM #content-related { _margin-right: 10px; _margin-left: -115px; _position: static; } .form-row { _height: 1%; } /* Fix right margin for changelist filters in IE6 */ #changelist-filter ul { _margin-right: -10px; } /* IE ignores min-height, but treats height as if it were min-height */ .change-list .filtered { _height: 400px; } /* IE doesn't know alpha transparency in PNGs */ .inline-deletelink { background: transparent url(../img/admin/inline-delete-8bit.png) no-repeat; } ================================================ FILE: examples/django/1.2.7/static/css/login.css ================================================ /* LOGIN FORM */ body.login { background: #eee; } .login #container { background: white; border: 1px solid #ccc; width: 28em; min-width: 300px; margin-left: auto; margin-right: auto; margin-top: 100px; } .login #content-main { width: 100%; } .login form { margin-top: 1em; } .login .form-row { padding: 4px 0; float: left; width: 100%; } .login .form-row label { float: left; width: 9em; padding-right: 0.5em; line-height: 2em; text-align: right; font-size: 1em; color: #333; } .login .form-row #id_username, .login .form-row #id_password { width: 14em; } .login span.help { font-size: 10px; display: block; } .login .submit-row { clear: both; padding: 1em 0 0 9.4em; } ================================================ FILE: examples/django/1.2.7/static/css/rtl.css ================================================ body { direction: rtl; } /* LOGIN */ .login .form-row { float: right; } .login .form-row label { float: right; padding-left: 0.5em; padding-right: 0; text-align: left; } .login .submit-row { clear: both; padding: 1em 9.4em 0 0; } /* GLOBAL */ th { text-align: right; } .module h2, .module caption { text-align: right; } .addlink, .changelink { padding-left: 0px; padding-right: 12px; background-position: 100% 0.2em; } .deletelink { padding-left: 0px; padding-right: 12px; background-position: 100% 0.25em; } .object-tools { float: left; } /* LAYOUT */ #user-tools { right: auto; left: 0; text-align: left; } div.breadcrumbs { text-align: right; } #content-main { float: right; } #content-related { float: left; margin-left: -19em; margin-right: auto; } .colMS { margin-left: 20em !important; margin-right: 10px !important; } /* dashboard styles */ .dashboard .module table td a { padding-left: .6em; padding-right: 12px; } /* changelists styles */ .change-list ul.toplinks li { float: right; } .change-list .filtered { background: white url(../img/admin/changelist-bg_rtl.gif) top left repeat-y !important; } .change-list .filtered table { border-left: 1px solid #ddd; border-right: 0px none; } #changelist-filter { right: auto; left: 0; border-left: 0px none; border-right: 1px solid #ddd; } .change-list .filtered table, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { margin-right: 0px !important; margin-left: 160px !important; } #changelist-filter li.selected { border-left: 0px none; padding-left: 0px; margin-left: 0; border-right: 5px solid #ccc; padding-right: 5px; margin-right: -10px; } .filtered .actions { border-left:1px solid #DDDDDD; margin-left:160px !important; border-right: 0 none; margin-right:0 !important; } /* FORMS */ .aligned label { padding: 0 0 3px 1em; float: right; } .submit-row { text-align: left } .submit-row p.deletelink-box { float: right; } .submit-row .deletelink { background: url(../img/admin/icon_deletelink.gif) 0 50% no-repeat; padding-right: 14px; } .vDateField, .vTimeField { margin-left: 2px; } form ul.inline li { float: right; padding-right: 0; padding-left: 7px; } input[type=submit].default, .submit-row input.default { float: left; } fieldset .field-box { float: right; margin-left: 20px; } .errorlist li { background-position: 100% .3em; padding: 4px 25px 4px 5px; } .errornote { background-position: 100% .3em; padding: 4px 25px 4px 5px; } /* WIDGETS */ .calendarnav-previous { top: 0; left: auto; right: 0; } .calendarnav-next { top: 0; right: auto; left: 0; } .calendar caption, .calendarbox h2 { text-align: center; } .selector { float: right; } .selector .selector-filter { text-align: right; } .inline-deletelink { float: left; } /* MISC */ .inline-related h2, .inline-group h2 { text-align: right } .inline-related h3 span.delete { padding-right: 20px; padding-left: inherit; left: 10px; right: inherit; } .inline-related h3 span.delete label { margin-left: inherit; margin-right: 2px; } ================================================ FILE: examples/django/1.2.7/static/css/widgets.css ================================================ /* SELECTOR (FILTER INTERFACE) */ .selector { width: 580px; float: left; } .selector select { width: 270px; height: 17.2em; } .selector-available, .selector-chosen { float: left; width: 270px; text-align: center; margin-bottom: 5px; } .selector-available h2, .selector-chosen h2 { border: 1px solid #ccc; } .selector .selector-available h2 { background: white url(../img/admin/nav-bg.gif) bottom left repeat-x; color: #666; } .selector .selector-filter { background: white; border: 1px solid #ccc; border-width: 0 1px; padding: 3px; color: #999; font-size: 10px; margin: 0; text-align: left; } .selector .selector-chosen .selector-filter { padding: 4px 5px; } .selector .selector-available input { width: 230px; } .selector ul.selector-chooser { float: left; width: 22px; height: 50px; background: url(../img/admin/chooser-bg.gif) top center no-repeat; margin: 8em 3px 0 3px; padding: 0; } .selector-chooser li { margin: 0; padding: 3px; list-style-type: none; } .selector select { margin-bottom: 5px; margin-top: 0; } .selector-add, .selector-remove { width: 16px; height: 16px; display: block; text-indent: -3000px; overflow: hidden; } .selector-add { background: url(../img/admin/selector-add.gif) top center no-repeat; margin-bottom: 2px; } .selector-remove { background: url(../img/admin/selector-remove.gif) top center no-repeat; } a.selector-chooseall, a.selector-clearall { display: block; width: 6em; text-align: left; margin-left: auto; margin-right: auto; font-weight: bold; color: #666; padding: 3px 0 3px 18px; } a.selector-chooseall:hover, a.selector-clearall:hover { color: #036; } a.selector-chooseall { width: 7em; background: url(../img/admin/selector-addall.gif) left center no-repeat; } a.selector-clearall { background: url(../img/admin/selector-removeall.gif) left center no-repeat; } /* STACKED SELECTORS */ .stacked { float: left; width: 500px; } .stacked select { width: 480px; height: 10.1em; } .stacked .selector-available, .stacked .selector-chosen { width: 480px; } .stacked .selector-available { margin-bottom: 0; } .stacked .selector-available input { width: 442px; } .stacked ul.selector-chooser { height: 22px; width: 50px; margin: 0 0 3px 40%; background: url(../img/admin/chooser_stacked-bg.gif) top center no-repeat; } .stacked .selector-chooser li { float: left; padding: 3px 3px 3px 5px; } .stacked .selector-chooseall, .stacked .selector-clearall { display: none; } .stacked .selector-add { background-image: url(../img/admin/selector_stacked-add.gif); } .stacked .selector-remove { background-image: url(../img/admin/selector_stacked-remove.gif); } /* DATE AND TIME */ p.datetime { line-height: 20px; margin: 0; padding: 0; color: #666; font-size: 11px; font-weight: bold; } .datetime span { font-size: 11px; color: #ccc; font-weight: normal; white-space: nowrap; } table p.datetime { font-size: 10px; margin-left: 0; padding-left: 0; } /* FILE UPLOADS */ p.file-upload { line-height: 20px; margin: 0; padding: 0; color: #666; font-size: 11px; font-weight: bold; } .file-upload a { font-weight: normal; } .file-upload .deletelink { margin-left: 5px; } /* CALENDARS & CLOCKS */ .calendarbox, .clockbox { margin: 5px auto; font-size: 11px; width: 16em; text-align: center; background: white; position: relative; } .clockbox { width: auto; } .calendar { margin: 0; padding: 0; } .calendar table { margin: 0; padding: 0; border-collapse: collapse; background: white; width: 99%; } .calendar caption, .calendarbox h2 { margin: 0; font-size: 11px; text-align: center; border-top: none; } .calendar th { font-size: 10px; color: #666; padding: 2px 3px; text-align: center; background: #e1e1e1 url(../img/admin/nav-bg.gif) 0 50% repeat-x; border-bottom: 1px solid #ddd; } .calendar td { font-size: 11px; text-align: center; padding: 0; border-top: 1px solid #eee; border-bottom: none; } .calendar td.selected a { background: #C9DBED; } .calendar td.nonday { background: #efefef; } .calendar td.today a { background: #ffc; } .calendar td a, .timelist a { display: block; font-weight: bold; padding: 4px; text-decoration: none; color: #444; } .calendar td a:hover, .timelist a:hover { background: #5b80b2; color: white; } .calendar td a:active, .timelist a:active { background: #036; color: white; } .calendarnav { font-size: 10px; text-align: center; color: #ccc; margin: 0; padding: 1px 3px; } .calendarnav a:link, #calendarnav a:visited, #calendarnav a:hover { color: #999; } .calendar-shortcuts { background: white; font-size: 10px; line-height: 11px; border-top: 1px solid #eee; padding: 3px 0 4px; color: #ccc; } .calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { display: block; position: absolute; font-weight: bold; font-size: 12px; background: #C9DBED url(../img/admin/default-bg.gif) bottom left repeat-x; padding: 1px 4px 2px 4px; color: white; } .calendarnav-previous:hover, .calendarnav-next:hover { background: #036; } .calendarnav-previous { top: 0; left: 0; } .calendarnav-next { top: 0; right: 0; } .calendar-cancel { margin: 0 !important; padding: 0; font-size: 10px; background: #e1e1e1 url(../img/admin/nav-bg.gif) 0 50% repeat-x; border-top: 1px solid #ddd; } .calendar-cancel a { padding: 2px; color: #999; } ul.timelist, .timelist li { list-style-type: none; margin: 0; padding: 0; } .timelist a { padding: 2px; } /* INLINE ORDERER */ ul.orderer { position: relative; padding: 0 !important; margin: 0 !important; list-style-type: none; } ul.orderer li { list-style-type: none; display: block; padding: 0; margin: 0; border: 1px solid #bbb; border-width: 0 1px 1px 0; white-space: nowrap; overflow: hidden; background: #e2e2e2 url(../img/admin/nav-bg-grabber.gif) repeat-y; } ul.orderer li:hover { cursor: move; background-color: #ddd; } ul.orderer li a.selector { margin-left: 12px; overflow: hidden; width: 83%; font-size: 10px !important; padding: 0.6em 0; } ul.orderer li a:link, ul.orderer li a:visited { color: #333; } ul.orderer li .inline-deletelink { position: absolute; right: 4px; margin-top: 0.6em; } ul.orderer li.selected { background-color: #f8f8f8; border-right-color: #f8f8f8; } ul.orderer li.deleted { background: #bbb url(../img/admin/deleted-overlay.gif); } ul.orderer li.deleted a:link, ul.orderer li.deleted a:visited { color: #888; } ul.orderer li.deleted .inline-deletelink { background-image: url(../img/admin/inline-restore.png); } ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover { cursor: default; } /* EDIT INLINE */ .inline-deletelink { float: right; text-indent: -9999px; background: transparent url(../img/admin/inline-delete.png) no-repeat; width: 15px; height: 15px; border: 0px none; outline: 0; /* Remove dotted border around link */ } .inline-deletelink:hover { background-position: -15px 0; cursor: pointer; } .editinline button.addlink { border: 0px none; color: #5b80b2; font-size: 100%; cursor: pointer; } .editinline button.addlink:hover { color: #036; cursor: pointer; } .editinline table .help { text-align: right; float: right; padding-left: 2em; } .editinline tfoot .addlink { white-space: nowrap; } .editinline table thead th:last-child { border-left: none; } .editinline tr.deleted { background: #ddd url(../img/admin/deleted-overlay.gif); } .editinline tr.deleted .inline-deletelink { background-image: url(../img/admin/inline-restore.png); } .editinline tr.deleted td:hover { cursor: default; } .editinline tr.deleted td:first-child { background-image: none !important; } /* EDIT INLINE - STACKED */ .editinline-stacked { min-width: 758px; } .editinline-stacked .inline-object { margin-left: 210px; background: white; } .editinline-stacked .inline-source { float: left; width: 200px; background: #f8f8f8; } .editinline-stacked .inline-splitter { float: left; width: 9px; background: #f8f8f8 url(../img/admin/inline-splitter-bg.gif) 50% 50% no-repeat; border-right: 1px solid #ccc; } .editinline-stacked .controls { clear: both; background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; padding: 3px 4px; font-size: 11px; border-top: 1px solid #ddd; } ================================================ FILE: examples/django/1.2.7/static/js/SelectBox.js ================================================ var SelectBox = { cache: new Object(), init: function(id) { var box = document.getElementById(id); var node; SelectBox.cache[id] = new Array(); var cache = SelectBox.cache[id]; for (var i = 0; (node = box.options[i]); i++) { cache.push({value: node.value, text: node.text, displayed: 1}); } }, redisplay: function(id) { // Repopulate HTML select box from cache var box = document.getElementById(id); box.options.length = 0; // clear all options for (var i = 0, j = SelectBox.cache[id].length; i < j; i++) { var node = SelectBox.cache[id][i]; if (node.displayed) { box.options[box.options.length] = new Option(node.text, node.value, false, false); } } }, filter: function(id, text) { // Redisplay the HTML select box, displaying only the choices containing ALL // the words in text. (It's an AND search.) var tokens = text.toLowerCase().split(/\s+/); var node, token; for (var i = 0; (node = SelectBox.cache[id][i]); i++) { node.displayed = 1; for (var j = 0; (token = tokens[j]); j++) { if (node.text.toLowerCase().indexOf(token) == -1) { node.displayed = 0; } } } SelectBox.redisplay(id); }, delete_from_cache: function(id, value) { var node, delete_index = null; for (var i = 0; (node = SelectBox.cache[id][i]); i++) { if (node.value == value) { delete_index = i; break; } } var j = SelectBox.cache[id].length - 1; for (var i = delete_index; i < j; i++) { SelectBox.cache[id][i] = SelectBox.cache[id][i+1]; } SelectBox.cache[id].length--; }, add_to_cache: function(id, option) { SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); }, cache_contains: function(id, value) { // Check if an item is contained in the cache var node; for (var i = 0; (node = SelectBox.cache[id][i]); i++) { if (node.value == value) { return true; } } return false; }, move: function(from, to) { var from_box = document.getElementById(from); var to_box = document.getElementById(to); var option; for (var i = 0; (option = from_box.options[i]); i++) { if (option.selected && SelectBox.cache_contains(from, option.value)) { SelectBox.add_to_cache(to, {value: option.value, text: option.text, displayed: 1}); SelectBox.delete_from_cache(from, option.value); } } SelectBox.redisplay(from); SelectBox.redisplay(to); }, move_all: function(from, to) { var from_box = document.getElementById(from); var to_box = document.getElementById(to); var option; for (var i = 0; (option = from_box.options[i]); i++) { if (SelectBox.cache_contains(from, option.value)) { SelectBox.add_to_cache(to, {value: option.value, text: option.text, displayed: 1}); SelectBox.delete_from_cache(from, option.value); } } SelectBox.redisplay(from); SelectBox.redisplay(to); }, sort: function(id) { SelectBox.cache[id].sort( function(a, b) { a = a.text.toLowerCase(); b = b.text.toLowerCase(); try { if (a > b) return 1; if (a < b) return -1; } catch (e) { // silently fail on IE 'unknown' exception } return 0; } ); }, select_all: function(id) { var box = document.getElementById(id); for (var i = 0; i < box.options.length; i++) { box.options[i].selected = 'selected'; } } } ================================================ FILE: examples/django/1.2.7/static/js/SelectFilter2.js ================================================ /* SelectFilter2 - Turns a multiple-select box into a filter interface. Different than SelectFilter because this is coupled to the admin framework. Requires core.js, SelectBox.js and addevent.js. */ function findForm(node) { // returns the node of the form containing the given node if (node.tagName.toLowerCase() != 'form') { return findForm(node.parentNode); } return node; } var SelectFilter = { init: function(field_id, field_name, is_stacked, admin_media_prefix) { if (field_id.match(/__prefix__/)){ // Don't intialize on empty forms. return; } var from_box = document.getElementById(field_id); from_box.id += '_from'; // change its ID from_box.className = 'filtered'; // Remove

, because it just gets in the way. var ps = from_box.parentNode.getElementsByTagName('p'); for (var i=0; i or

var selector_div = quickElement('div', from_box.parentNode); selector_div.className = is_stacked ? 'selector stacked' : 'selector'; //
var selector_available = quickElement('div', selector_div, ''); selector_available.className = 'selector-available'; quickElement('h2', selector_available, interpolate(gettext('Available %s'), [field_name])); var filter_p = quickElement('p', selector_available, ''); filter_p.className = 'selector-filter'; quickElement('img', filter_p, '', 'src', admin_media_prefix + 'img/admin/selector-search.gif'); filter_p.appendChild(document.createTextNode(' ')); var filter_input = quickElement('input', filter_p, '', 'type', 'text'); filter_input.id = field_id + '_input'; selector_available.appendChild(from_box); var choose_all = quickElement('a', selector_available, gettext('Choose all'), 'href', 'javascript: (function(){ SelectBox.move_all("' + field_id + '_from", "' + field_id + '_to"); })()'); choose_all.className = 'selector-chooseall'; //
    var selector_chooser = quickElement('ul', selector_div, ''); selector_chooser.className = 'selector-chooser'; var add_link = quickElement('a', quickElement('li', selector_chooser, ''), gettext('Add'), 'href', 'javascript: (function(){ SelectBox.move("' + field_id + '_from","' + field_id + '_to");})()'); add_link.className = 'selector-add'; var remove_link = quickElement('a', quickElement('li', selector_chooser, ''), gettext('Remove'), 'href', 'javascript: (function(){ SelectBox.move("' + field_id + '_to","' + field_id + '_from");})()'); remove_link.className = 'selector-remove'; //
    var selector_chosen = quickElement('div', selector_div, ''); selector_chosen.className = 'selector-chosen'; quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s'), [field_name])); var selector_filter = quickElement('p', selector_chosen, gettext('Select your choice(s) and click ')); selector_filter.className = 'selector-filter'; quickElement('img', selector_filter, '', 'src', admin_media_prefix + (is_stacked ? 'img/admin/selector_stacked-add.gif':'img/admin/selector-add.gif'), 'alt', 'Add'); var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name')); to_box.className = 'filtered'; var clear_all = quickElement('a', selector_chosen, gettext('Clear all'), 'href', 'javascript: (function() { SelectBox.move_all("' + field_id + '_to", "' + field_id + '_from");})()'); clear_all.className = 'selector-clearall'; from_box.setAttribute('name', from_box.getAttribute('name') + '_old'); // Set up the JavaScript event handlers for the select box filter interface addEvent(filter_input, 'keyup', function(e) { SelectFilter.filter_key_up(e, field_id); }); addEvent(filter_input, 'keydown', function(e) { SelectFilter.filter_key_down(e, field_id); }); addEvent(from_box, 'dblclick', function() { SelectBox.move(field_id + '_from', field_id + '_to'); }); addEvent(to_box, 'dblclick', function() { SelectBox.move(field_id + '_to', field_id + '_from'); }); addEvent(findForm(from_box), 'submit', function() { SelectBox.select_all(field_id + '_to'); }); SelectBox.init(field_id + '_from'); SelectBox.init(field_id + '_to'); // Move selected from_box options to to_box SelectBox.move(field_id + '_from', field_id + '_to'); }, filter_key_up: function(event, field_id) { from = document.getElementById(field_id + '_from'); // don't submit form if user pressed Enter if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) { from.selectedIndex = 0; SelectBox.move(field_id + '_from', field_id + '_to'); from.selectedIndex = 0; return false; } var temp = from.selectedIndex; SelectBox.filter(field_id + '_from', document.getElementById(field_id + '_input').value); from.selectedIndex = temp; return true; }, filter_key_down: function(event, field_id) { from = document.getElementById(field_id + '_from'); // right arrow -- move across if ((event.which && event.which == 39) || (event.keyCode && event.keyCode == 39)) { var old_index = from.selectedIndex; SelectBox.move(field_id + '_from', field_id + '_to'); from.selectedIndex = (old_index == from.length) ? from.length - 1 : old_index; return false; } // down arrow -- wrap around if ((event.which && event.which == 40) || (event.keyCode && event.keyCode == 40)) { from.selectedIndex = (from.length == from.selectedIndex + 1) ? 0 : from.selectedIndex + 1; } // up arrow -- wrap around if ((event.which && event.which == 38) || (event.keyCode && event.keyCode == 38)) { from.selectedIndex = (from.selectedIndex == 0) ? from.length - 1 : from.selectedIndex - 1; } return true; } } ================================================ FILE: examples/django/1.2.7/static/js/actions.js ================================================ (function($) { $.fn.actions = function(opts) { var options = $.extend({}, $.fn.actions.defaults, opts); var actionCheckboxes = $(this); var list_editable_changed = false; checker = function(checked) { if (checked) { showQuestion(); } else { reset(); } $(actionCheckboxes).attr("checked", checked) .parent().parent().toggleClass(options.selectedClass, checked); } updateCounter = function() { var sel = $(actionCheckboxes).filter(":checked").length; $(options.counterContainer).html(interpolate( ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), { sel: sel, cnt: _actions_icnt }, true)); $(options.allToggle).attr("checked", function() { if (sel == actionCheckboxes.length) { value = true; showQuestion(); } else { value = false; clearAcross(); } return value; }); } showQuestion = function() { $(options.acrossClears).hide(); $(options.acrossQuestions).show(); $(options.allContainer).hide(); } showClear = function() { $(options.acrossClears).show(); $(options.acrossQuestions).hide(); $(options.actionContainer).toggleClass(options.selectedClass); $(options.allContainer).show(); $(options.counterContainer).hide(); } reset = function() { $(options.acrossClears).hide(); $(options.acrossQuestions).hide(); $(options.allContainer).hide(); $(options.counterContainer).show(); } clearAcross = function() { reset(); $(options.acrossInput).val(0); $(options.actionContainer).removeClass(options.selectedClass); } // Show counter by default $(options.counterContainer).show(); // Check state of checkboxes and reinit state if needed $(this).filter(":checked").each(function(i) { $(this).parent().parent().toggleClass(options.selectedClass); updateCounter(); if ($(options.acrossInput).val() == 1) { showClear(); } }); $(options.allToggle).show().click(function() { checker($(this).attr("checked")); updateCounter(); }); $("div.actions span.question a").click(function(event) { event.preventDefault(); $(options.acrossInput).val(1); showClear(); }); $("div.actions span.clear a").click(function(event) { event.preventDefault(); $(options.allToggle).attr("checked", false); clearAcross(); checker(0); updateCounter(); }); lastChecked = null; $(actionCheckboxes).click(function(event) { if (!event) { var event = window.event; } var target = event.target ? event.target : event.srcElement; if (lastChecked && $.data(lastChecked) != $.data(target) && event.shiftKey == true) { var inrange = false; $(lastChecked).attr("checked", target.checked) .parent().parent().toggleClass(options.selectedClass, target.checked); $(actionCheckboxes).each(function() { if ($.data(this) == $.data(lastChecked) || $.data(this) == $.data(target)) { inrange = (inrange) ? false : true; } if (inrange) { $(this).attr("checked", target.checked) .parent().parent().toggleClass(options.selectedClass, target.checked); } }); } $(target).parent().parent().toggleClass(options.selectedClass, target.checked); lastChecked = target; updateCounter(); }); $('form#changelist-form table#result_list tr').find('td:gt(0) :input').change(function() { list_editable_changed = true; }); $('form#changelist-form button[name="index"]').click(function(event) { if (list_editable_changed) { return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.")); } }); $('form#changelist-form input[name="_save"]').click(function(event) { var action_changed = false; $('div.actions select option:selected').each(function() { if ($(this).val()) { action_changed = true; } }); if (action_changed) { if (list_editable_changed) { return confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")); } else { return confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button.")); } } }); } /* Setup plugin defaults */ $.fn.actions.defaults = { actionContainer: "div.actions", counterContainer: "span.action-counter", allContainer: "div.actions span.all", acrossInput: "div.actions input.select-across", acrossQuestions: "div.actions span.question", acrossClears: "div.actions span.clear", allToggle: "#action-toggle", selectedClass: "selected" } })(django.jQuery); ================================================ FILE: examples/django/1.2.7/static/js/admin/DateTimeShortcuts.js ================================================ // Inserts shortcut buttons after all of the following: // // var DateTimeShortcuts = { calendars: [], calendarInputs: [], clockInputs: [], calendarDivName1: 'calendarbox', // name of calendar
    that gets toggled calendarDivName2: 'calendarin', // name of
    that contains calendar calendarLinkName: 'calendarlink',// name of the link that is used to toggle clockDivName: 'clockbox', // name of clock
    that gets toggled clockLinkName: 'clocklink', // name of the link that is used to toggle shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts admin_media_prefix: '', init: function() { // Get admin_media_prefix by grabbing it off the window object. It's // set in the admin/base.html template, so if it's not there, someone's // overridden the template. In that case, we'll set a clearly-invalid // value in the hopes that someone will examine HTTP requests and see it. if (window.__admin_media_prefix__ != undefined) { DateTimeShortcuts.admin_media_prefix = window.__admin_media_prefix__; } else { DateTimeShortcuts.admin_media_prefix = '/missing-admin-media-prefix/'; } var inputs = document.getElementsByTagName('input'); for (i=0; i //

    Choose a time

    // //

    Cancel

    //
    var clock_box = document.createElement('div'); clock_box.style.display = 'none'; clock_box.style.position = 'absolute'; clock_box.className = 'clockbox module'; clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num); document.body.appendChild(clock_box); addEvent(clock_box, 'click', DateTimeShortcuts.cancelEventPropagation); quickElement('h2', clock_box, gettext('Choose a time')); time_list = quickElement('ul', clock_box, ''); time_list.className = 'timelist'; time_format = get_format('TIME_INPUT_FORMATS')[0]; quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));"); quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));"); quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));"); quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));"); cancel_p = quickElement('p', clock_box, ''); cancel_p.className = 'calendar-cancel'; quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');'); }, openClock: function(num) { var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num) var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName+num) // Recalculate the clockbox position // is it left-to-right or right-to-left layout ? if (getStyle(document.body,'direction')!='rtl') { clock_box.style.left = findPosX(clock_link) + 17 + 'px'; } else { // since style's width is in em, it'd be tough to calculate // px value of it. let's use an estimated px for now // TODO: IE returns wrong value for findPosX when in rtl mode // (it returns as it was left aligned), needs to be fixed. clock_box.style.left = findPosX(clock_link) - 110 + 'px'; } clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px'; // Show the clock box clock_box.style.display = 'block'; addEvent(window.document, 'click', function() { DateTimeShortcuts.dismissClock(num); return true; }); }, dismissClock: function(num) { document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none'; window.document.onclick = null; }, handleClockQuicklink: function(num, val) { DateTimeShortcuts.clockInputs[num].value = val; DateTimeShortcuts.clockInputs[num].focus(); DateTimeShortcuts.dismissClock(num); }, // Add calendar widget to a given field. addCalendar: function(inp) { var num = DateTimeShortcuts.calendars.length; DateTimeShortcuts.calendarInputs[num] = inp; // Shortcut links (calendar icon and "Today" link) var shortcuts_span = document.createElement('span'); shortcuts_span.className = DateTimeShortcuts.shortCutsClass; inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); var today_link = document.createElement('a'); today_link.setAttribute('href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', 0);'); today_link.appendChild(document.createTextNode(gettext('Today'))); var cal_link = document.createElement('a'); cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');'); cal_link.id = DateTimeShortcuts.calendarLinkName + num; quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_calendar.gif', 'alt', gettext('Calendar')); shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(today_link); shortcuts_span.appendChild(document.createTextNode('\240|\240')); shortcuts_span.appendChild(cal_link); // Create calendarbox div. // // Markup looks like: // //
    //

    // // February 2003 //

    //
    // //
    // //

    Cancel

    //
    var cal_box = document.createElement('div'); cal_box.style.display = 'none'; cal_box.style.position = 'absolute'; cal_box.className = 'calendarbox module'; cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num); document.body.appendChild(cal_box); addEvent(cal_box, 'click', DateTimeShortcuts.cancelEventPropagation); // next-prev links var cal_nav = quickElement('div', cal_box, ''); var cal_nav_prev = quickElement('a', cal_nav, '<', 'href', 'javascript:DateTimeShortcuts.drawPrev('+num+');'); cal_nav_prev.className = 'calendarnav-previous'; var cal_nav_next = quickElement('a', cal_nav, '>', 'href', 'javascript:DateTimeShortcuts.drawNext('+num+');'); cal_nav_next.className = 'calendarnav-next'; // main box var cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num); cal_main.className = 'calendar'; DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num)); DateTimeShortcuts.calendars[num].drawCurrent(); // calendar shortcuts var shortcuts = quickElement('div', cal_box, ''); shortcuts.className = 'calendar-shortcuts'; quickElement('a', shortcuts, gettext('Yesterday'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', -1);'); shortcuts.appendChild(document.createTextNode('\240|\240')); quickElement('a', shortcuts, gettext('Today'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', 0);'); shortcuts.appendChild(document.createTextNode('\240|\240')); quickElement('a', shortcuts, gettext('Tomorrow'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', +1);'); // cancel bar var cancel_p = quickElement('p', cal_box, ''); cancel_p.className = 'calendar-cancel'; quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');'); }, openCalendar: function(num) { var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num) var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num) var inp = DateTimeShortcuts.calendarInputs[num]; // Determine if the current value in the input has a valid date. // If so, draw the calendar with that date's year and month. if (inp.value) { var date_parts = inp.value.split('-'); var year = date_parts[0]; var month = parseFloat(date_parts[1]); if (year.match(/\d\d\d\d/) && month >= 1 && month <= 12) { DateTimeShortcuts.calendars[num].drawDate(month, year); } } // Recalculate the clockbox position // is it left-to-right or right-to-left layout ? if (getStyle(document.body,'direction')!='rtl') { cal_box.style.left = findPosX(cal_link) + 17 + 'px'; } else { // since style's width is in em, it'd be tough to calculate // px value of it. let's use an estimated px for now // TODO: IE returns wrong value for findPosX when in rtl mode // (it returns as it was left aligned), needs to be fixed. cal_box.style.left = findPosX(cal_link) - 180 + 'px'; } cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px'; cal_box.style.display = 'block'; addEvent(window.document, 'click', function() { DateTimeShortcuts.dismissCalendar(num); return true; }); }, dismissCalendar: function(num) { document.getElementById(DateTimeShortcuts.calendarDivName1+num).style.display = 'none'; window.document.onclick = null; }, drawPrev: function(num) { DateTimeShortcuts.calendars[num].drawPreviousMonth(); }, drawNext: function(num) { DateTimeShortcuts.calendars[num].drawNextMonth(); }, handleCalendarCallback: function(num) { format = get_format('DATE_INPUT_FORMATS')[0]; // the format needs to be escaped a little format = format.replace('\\', '\\\\'); format = format.replace('\r', '\\r'); format = format.replace('\n', '\\n'); format = format.replace('\t', '\\t'); format = format.replace("'", "\\'"); return ["function(y, m, d) { DateTimeShortcuts.calendarInputs[", num, "].value = new Date(y, m-1, d).strftime('", format, "');DateTimeShortcuts.calendarInputs[", num, "].focus();document.getElementById(DateTimeShortcuts.calendarDivName1+", num, ").style.display='none';}"].join(''); }, handleCalendarQuickLink: function(num, offset) { var d = new Date(); d.setDate(d.getDate() + offset) DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]); DateTimeShortcuts.calendarInputs[num].focus(); DateTimeShortcuts.dismissCalendar(num); }, cancelEventPropagation: function(e) { if (!e) e = window.event; e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); } } addEvent(window, 'load', DateTimeShortcuts.init); ================================================ FILE: examples/django/1.2.7/static/js/admin/RelatedObjectLookups.js ================================================ // Handles related-objects functionality: lookup link for raw_id_fields // and Add Another links. function html_unescape(text) { // Unescape a string that was escaped using django.utils.html.escape. text = text.replace(/</g, '<'); text = text.replace(/>/g, '>'); text = text.replace(/"/g, '"'); text = text.replace(/'/g, "'"); text = text.replace(/&/g, '&'); return text; } // IE doesn't accept periods or dashes in the window name, but the element IDs // we use to generate popup window names may contain them, therefore we map them // to allowed characters in a reversible way so that we can locate the correct // element when the popup window is dismissed. function id_to_windowname(text) { text = text.replace(/\./g, '__dot__'); text = text.replace(/\-/g, '__dash__'); return text; } function windowname_to_id(text) { text = text.replace(/__dot__/g, '.'); text = text.replace(/__dash__/g, '-'); return text; } function showRelatedObjectLookupPopup(triggeringLink) { var name = triggeringLink.id.replace(/^lookup_/, ''); name = id_to_windowname(name); var href; if (triggeringLink.href.search(/\?/) >= 0) { href = triggeringLink.href + '&pop=1'; } else { href = triggeringLink.href + '?pop=1'; } var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); win.focus(); return false; } function dismissRelatedLookupPopup(win, chosenId) { var name = windowname_to_id(win.name); var elem = document.getElementById(name); if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) { elem.value += ',' + chosenId; } else { document.getElementById(name).value = chosenId; } win.close(); } function showAddAnotherPopup(triggeringLink) { var name = triggeringLink.id.replace(/^add_/, ''); name = id_to_windowname(name); href = triggeringLink.href if (href.indexOf('?') == -1) { href += '?_popup=1'; } else { href += '&_popup=1'; } var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); win.focus(); return false; } function dismissAddAnotherPopup(win, newId, newRepr) { // newId and newRepr are expected to have previously been escaped by // django.utils.html.escape. newId = html_unescape(newId); newRepr = html_unescape(newRepr); var name = windowname_to_id(win.name); var elem = document.getElementById(name); if (elem) { if (elem.nodeName == 'SELECT') { var o = new Option(newRepr, newId); elem.options[elem.options.length] = o; o.selected = true; } else if (elem.nodeName == 'INPUT') { if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) { elem.value += ',' + newId; } else { elem.value = newId; } } } else { var toId = name + "_to"; elem = document.getElementById(toId); var o = new Option(newRepr, newId); SelectBox.add_to_cache(toId, o); SelectBox.redisplay(toId); } win.close(); } ================================================ FILE: examples/django/1.2.7/static/js/admin/ordering.js ================================================ addEvent(window, 'load', reorder_init); var lis; var top = 0; var left = 0; var height = 30; function reorder_init() { lis = document.getElementsBySelector('ul#orderthese li'); var input = document.getElementsBySelector('input[name=order_]')[0]; setOrder(input.value.split(',')); input.disabled = true; draw(); // Now initialise the dragging behaviour var limit = (lis.length - 1) * height; for (var i = 0; i < lis.length; i++) { var li = lis[i]; var img = document.getElementById('handle'+li.id); li.style.zIndex = 1; Drag.init(img, li, left + 10, left + 10, top + 10, top + 10 + limit); li.onDragStart = startDrag; li.onDragEnd = endDrag; img.style.cursor = 'move'; } } function submitOrderForm() { var inputOrder = document.getElementsBySelector('input[name=order_]')[0]; inputOrder.value = getOrder(); inputOrder.disabled=false; } function startDrag() { this.style.zIndex = '10'; this.className = 'dragging'; } function endDrag(x, y) { this.style.zIndex = '1'; this.className = ''; // Work out how far along it has been dropped, using x co-ordinate var oldIndex = this.index; var newIndex = Math.round((y - 10 - top) / height); // 'Snap' to the correct position this.style.top = (10 + top + newIndex * height) + 'px'; this.index = newIndex; moveItem(oldIndex, newIndex); } function moveItem(oldIndex, newIndex) { // Swaps two items, adjusts the index and left co-ord for all others if (oldIndex == newIndex) { return; // Nothing to swap; } var direction, lo, hi; if (newIndex > oldIndex) { lo = oldIndex; hi = newIndex; direction = -1; } else { direction = 1; hi = oldIndex; lo = newIndex; } var lis2 = new Array(); // We will build the new order in this array for (var i = 0; i < lis.length; i++) { if (i < lo || i > hi) { // Position of items not between the indexes is unaffected lis2[i] = lis[i]; continue; } else if (i == newIndex) { lis2[i] = lis[oldIndex]; continue; } else { // Item is between the two indexes - move it along 1 lis2[i] = lis[i - direction]; } } // Re-index everything reIndex(lis2); lis = lis2; draw(); // document.getElementById('hiddenOrder').value = getOrder(); document.getElementsBySelector('input[name=order_]')[0].value = getOrder(); } function reIndex(lis) { for (var i = 0; i < lis.length; i++) { lis[i].index = i; } } function draw() { for (var i = 0; i < lis.length; i++) { var li = lis[i]; li.index = i; li.style.position = 'absolute'; li.style.left = (10 + left) + 'px'; li.style.top = (10 + top + (i * height)) + 'px'; } } function getOrder() { var order = new Array(lis.length); for (var i = 0; i < lis.length; i++) { order[i] = lis[i].id.substring(1, 100); } return order.join(','); } function setOrder(id_list) { /* Set the current order to match the lsit of IDs */ var temp_lis = new Array(); for (var i = 0; i < id_list.length; i++) { var id = 'p' + id_list[i]; temp_lis[temp_lis.length] = document.getElementById(id); } reIndex(temp_lis); lis = temp_lis; draw(); } function addEvent(elm, evType, fn, useCapture) // addEvent and removeEvent // cross-browser event handling for IE5+, NS6 and Mozilla // By Scott Andrew { if (elm.addEventListener){ elm.addEventListener(evType, fn, useCapture); return true; } else if (elm.attachEvent){ var r = elm.attachEvent("on"+evType, fn); return r; } else { elm['on'+evType] = fn; } } ================================================ FILE: examples/django/1.2.7/static/js/calendar.js ================================================ /* calendar.js - Calendar functions by Adrian Holovaty */ function removeChildren(a) { // "a" is reference to an object while (a.hasChildNodes()) a.removeChild(a.lastChild); } // quickElement(tagType, parentReference, textInChildNode, [, attribute, attributeValue ...]); function quickElement() { var obj = document.createElement(arguments[0]); if (arguments[2] != '' && arguments[2] != null) { var textNode = document.createTextNode(arguments[2]); obj.appendChild(textNode); } var len = arguments.length; for (var i = 3; i < len; i += 2) { obj.setAttribute(arguments[i], arguments[i+1]); } arguments[1].appendChild(obj); return obj; } // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions var CalendarNamespace = { monthsOfYear: gettext('January February March April May June July August September October November December').split(' '), daysOfWeek: gettext('S M T W T F S').split(' '), firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')), isLeapYear: function(year) { return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0)); }, getDaysInMonth: function(month,year) { var days; if (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) { days = 31; } else if (month==4 || month==6 || month==9 || month==11) { days = 30; } else if (month==2 && CalendarNamespace.isLeapYear(year)) { days = 29; } else { days = 28; } return days; }, draw: function(month, year, div_id, callback) { // month = 1-12, year = 1-9999 var today = new Date(); var todayDay = today.getDate(); var todayMonth = today.getMonth()+1; var todayYear = today.getFullYear(); var todayClass = ''; month = parseInt(month); year = parseInt(year); var calDiv = document.getElementById(div_id); removeChildren(calDiv); var calTable = document.createElement('table'); quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month-1] + ' ' + year); var tableBody = quickElement('tbody', calTable); // Draw days-of-week header var tableRow = quickElement('tr', tableBody); for (var i = 0; i < 7; i++) { quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]); } var startingPos = new Date(year, month-1, 1 - CalendarNamespace.firstDayOfWeek).getDay(); var days = CalendarNamespace.getDaysInMonth(month, year); // Draw blanks before first of month tableRow = quickElement('tr', tableBody); for (var i = 0; i < startingPos; i++) { var _cell = quickElement('td', tableRow, ' '); _cell.style.backgroundColor = '#f3f3f3'; } // Draw days of month var currentDay = 1; for (var i = startingPos; currentDay <= days; i++) { if (i%7 == 0 && currentDay != 1) { tableRow = quickElement('tr', tableBody); } if ((currentDay==todayDay) && (month==todayMonth) && (year==todayYear)) { todayClass='today'; } else { todayClass=''; } var cell = quickElement('td', tableRow, '', 'class', todayClass); quickElement('a', cell, currentDay, 'href', 'javascript:void(' + callback + '('+year+','+month+','+currentDay+'));'); currentDay++; } // Draw blanks after end of month (optional, but makes for valid code) while (tableRow.childNodes.length < 7) { var _cell = quickElement('td', tableRow, ' '); _cell.style.backgroundColor = '#f3f3f3'; } calDiv.appendChild(calTable); } } // Calendar -- A calendar instance function Calendar(div_id, callback) { // div_id (string) is the ID of the element in which the calendar will // be displayed // callback (string) is the name of a JavaScript function that will be // called with the parameters (year, month, day) when a day in the // calendar is clicked this.div_id = div_id; this.callback = callback; this.today = new Date(); this.currentMonth = this.today.getMonth() + 1; this.currentYear = this.today.getFullYear(); } Calendar.prototype = { drawCurrent: function() { CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback); }, drawDate: function(month, year) { this.currentMonth = month; this.currentYear = year; this.drawCurrent(); }, drawPreviousMonth: function() { if (this.currentMonth == 1) { this.currentMonth = 12; this.currentYear--; } else { this.currentMonth--; } this.drawCurrent(); }, drawNextMonth: function() { if (this.currentMonth == 12) { this.currentMonth = 1; this.currentYear++; } else { this.currentMonth++; } this.drawCurrent(); }, drawPreviousYear: function() { this.currentYear--; this.drawCurrent(); }, drawNextYear: function() { this.currentYear++; this.drawCurrent(); } } ================================================ FILE: examples/django/1.2.7/static/js/collapse.js ================================================ (function($) { $(document).ready(function() { // Add anchor tag for Show/Hide link $("fieldset.collapse").each(function(i, elem) { // Don't hide if fields in this fieldset have errors if ( $(elem).find("div.errors").length == 0 ) { $(elem).addClass("collapsed"); $(elem).find("h2").first().append(' (' + gettext("Show") + ')'); } }); // Add toggle to anchor tag $("fieldset.collapse a.collapse-toggle").toggle( function() { // Show $(this).text(gettext("Hide")); $(this).closest("fieldset").removeClass("collapsed"); return false; }, function() { // Hide $(this).text(gettext("Show")); $(this).closest("fieldset").addClass("collapsed"); return false; } ); }); })(django.jQuery); ================================================ FILE: examples/django/1.2.7/static/js/compress.py ================================================ #!/usr/bin/env python import os import optparse import subprocess import sys here = os.path.dirname(__file__) def main(): usage = "usage: %prog [file1..fileN]" description = """With no file paths given this script will automatically compress all jQuery-based files of the admin app. Requires the Google Closure Compiler library and Java version 6 or later.""" parser = optparse.OptionParser(usage, description=description) parser.add_option("-c", dest="compiler", default="~/bin/compiler.jar", help="path to Closure Compiler jar file") parser.add_option("-v", "--verbose", action="store_true", dest="verbose") parser.add_option("-q", "--quiet", action="store_false", dest="verbose") (options, args) = parser.parse_args() compiler = os.path.expanduser(options.compiler) if not os.path.exists(compiler): sys.exit("Google Closure compiler jar file %s not found. Please use the -c option to specify the path." % compiler) if not args: if options.verbose: sys.stdout.write("No filenames given; defaulting to admin scripts\n") args = [os.path.join(here, f) for f in [ "actions.js", "collapse.js", "inlines.js", "prepopulate.js"]] for arg in args: if not arg.endswith(".js"): arg = arg + ".js" to_compress = os.path.expanduser(arg) if os.path.exists(to_compress): to_compress_min = "%s.min.js" % "".join(arg.rsplit(".js")) cmd = "java -jar %s --js %s --js_output_file %s" % (compiler, to_compress, to_compress_min) if options.verbose: sys.stdout.write("Running: %s\n" % cmd) subprocess.call(cmd.split()) else: sys.stdout.write("File %s not found. Sure it exists?\n" % to_compress) if __name__ == '__main__': main() ================================================ FILE: examples/django/1.2.7/static/js/core.js ================================================ // Core javascript helper functions // basic browser identification & version var isOpera = (navigator.userAgent.indexOf("Opera")>=0) && parseFloat(navigator.appVersion); var isIE = ((document.all) && (!isOpera)) && parseFloat(navigator.appVersion.split("MSIE ")[1].split(";")[0]); // Cross-browser event handlers. function addEvent(obj, evType, fn) { if (obj.addEventListener) { obj.addEventListener(evType, fn, false); return true; } else if (obj.attachEvent) { var r = obj.attachEvent("on" + evType, fn); return r; } else { return false; } } function removeEvent(obj, evType, fn) { if (obj.removeEventListener) { obj.removeEventListener(evType, fn, false); return true; } else if (obj.detachEvent) { obj.detachEvent("on" + evType, fn); return true; } else { return false; } } // quickElement(tagType, parentReference, textInChildNode, [, attribute, attributeValue ...]); function quickElement() { var obj = document.createElement(arguments[0]); if (arguments[2] != '' && arguments[2] != null) { var textNode = document.createTextNode(arguments[2]); obj.appendChild(textNode); } var len = arguments.length; for (var i = 3; i < len; i += 2) { obj.setAttribute(arguments[i], arguments[i+1]); } arguments[1].appendChild(obj); return obj; } // ---------------------------------------------------------------------------- // Cross-browser xmlhttp object // from http://jibbering.com/2002/4/httprequest.html // ---------------------------------------------------------------------------- var xmlhttp; /*@cc_on @*/ /*@if (@_jscript_version >= 5) try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { xmlhttp = false; } } @else xmlhttp = false; @end @*/ if (!xmlhttp && typeof XMLHttpRequest != 'undefined') { xmlhttp = new XMLHttpRequest(); } // ---------------------------------------------------------------------------- // Find-position functions by PPK // See http://www.quirksmode.org/js/findpos.html // ---------------------------------------------------------------------------- function findPosX(obj) { var curleft = 0; if (obj.offsetParent) { while (obj.offsetParent) { curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft); obj = obj.offsetParent; } // IE offsetParent does not include the top-level if (isIE && obj.parentElement){ curleft += obj.offsetLeft - obj.scrollLeft; } } else if (obj.x) { curleft += obj.x; } return curleft; } function findPosY(obj) { var curtop = 0; if (obj.offsetParent) { while (obj.offsetParent) { curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop); obj = obj.offsetParent; } // IE offsetParent does not include the top-level if (isIE && obj.parentElement){ curtop += obj.offsetTop - obj.scrollTop; } } else if (obj.y) { curtop += obj.y; } return curtop; } //----------------------------------------------------------------------------- // Date object extensions // ---------------------------------------------------------------------------- Date.prototype.getCorrectYear = function() { // Date.getYear() is unreliable -- // see http://www.quirksmode.org/js/introdate.html#year var y = this.getYear() % 100; return (y < 38) ? y + 2000 : y + 1900; } Date.prototype.getTwelveHours = function() { hours = this.getHours(); if (hours == 0) { return 12; } else { return hours <= 12 ? hours : hours-12 } } Date.prototype.getTwoDigitMonth = function() { return (this.getMonth() < 9) ? '0' + (this.getMonth()+1) : (this.getMonth()+1); } Date.prototype.getTwoDigitDate = function() { return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); } Date.prototype.getTwoDigitTwelveHour = function() { return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); } Date.prototype.getTwoDigitHour = function() { return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); } Date.prototype.getTwoDigitMinute = function() { return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); } Date.prototype.getTwoDigitSecond = function() { return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); } Date.prototype.getISODate = function() { return this.getCorrectYear() + '-' + this.getTwoDigitMonth() + '-' + this.getTwoDigitDate(); } Date.prototype.getHourMinute = function() { return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute(); } Date.prototype.getHourMinuteSecond = function() { return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond(); } Date.prototype.strftime = function(format) { var fields = { c: this.toString(), d: this.getTwoDigitDate(), H: this.getTwoDigitHour(), I: this.getTwoDigitTwelveHour(), m: this.getTwoDigitMonth(), M: this.getTwoDigitMinute(), p: (this.getHours() >= 12) ? 'PM' : 'AM', S: this.getTwoDigitSecond(), w: '0' + this.getDay(), x: this.toLocaleDateString(), X: this.toLocaleTimeString(), y: ('' + this.getFullYear()).substr(2, 4), Y: '' + this.getFullYear(), '%' : '%' }; var result = '', i = 0; while (i < format.length) { if (format.charAt(i) === '%') { result = result + fields[format.charAt(i + 1)]; ++i; } else { result = result + format.charAt(i); } ++i; } return result; } // ---------------------------------------------------------------------------- // String object extensions // ---------------------------------------------------------------------------- String.prototype.pad_left = function(pad_length, pad_string) { var new_string = this; for (var i = 0; new_string.length < pad_length; i++) { new_string = pad_string + new_string; } return new_string; } // ---------------------------------------------------------------------------- // Get the computed style for and element // ---------------------------------------------------------------------------- function getStyle(oElm, strCssRule){ var strValue = ""; if(document.defaultView && document.defaultView.getComputedStyle){ strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule); } else if(oElm.currentStyle){ strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){ return p1.toUpperCase(); }); strValue = oElm.currentStyle[strCssRule]; } return strValue; } ================================================ FILE: examples/django/1.2.7/static/js/dateparse.js ================================================ /* 'Magic' date parsing, by Simon Willison (6th October 2003) http://simon.incutio.com/archive/2003/10/06/betterDateInput Adapted for 6newslawrence.com, 28th January 2004 */ /* Finds the index of the first occurence of item in the array, or -1 if not found */ if (typeof Array.prototype.indexOf == 'undefined') { Array.prototype.indexOf = function(item) { var len = this.length; for (var i = 0; i < len; i++) { if (this[i] == item) { return i; } } return -1; }; } /* Returns an array of items judged 'true' by the passed in test function */ if (typeof Array.prototype.filter == 'undefined') { Array.prototype.filter = function(test) { var matches = []; var len = this.length; for (var i = 0; i < len; i++) { if (test(this[i])) { matches[matches.length] = this[i]; } } return matches; }; } var monthNames = gettext("January February March April May June July August September October November December").split(" "); var weekdayNames = gettext("Sunday Monday Tuesday Wednesday Thursday Friday Saturday").split(" "); /* Takes a string, returns the index of the month matching that string, throws an error if 0 or more than 1 matches */ function parseMonth(month) { var matches = monthNames.filter(function(item) { return new RegExp("^" + month, "i").test(item); }); if (matches.length == 0) { throw new Error("Invalid month string"); } if (matches.length > 1) { throw new Error("Ambiguous month"); } return monthNames.indexOf(matches[0]); } /* Same as parseMonth but for days of the week */ function parseWeekday(weekday) { var matches = weekdayNames.filter(function(item) { return new RegExp("^" + weekday, "i").test(item); }); if (matches.length == 0) { throw new Error("Invalid day string"); } if (matches.length > 1) { throw new Error("Ambiguous weekday"); } return weekdayNames.indexOf(matches[0]); } /* Array of objects, each has 're', a regular expression and 'handler', a function for creating a date from something that matches the regular expression. Handlers may throw errors if string is unparseable. */ var dateParsePatterns = [ // Today { re: /^tod/i, handler: function() { return new Date(); } }, // Tomorrow { re: /^tom/i, handler: function() { var d = new Date(); d.setDate(d.getDate() + 1); return d; } }, // Yesterday { re: /^yes/i, handler: function() { var d = new Date(); d.setDate(d.getDate() - 1); return d; } }, // 4th { re: /^(\d{1,2})(st|nd|rd|th)?$/i, handler: function(bits) { var d = new Date(); d.setDate(parseInt(bits[1], 10)); return d; } }, // 4th Jan { re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+)$/i, handler: function(bits) { var d = new Date(); d.setDate(parseInt(bits[1], 10)); d.setMonth(parseMonth(bits[2])); return d; } }, // 4th Jan 2003 { re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+),? (\d{4})$/i, handler: function(bits) { var d = new Date(); d.setDate(parseInt(bits[1], 10)); d.setMonth(parseMonth(bits[2])); d.setYear(bits[3]); return d; } }, // Jan 4th { re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?$/i, handler: function(bits) { var d = new Date(); d.setDate(parseInt(bits[2], 10)); d.setMonth(parseMonth(bits[1])); return d; } }, // Jan 4th 2003 { re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?,? (\d{4})$/i, handler: function(bits) { var d = new Date(); d.setDate(parseInt(bits[2], 10)); d.setMonth(parseMonth(bits[1])); d.setYear(bits[3]); return d; } }, // next Tuesday - this is suspect due to weird meaning of "next" { re: /^next (\w+)$/i, handler: function(bits) { var d = new Date(); var day = d.getDay(); var newDay = parseWeekday(bits[1]); var addDays = newDay - day; if (newDay <= day) { addDays += 7; } d.setDate(d.getDate() + addDays); return d; } }, // last Tuesday { re: /^last (\w+)$/i, handler: function(bits) { throw new Error("Not yet implemented"); } }, // mm/dd/yyyy (American style) { re: /(\d{1,2})\/(\d{1,2})\/(\d{4})/, handler: function(bits) { var d = new Date(); d.setYear(bits[3]); d.setDate(parseInt(bits[2], 10)); d.setMonth(parseInt(bits[1], 10) - 1); // Because months indexed from 0 return d; } }, // yyyy-mm-dd (ISO style) { re: /(\d{4})-(\d{1,2})-(\d{1,2})/, handler: function(bits) { var d = new Date(); d.setYear(parseInt(bits[1])); d.setMonth(parseInt(bits[2], 10) - 1); d.setDate(parseInt(bits[3], 10)); return d; } }, ]; function parseDateString(s) { for (var i = 0; i < dateParsePatterns.length; i++) { var re = dateParsePatterns[i].re; var handler = dateParsePatterns[i].handler; var bits = re.exec(s); if (bits) { return handler(bits); } } throw new Error("Invalid date string"); } function fmt00(x) { // fmt00: Tags leading zero onto numbers 0 - 9. // Particularly useful for displaying results from Date methods. // if (Math.abs(parseInt(x)) < 10){ x = "0"+ Math.abs(x); } return x; } function parseDateStringISO(s) { try { var d = parseDateString(s); return d.getFullYear() + '-' + (fmt00(d.getMonth() + 1)) + '-' + fmt00(d.getDate()) } catch (e) { return s; } } function magicDate(input) { var messagespan = input.id + 'Msg'; try { var d = parseDateString(input.value); input.value = d.getFullYear() + '-' + (fmt00(d.getMonth() + 1)) + '-' + fmt00(d.getDate()); input.className = ''; // Human readable date if (document.getElementById(messagespan)) { document.getElementById(messagespan).firstChild.nodeValue = d.toDateString(); document.getElementById(messagespan).className = 'normal'; } } catch (e) { input.className = 'error'; var message = e.message; // Fix for IE6 bug if (message.indexOf('is null or not an object') > -1) { message = 'Invalid date string'; } if (document.getElementById(messagespan)) { document.getElementById(messagespan).firstChild.nodeValue = message; document.getElementById(messagespan).className = 'error'; } } } ================================================ FILE: examples/django/1.2.7/static/js/getElementsBySelector.js ================================================ /* document.getElementsBySelector(selector) - returns an array of element objects from the current document matching the CSS selector. Selectors can contain element names, class names and ids and can be nested. For example: elements = document.getElementsBySelect('div#main p a.external') Will return an array of all 'a' elements with 'external' in their class attribute that are contained inside 'p' elements that are contained inside the 'div' element which has id="main" New in version 0.4: Support for CSS2 and CSS3 attribute selectors: See http://www.w3.org/TR/css3-selectors/#attribute-selectors Version 0.4 - Simon Willison, March 25th 2003 -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows -- Opera 7 fails */ function getAllChildren(e) { // Returns all children of element. Workaround required for IE5/Windows. Ugh. return e.all ? e.all : e.getElementsByTagName('*'); } document.getElementsBySelector = function(selector) { // Attempt to fail gracefully in lesser browsers if (!document.getElementsByTagName) { return new Array(); } // Split selector in to tokens var tokens = selector.split(' '); var currentContext = new Array(document); for (var i = 0; i < tokens.length; i++) { token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');; if (token.indexOf('#') > -1) { // Token is an ID selector var bits = token.split('#'); var tagName = bits[0]; var id = bits[1]; var element = document.getElementById(id); if (!element || (tagName && element.nodeName.toLowerCase() != tagName)) { // ID not found or tag with that ID not found, return false. return new Array(); } // Set currentContext to contain just this element currentContext = new Array(element); continue; // Skip to next token } if (token.indexOf('.') > -1) { // Token contains a class selector var bits = token.split('.'); var tagName = bits[0]; var className = bits[1]; if (!tagName) { tagName = '*'; } // Get elements matching tag, filter them for class selector var found = new Array; var foundCount = 0; for (var h = 0; h < currentContext.length; h++) { var elements; if (tagName == '*') { elements = getAllChildren(currentContext[h]); } else { try { elements = currentContext[h].getElementsByTagName(tagName); } catch(e) { elements = []; } } for (var j = 0; j < elements.length; j++) { found[foundCount++] = elements[j]; } } currentContext = new Array; var currentContextIndex = 0; for (var k = 0; k < found.length; k++) { if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) { currentContext[currentContextIndex++] = found[k]; } } continue; // Skip to next token } // Code to deal with attribute selectors if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) { var tagName = RegExp.$1; var attrName = RegExp.$2; var attrOperator = RegExp.$3; var attrValue = RegExp.$4; if (!tagName) { tagName = '*'; } // Grab all of the tagName elements within current context var found = new Array; var foundCount = 0; for (var h = 0; h < currentContext.length; h++) { var elements; if (tagName == '*') { elements = getAllChildren(currentContext[h]); } else { elements = currentContext[h].getElementsByTagName(tagName); } for (var j = 0; j < elements.length; j++) { found[foundCount++] = elements[j]; } } currentContext = new Array; var currentContextIndex = 0; var checkFunction; // This function will be used to filter the elements switch (attrOperator) { case '=': // Equality checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); }; break; case '~': // Match one of space seperated words checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); }; break; case '|': // Match start with value followed by optional hyphen checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); }; break; case '^': // Match starts with value checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); }; break; case '$': // Match ends with value - fails with "Warning" in Opera 7 checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); }; break; case '*': // Match ends with value checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); }; break; default : // Just test for existence of attribute checkFunction = function(e) { return e.getAttribute(attrName); }; } currentContext = new Array; var currentContextIndex = 0; for (var k = 0; k < found.length; k++) { if (checkFunction(found[k])) { currentContext[currentContextIndex++] = found[k]; } } // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue); continue; // Skip to next token } // If we get here, token is JUST an element (not a class or ID selector) tagName = token; var found = new Array; var foundCount = 0; for (var h = 0; h < currentContext.length; h++) { var elements = currentContext[h].getElementsByTagName(tagName); for (var j = 0; j < elements.length; j++) { found[foundCount++] = elements[j]; } } currentContext = found; } return currentContext; } /* That revolting regular expression explained /^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/ \---/ \---/\-------------/ \-------/ | | | | | | | The value | | ~,|,^,$,* or = | Attribute Tag */ ================================================ FILE: examples/django/1.2.7/static/js/inlines.js ================================================ /** * Django admin inlines * * Based on jQuery Formset 1.1 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com) * @requires jQuery 1.2.6 or later * * Copyright (c) 2009, Stanislaus Madueke * All rights reserved. * * Spiced up with Code from Zain Memon's GSoC project 2009 * and modified for Django by Jannis Leidel * * Licensed under the New BSD License * See: http://www.opensource.org/licenses/bsd-license.php */ (function($) { $.fn.formset = function(opts) { var options = $.extend({}, $.fn.formset.defaults, opts); var updateElementIndex = function(el, prefix, ndx) { var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))"); var replacement = prefix + "-" + ndx; if ($(el).attr("for")) { $(el).attr("for", $(el).attr("for").replace(id_regex, replacement)); } if (el.id) { el.id = el.id.replace(id_regex, replacement); } if (el.name) { el.name = el.name.replace(id_regex, replacement); } }; var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off"); var nextIndex = parseInt(totalForms.val()); var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").attr("autocomplete", "off"); // only show the add button if we are allowed to add more items, // note that max_num = None translates to a blank string. var showAddButton = maxForms.val() == '' || (maxForms.val()-totalForms.val()) > 0; $(this).each(function(i) { $(this).not("." + options.emptyCssClass).addClass(options.formCssClass); }); if ($(this).length && showAddButton) { var addButton; if ($(this).attr("tagName") == "TR") { // If forms are laid out as table rows, insert the // "add" button in a new table row: var numCols = this.eq(0).children().length; $(this).parent().append('' + options.addText + ""); addButton = $(this).parent().find("tr:last a"); } else { // Otherwise, insert it immediately after the last form: $(this).filter(":last").after('"); addButton = $(this).filter(":last").next().find("a"); } addButton.click(function() { var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS"); var template = $("#" + options.prefix + "-empty"); var row = template.clone(true); row.removeClass(options.emptyCssClass) .addClass(options.formCssClass) .attr("id", options.prefix + "-" + nextIndex); if (row.is("tr")) { // If the forms are laid out in table rows, insert // the remove button into the last table cell: row.children(":last").append('"); } else if (row.is("ul") || row.is("ol")) { // If they're laid out as an ordered/unordered list, // insert an
  • after the last list item: row.append('
  • ' + options.deleteText + "
  • "); } else { // Otherwise, just insert the remove button as the // last child element of the form's container: row.children(":first").append('' + options.deleteText + ""); } row.find("*").each(function() { updateElementIndex(this, options.prefix, totalForms.val()); }); // Insert the new form when it has been fully edited row.insertBefore($(template)); // Update number of total forms $(totalForms).val(parseInt(totalForms.val()) + 1); nextIndex += 1; // Hide add button in case we've hit the max, except we want to add infinitely if ((maxForms.val() != '') && (maxForms.val()-totalForms.val()) <= 0) { addButton.parent().hide(); } // The delete button of each row triggers a bunch of other things row.find("a." + options.deleteCssClass).click(function() { // Remove the parent form containing this button: var row = $(this).parents("." + options.formCssClass); row.remove(); nextIndex -= 1; // If a post-delete callback was provided, call it with the deleted form: if (options.removed) { options.removed(row); } // Update the TOTAL_FORMS form count. var forms = $("." + options.formCssClass); $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length); // Show add button again once we drop below max if ((maxForms.val() == '') || (maxForms.val()-forms.length) > 0) { addButton.parent().show(); } // Also, update names and ids for all remaining form controls // so they remain in sequence: for (var i=0, formCount=forms.length; i)[^>]*$|^#([\w-]+)$/, // Is it a simple selector isSimple = /^.[^:#\[\.,]*$/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, // Used for trimming whitespace rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, // Has the ready events already been bound? readyBound = false, // The functions to execute on DOM ready readyList = [], // The ready event handler DOMContentLoaded, // Save a reference to some core methods toString = Object.prototype.toString, hasOwnProperty = Object.prototype.hasOwnProperty, push = Array.prototype.push, slice = Array.prototype.slice, indexOf = Array.prototype.indexOf; jQuery.fn = jQuery.prototype = { init: function( selector, context ) { var match, elem, ret, doc; // Handle $(""), $(null), or $(undefined) if ( !selector ) { return this; } // Handle $(DOMElement) if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; } // The body element only exists once, optimize finding it if ( selector === "body" && !context ) { this.context = document; this[0] = document.body; this.selector = "body"; this.length = 1; return this; } // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? match = quickExpr.exec( selector ); // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { doc = (context ? context.ownerDocument || context : document); // If a single string is passed in and it's a single tag // just do a createElement and skip the rest ret = rsingleTag.exec( selector ); if ( ret ) { if ( jQuery.isPlainObject( context ) ) { selector = [ document.createElement( ret[1] ) ]; jQuery.fn.attr.call( selector, context, true ); } else { selector = [ doc.createElement( ret[1] ) ]; } } else { ret = buildFragment( [ match[1] ], [ doc ] ); selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; } return jQuery.merge( this, selector ); // HANDLE: $("#id") } else { elem = document.getElementById( match[2] ); if ( elem ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $("TAG") } else if ( !context && /^\w+$/.test( selector ) ) { this.selector = selector; this.context = document; selector = document.getElementsByTagName( selector ); return jQuery.merge( this, selector ); // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return (context || rootjQuery).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return jQuery( context ).find( selector ); } // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } if (selector.selector !== undefined) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }, // Start with an empty selector selector: "", // The current version of jQuery being used jquery: "1.4.2", // The default length of a jQuery object is 0 length: 0, // The number of elements contained in the matched element set size: function() { return this.length; }, toArray: function() { return slice.call( this, 0 ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num == null ? // Return a 'clean' array this.toArray() : // Return just the object ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems, name, selector ) { // Build a new jQuery matched element set var ret = jQuery(); if ( jQuery.isArray( elems ) ) { push.apply( ret, elems ); } else { jQuery.merge( ret, elems ); } // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; if ( name === "find" ) { ret.selector = this.selector + (this.selector ? " " : "") + selector; } else if ( name ) { ret.selector = this.selector + "." + name + "(" + selector + ")"; } // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, ready: function( fn ) { // Attach the listeners jQuery.bindReady(); // If the DOM is already ready if ( jQuery.isReady ) { // Execute the function immediately fn.call( document, jQuery ); // Otherwise, remember the function for later } else if ( readyList ) { // Add the function to the wait list readyList.push( fn ); } return this; }, eq: function( i ) { return i === -1 ? this.slice( i ) : this.slice( i, +i + 1 ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, slice: function() { return this.pushStack( slice.apply( this, arguments ), "slice", slice.call(arguments).join(",") ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, end: function() { return this.prevObject || jQuery(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: [].sort, splice: [].splice }; // Give the init function the jQuery prototype for later instantiation jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { // copy reference to target object var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( length === i ) { target = this; --i; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging object literal values or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src : jQuery.isArray(copy) ? [] : {}; // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ noConflict: function( deep ) { window.$ = _$; if ( deep ) { window.jQuery = _jQuery; } return jQuery; }, // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // Handle when the DOM is ready ready: function() { // Make sure that the DOM is not already loaded if ( !jQuery.isReady ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 13 ); } // Remember that the DOM is ready jQuery.isReady = true; // If there are functions bound, to execute if ( readyList ) { // Execute all of them var fn, i = 0; while ( (fn = readyList[ i++ ]) ) { fn.call( document, jQuery ); } // Reset the list of functions readyList = null; } // Trigger any bound ready events if ( jQuery.fn.triggerHandler ) { jQuery( document ).triggerHandler( "ready" ); } } }, bindReady: function() { if ( readyBound ) { return; } readyBound = true; // Catch cases where $(document).ready() is called after the // browser event has already occurred. if ( document.readyState === "complete" ) { return jQuery.ready(); } // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes document.attachEvent("onreadystatechange", DOMContentLoaded); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame // continually check to see if the document is ready var toplevel = false; try { toplevel = window.frameElement == null; } catch(e) {} if ( document.documentElement.doScroll && toplevel ) { doScrollCheck(); } } }, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return toString.call(obj) === "[object Function]"; }, isArray: function( obj ) { return toString.call(obj) === "[object Array]"; }, isPlainObject: function( obj ) { // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { return false; } // Not own constructor property must be Object if ( obj.constructor && !hasOwnProperty.call(obj, "constructor") && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || hasOwnProperty.call( obj, key ); }, isEmptyObject: function( obj ) { for ( var name in obj ) { return false; } return true; }, error: function( msg ) { throw msg; }, parseJSON: function( data ) { if ( typeof data !== "string" || !data ) { return null; } // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { // Try to use the native JSON parser first return window.JSON && window.JSON.parse ? window.JSON.parse( data ) : (new Function("return " + data))(); } else { jQuery.error( "Invalid JSON: " + data ); } }, noop: function() {}, // Evalulates a script in a global context globalEval: function( data ) { if ( data && rnotwhite.test(data) ) { // Inspired by code by Andrea Giammarchi // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html var head = document.getElementsByTagName("head")[0] || document.documentElement, script = document.createElement("script"); script.type = "text/javascript"; if ( jQuery.support.scriptEval ) { script.appendChild( document.createTextNode( data ) ); } else { script.text = data; } // Use insertBefore instead of appendChild to circumvent an IE6 bug. // This arises when a base node is used (#2709). head.insertBefore( script, head.firstChild ); head.removeChild( script ); } }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, // args is for internal usage only each: function( object, callback, args ) { var name, i = 0, length = object.length, isObj = length === undefined || jQuery.isFunction(object); if ( args ) { if ( isObj ) { for ( name in object ) { if ( callback.apply( object[ name ], args ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.apply( object[ i++ ], args ) === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isObj ) { for ( name in object ) { if ( callback.call( object[ name ], name, object[ name ] ) === false ) { break; } } } else { for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} } } return object; }, trim: function( text ) { return (text || "").replace( rtrim, "" ); }, // results is for internal usage only makeArray: function( array, results ) { var ret = results || []; if ( array != null ) { // The window, strings (and functions) also have 'length' // The extra typeof function check is to prevent crashes // in Safari 2 (See: #3039) if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { push.call( ret, array ); } else { jQuery.merge( ret, array ); } } return ret; }, inArray: function( elem, array ) { if ( array.indexOf ) { return array.indexOf( elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; }, merge: function( first, second ) { var i = first.length, j = 0; if ( typeof second.length === "number" ) { for ( var l = second.length; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, inv ) { var ret = []; // Go through the array, only saving the items // that pass the validator function for ( var i = 0, length = elems.length; i < length; i++ ) { if ( !inv !== !callback( elems[ i ], i ) ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only map: function( elems, callback, arg ) { var ret = [], value; // Go through the array, translating each of the items to their // new value (or values). for ( var i = 0, length = elems.length; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret[ ret.length ] = value; } } return ret.concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, proxy: function( fn, proxy, thisObject ) { if ( arguments.length === 2 ) { if ( typeof proxy === "string" ) { thisObject = fn; fn = thisObject[ proxy ]; proxy = undefined; } else if ( proxy && !jQuery.isFunction( proxy ) ) { thisObject = proxy; proxy = undefined; } } if ( !proxy && fn ) { proxy = function() { return fn.apply( thisObject || this, arguments ); }; } // Set the guid of unique handler to the same of original handler, so it can be removed if ( fn ) { proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; } // So proxy can be declared as an argument return proxy; }, // Use of jQuery.browser is frowned upon. // More details: http://docs.jquery.com/Utilities/jQuery.browser uaMatch: function( ua ) { ua = ua.toLowerCase(); var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) || /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || /(msie) ([\w.]+)/.exec( ua ) || !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || []; return { browser: match[1] || "", version: match[2] || "0" }; }, browser: {} }); browserMatch = jQuery.uaMatch( userAgent ); if ( browserMatch.browser ) { jQuery.browser[ browserMatch.browser ] = true; jQuery.browser.version = browserMatch.version; } // Deprecated, use jQuery.browser.webkit instead if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } if ( indexOf ) { jQuery.inArray = function( elem, array ) { return indexOf.call( array, elem ); }; } // All jQuery objects should point back to these rootjQuery = jQuery(document); // Cleanup functions for the document ready method if ( document.addEventListener ) { DOMContentLoaded = function() { document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); }; } else if ( document.attachEvent ) { DOMContentLoaded = function() { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( document.readyState === "complete" ) { document.detachEvent( "onreadystatechange", DOMContentLoaded ); jQuery.ready(); } }; } // The DOM ready check for Internet Explorer function doScrollCheck() { if ( jQuery.isReady ) { return; } try { // If IE is used, use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ document.documentElement.doScroll("left"); } catch( error ) { setTimeout( doScrollCheck, 1 ); return; } // and execute any waiting functions jQuery.ready(); } function evalScript( i, elem ) { if ( elem.src ) { jQuery.ajax({ url: elem.src, async: false, dataType: "script" }); } else { jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); } if ( elem.parentNode ) { elem.parentNode.removeChild( elem ); } } // Mutifunctional method to get and set values to a collection // The value/s can be optionally by executed if its a function function access( elems, key, value, exec, fn, pass ) { var length = elems.length; // Setting many attributes if ( typeof key === "object" ) { for ( var k in key ) { access( elems, k, key[k], exec, fn, value ); } return elems; } // Setting one attribute if ( value !== undefined ) { // Optionally, function values get executed if exec is true exec = !pass && exec && jQuery.isFunction(value); for ( var i = 0; i < length; i++ ) { fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); } return elems; } // Getting an attribute return length ? fn( elems[0], key ) : undefined; } function now() { return (new Date).getTime(); } (function() { jQuery.support = {}; var root = document.documentElement, script = document.createElement("script"), div = document.createElement("div"), id = "script" + now(); div.style.display = "none"; div.innerHTML = "
    a"; var all = div.getElementsByTagName("*"), a = div.getElementsByTagName("a")[0]; // Can't get basic test support if ( !all || !all.length || !a ) { return; } jQuery.support = { // IE strips leading whitespace when .innerHTML is used leadingWhitespace: div.firstChild.nodeType === 3, // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables tbody: !div.getElementsByTagName("tbody").length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE htmlSerialize: !!div.getElementsByTagName("link").length, // Get the style information from getAttribute // (IE uses .cssText insted) style: /red/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) hrefNormalized: a.getAttribute("href") === "/a", // Make sure that element opacity exists // (IE uses filter instead) // Use a regex to work around a WebKit issue. See #5145 opacity: /^0.55$/.test( a.style.opacity ), // Verify style float existence // (IE uses styleFloat instead of cssFloat) cssFloat: !!a.style.cssFloat, // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) checkOn: div.getElementsByTagName("input")[0].value === "on", // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected, parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null, // Will be defined later deleteExpando: true, checkClone: false, scriptEval: false, noCloneEvent: true, boxModel: null }; script.type = "text/javascript"; try { script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); } catch(e) {} root.insertBefore( script, root.firstChild ); // Make sure that the execution of code works by injecting a script // tag with appendChild/createTextNode // (IE doesn't support this, fails, and uses .text instead) if ( window[ id ] ) { jQuery.support.scriptEval = true; delete window[ id ]; } // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete script.test; } catch(e) { jQuery.support.deleteExpando = false; } root.removeChild( script ); if ( div.attachEvent && div.fireEvent ) { div.attachEvent("onclick", function click() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) jQuery.support.noCloneEvent = false; div.detachEvent("onclick", click); }); div.cloneNode(true).fireEvent("onclick"); } div = document.createElement("div"); div.innerHTML = ""; var fragment = document.createDocumentFragment(); fragment.appendChild( div.firstChild ); // WebKit doesn't clone checked state correctly in fragments jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; // Figure out if the W3C box model works as expected // document.body must exist before we can do this jQuery(function() { var div = document.createElement("div"); div.style.width = div.style.paddingLeft = "1px"; document.body.appendChild( div ); jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; document.body.removeChild( div ).style.display = 'none'; div = null; }); // Technique from Juriy Zaytsev // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ var eventSupported = function( eventName ) { var el = document.createElement("div"); eventName = "on" + eventName; var isSupported = (eventName in el); if ( !isSupported ) { el.setAttribute(eventName, "return;"); isSupported = typeof el[eventName] === "function"; } el = null; return isSupported; }; jQuery.support.submitBubbles = eventSupported("submit"); jQuery.support.changeBubbles = eventSupported("change"); // release memory in IE root = script = div = all = a = null; })(); jQuery.props = { "for": "htmlFor", "class": "className", readonly: "readOnly", maxlength: "maxLength", cellspacing: "cellSpacing", rowspan: "rowSpan", colspan: "colSpan", tabindex: "tabIndex", usemap: "useMap", frameborder: "frameBorder" }; var expando = "jQuery" + now(), uuid = 0, windowData = {}; jQuery.extend({ cache: {}, expando:expando, // The following elements throw uncatchable exceptions if you // attempt to add expando properties to them. noData: { "embed": true, "object": true, "applet": true }, data: function( elem, name, data ) { if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { return; } elem = elem == window ? windowData : elem; var id = elem[ expando ], cache = jQuery.cache, thisCache; if ( !id && typeof name === "string" && data === undefined ) { return null; } // Compute a unique ID for the element if ( !id ) { id = ++uuid; } // Avoid generating a new cache unless none exists and we // want to manipulate it. if ( typeof name === "object" ) { elem[ expando ] = id; thisCache = cache[ id ] = jQuery.extend(true, {}, name); } else if ( !cache[ id ] ) { elem[ expando ] = id; cache[ id ] = {}; } thisCache = cache[ id ]; // Prevent overriding the named cache with undefined values if ( data !== undefined ) { thisCache[ name ] = data; } return typeof name === "string" ? thisCache[ name ] : thisCache; }, removeData: function( elem, name ) { if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { return; } elem = elem == window ? windowData : elem; var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ]; // If we want to remove a specific section of the element's data if ( name ) { if ( thisCache ) { // Remove the section of cache data delete thisCache[ name ]; // If we've removed all the data, remove the element's cache if ( jQuery.isEmptyObject(thisCache) ) { jQuery.removeData( elem ); } } // Otherwise, we want to remove all of the element's data } else { if ( jQuery.support.deleteExpando ) { delete elem[ jQuery.expando ]; } else if ( elem.removeAttribute ) { elem.removeAttribute( jQuery.expando ); } // Completely remove the data cache delete cache[ id ]; } } }); jQuery.fn.extend({ data: function( key, value ) { if ( typeof key === "undefined" && this.length ) { return jQuery.data( this[0] ); } else if ( typeof key === "object" ) { return this.each(function() { jQuery.data( this, key ); }); } var parts = key.split("."); parts[1] = parts[1] ? "." + parts[1] : ""; if ( value === undefined ) { var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); if ( data === undefined && this.length ) { data = jQuery.data( this[0], key ); } return data === undefined && parts[1] ? this.data( parts[0] ) : data; } else { return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() { jQuery.data( this, key, value ); }); } }, removeData: function( key ) { return this.each(function() { jQuery.removeData( this, key ); }); } }); jQuery.extend({ queue: function( elem, type, data ) { if ( !elem ) { return; } type = (type || "fx") + "queue"; var q = jQuery.data( elem, type ); // Speed up dequeue by getting out quickly if this is just a lookup if ( !data ) { return q || []; } if ( !q || jQuery.isArray(data) ) { q = jQuery.data( elem, type, jQuery.makeArray(data) ); } else { q.push( data ); } return q; }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), fn = queue.shift(); // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift("inprogress"); } fn.call(elem, function() { jQuery.dequeue(elem, type); }); } } }); jQuery.fn.extend({ queue: function( type, data ) { if ( typeof type !== "string" ) { data = type; type = "fx"; } if ( data === undefined ) { return jQuery.queue( this[0], type ); } return this.each(function( i, elem ) { var queue = jQuery.queue( this, type, data ); if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; type = type || "fx"; return this.queue( type, function() { var elem = this; setTimeout(function() { jQuery.dequeue( elem, type ); }, time ); }); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); } }); var rclass = /[\n\t]/g, rspace = /\s+/, rreturn = /\r/g, rspecialurl = /href|src|style/, rtype = /(button|input)/i, rfocusable = /(button|input|object|select|textarea)/i, rclickable = /^(a|area)$/i, rradiocheck = /radio|checkbox/; jQuery.fn.extend({ attr: function( name, value ) { return access( this, name, value, true, jQuery.attr ); }, removeAttr: function( name, fn ) { return this.each(function(){ jQuery.attr( this, name, "" ); if ( this.nodeType === 1 ) { this.removeAttribute( name ); } }); }, addClass: function( value ) { if ( jQuery.isFunction(value) ) { return this.each(function(i) { var self = jQuery(this); self.addClass( value.call(this, i, self.attr("class")) ); }); } if ( value && typeof value === "string" ) { var classNames = (value || "").split( rspace ); for ( var i = 0, l = this.length; i < l; i++ ) { var elem = this[i]; if ( elem.nodeType === 1 ) { if ( !elem.className ) { elem.className = value; } else { var className = " " + elem.className + " ", setClass = elem.className; for ( var c = 0, cl = classNames.length; c < cl; c++ ) { if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { setClass += " " + classNames[c]; } } elem.className = jQuery.trim( setClass ); } } } } return this; }, removeClass: function( value ) { if ( jQuery.isFunction(value) ) { return this.each(function(i) { var self = jQuery(this); self.removeClass( value.call(this, i, self.attr("class")) ); }); } if ( (value && typeof value === "string") || value === undefined ) { var classNames = (value || "").split(rspace); for ( var i = 0, l = this.length; i < l; i++ ) { var elem = this[i]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { var className = (" " + elem.className + " ").replace(rclass, " "); for ( var c = 0, cl = classNames.length; c < cl; c++ ) { className = className.replace(" " + classNames[c] + " ", " "); } elem.className = jQuery.trim( className ); } else { elem.className = ""; } } } } return this; }, toggleClass: function( value, stateVal ) { var type = typeof value, isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { return this.each(function(i) { var self = jQuery(this); self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); }); } return this.each(function() { if ( type === "string" ) { // toggle individual class names var className, i = 0, self = jQuery(this), state = stateVal, classNames = value.split( rspace ); while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list state = isBool ? state : !self.hasClass( className ); self[ state ? "addClass" : "removeClass" ]( className ); } } else if ( type === "undefined" || type === "boolean" ) { if ( this.className ) { // store className if set jQuery.data( this, "__className__", this.className ); } // toggle whole className this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || ""; } }); }, hasClass: function( selector ) { var className = " " + selector + " "; for ( var i = 0, l = this.length; i < l; i++ ) { if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { return true; } } return false; }, val: function( value ) { if ( value === undefined ) { var elem = this[0]; if ( elem ) { if ( jQuery.nodeName( elem, "option" ) ) { return (elem.attributes.value || {}).specified ? elem.value : elem.text; } // We need to handle select boxes special if ( jQuery.nodeName( elem, "select" ) ) { var index = elem.selectedIndex, values = [], options = elem.options, one = elem.type === "select-one"; // Nothing was selected if ( index < 0 ) { return null; } // Loop through all the selected options for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { var option = options[ i ]; if ( option.selected ) { // Get the specifc value for the option value = jQuery(option).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } return values; } // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { return elem.getAttribute("value") === null ? "on" : elem.value; } // Everything else, we just grab the value return (elem.value || "").replace(rreturn, ""); } return undefined; } var isFunction = jQuery.isFunction(value); return this.each(function(i) { var self = jQuery(this), val = value; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { val = value.call(this, i, self.val()); } // Typecast each time if the value is a Function and the appended // value is therefore different each time. if ( typeof val === "number" ) { val += ""; } if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { this.checked = jQuery.inArray( self.val(), val ) >= 0; } else if ( jQuery.nodeName( this, "select" ) ) { var values = jQuery.makeArray(val); jQuery( "option", this ).each(function() { this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; }); if ( !values.length ) { this.selectedIndex = -1; } } else { this.value = val; } }); } }); jQuery.extend({ attrFn: { val: true, css: true, html: true, text: true, data: true, width: true, height: true, offset: true }, attr: function( elem, name, value, pass ) { // don't set attributes on text and comment nodes if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { return undefined; } if ( pass && name in jQuery.attrFn ) { return jQuery(elem)[name](value); } var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), // Whether we are setting (or getting) set = value !== undefined; // Try to normalize/fix the name name = notxml && jQuery.props[ name ] || name; // Only do all the following if this is a node (faster for style) if ( elem.nodeType === 1 ) { // These attributes require special treatment var special = rspecialurl.test( name ); // Safari mis-reports the default selected property of an option // Accessing the parent's selectedIndex property fixes it if ( name === "selected" && !jQuery.support.optSelected ) { var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } } // If applicable, access the attribute via the DOM 0 way if ( name in elem && notxml && !special ) { if ( set ) { // We can't allow the type property to be changed (since it causes problems in IE) if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { jQuery.error( "type property can't be changed" ); } elem[ name ] = value; } // browsers index elements by id/name on forms, give priority to attributes. if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { return elem.getAttributeNode( name ).nodeValue; } // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ if ( name === "tabIndex" ) { var attributeNode = elem.getAttributeNode( "tabIndex" ); return attributeNode && attributeNode.specified ? attributeNode.value : rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 0 : undefined; } return elem[ name ]; } if ( !jQuery.support.style && notxml && name === "style" ) { if ( set ) { elem.style.cssText = "" + value; } return elem.style.cssText; } if ( set ) { // convert the value to a string (all browsers do this but IE) see #1070 elem.setAttribute( name, "" + value ); } var attr = !jQuery.support.hrefNormalized && notxml && special ? // Some attributes require a special call on IE elem.getAttribute( name, 2 ) : elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return attr === null ? undefined : attr; } // elem is actually elem.style ... set the style // Using attr for specific style information is now deprecated. Use style instead. return jQuery.style( elem, name, value ); } }); var rnamespaces = /\.(.*)$/, fcleanup = function( nm ) { return nm.replace(/[^\w\s\.\|`]/g, function( ch ) { return "\\" + ch; }); }; /* * A number of helper functions used for managing events. * Many of the ideas behind this code originated from * Dean Edwards' addEvent library. */ jQuery.event = { // Bind an event to an element // Original by Dean Edwards add: function( elem, types, handler, data ) { if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // For whatever reason, IE has trouble passing the window object // around, causing it to be cloned in the process if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { elem = window; } var handleObjIn, handleObj; if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; } // Make sure that the function being executed has a unique ID if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure var elemData = jQuery.data( elem ); // If no elemData is found then we must be trying to bind to one of the // banned noData elements if ( !elemData ) { return; } var events = elemData.events = elemData.events || {}, eventHandle = elemData.handle, eventHandle; if ( !eventHandle ) { elemData.handle = eventHandle = function() { // Handle the second event of a trigger and when // an event is called after a page has unloaded return typeof jQuery !== "undefined" && !jQuery.event.triggered ? jQuery.event.handle.apply( eventHandle.elem, arguments ) : undefined; }; } // Add elem as a property of the handle function // This is to prevent a memory leak with non-native events in IE. eventHandle.elem = elem; // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); types = types.split(" "); var type, i = 0, namespaces; while ( (type = types[ i++ ]) ) { handleObj = handleObjIn ? jQuery.extend({}, handleObjIn) : { handler: handler, data: data }; // Namespaced event handlers if ( type.indexOf(".") > -1 ) { namespaces = type.split("."); type = namespaces.shift(); handleObj.namespace = namespaces.slice(0).sort().join("."); } else { namespaces = []; handleObj.namespace = ""; } handleObj.type = type; handleObj.guid = handler.guid; // Get the current list of functions bound to this event var handlers = events[ type ], special = jQuery.event.special[ type ] || {}; // Init the event handler queue if ( !handlers ) { handlers = events[ type ] = []; // Check for a special event handler // Only use addEventListener/attachEvent if the special // events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add the function to the element's handler list handlers.push( handleObj ); // Keep track of which events have been used, for global triggering jQuery.event.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, global: {}, // Detach an event or set of events from an element remove: function( elem, types, handler, pos ) { // don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, elemData = jQuery.data( elem ), events = elemData && elemData.events; if ( !elemData || !events ) { return; } // types is actually an event object here if ( types && types.type ) { handler = types.handler; types = types.type; } // Unbind all events for the element if ( !types || typeof types === "string" && types.charAt(0) === "." ) { types = types || ""; for ( type in events ) { jQuery.event.remove( elem, type + types ); } return; } // Handle multiple events separated by a space // jQuery(...).unbind("mouseover mouseout", fn); types = types.split(" "); while ( (type = types[ i++ ]) ) { origType = type; handleObj = null; all = type.indexOf(".") < 0; namespaces = []; if ( !all ) { // Namespaced event handlers namespaces = type.split("."); type = namespaces.shift(); namespace = new RegExp("(^|\\.)" + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)") } eventType = events[ type ]; if ( !eventType ) { continue; } if ( !handler ) { for ( var j = 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; if ( all || namespace.test( handleObj.namespace ) ) { jQuery.event.remove( elem, origType, handleObj.handler, j ); eventType.splice( j--, 1 ); } } continue; } special = jQuery.event.special[ type ] || {}; for ( var j = pos || 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; if ( handler.guid === handleObj.guid ) { // remove the given handler for the given type if ( all || namespace.test( handleObj.namespace ) ) { if ( pos == null ) { eventType.splice( j--, 1 ); } if ( special.remove ) { special.remove.call( elem, handleObj ); } } if ( pos != null ) { break; } } } // remove generic event handler if no more handlers exist if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { removeEvent( elem, type, elemData.handle ); } ret = null; delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { var handle = elemData.handle; if ( handle ) { handle.elem = null; } delete elemData.events; delete elemData.handle; if ( jQuery.isEmptyObject( elemData ) ) { jQuery.removeData( elem ); } } }, // bubbling is internal trigger: function( event, data, elem /*, bubbling */ ) { // Event object or event type var type = event.type || event, bubbling = arguments[3]; if ( !bubbling ) { event = typeof event === "object" ? // jQuery.Event object event[expando] ? event : // Object literal jQuery.extend( jQuery.Event(type), event ) : // Just the event type (string) jQuery.Event(type); if ( type.indexOf("!") >= 0 ) { event.type = type = type.slice(0, -1); event.exclusive = true; } // Handle a global trigger if ( !elem ) { // Don't bubble custom events when global (to avoid too much overhead) event.stopPropagation(); // Only trigger if we've ever bound an event for it if ( jQuery.event.global[ type ] ) { jQuery.each( jQuery.cache, function() { if ( this.events && this.events[type] ) { jQuery.event.trigger( event, data, this.handle.elem ); } }); } } // Handle triggering a single element // don't do events on text and comment nodes if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { return undefined; } // Clean up in case it is reused event.result = undefined; event.target = elem; // Clone the incoming data, if any data = jQuery.makeArray( data ); data.unshift( event ); } event.currentTarget = elem; // Trigger the event, it is assumed that "handle" is a function var handle = jQuery.data( elem, "handle" ); if ( handle ) { handle.apply( elem, data ); } var parent = elem.parentNode || elem.ownerDocument; // Trigger an inline bound script try { if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { event.result = false; } } // prevent IE from throwing an error for some elements with some event types, see #3533 } catch (e) {} if ( !event.isPropagationStopped() && parent ) { jQuery.event.trigger( event, data, parent, true ); } else if ( !event.isDefaultPrevented() ) { var target = event.target, old, isClick = jQuery.nodeName(target, "a") && type === "click", special = jQuery.event.special[ type ] || {}; if ( (!special._default || special._default.call( elem, event ) === false) && !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { try { if ( target[ type ] ) { // Make sure that we don't accidentally re-trigger the onFOO events old = target[ "on" + type ]; if ( old ) { target[ "on" + type ] = null; } jQuery.event.triggered = true; target[ type ](); } // prevent IE from throwing an error for some elements with some event types, see #3533 } catch (e) {} if ( old ) { target[ "on" + type ] = old; } jQuery.event.triggered = false; } } }, handle: function( event ) { var all, handlers, namespaces, namespace, events; event = arguments[0] = jQuery.event.fix( event || window.event ); event.currentTarget = this; // Namespaced event handlers all = event.type.indexOf(".") < 0 && !event.exclusive; if ( !all ) { namespaces = event.type.split("."); event.type = namespaces.shift(); namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)"); } var events = jQuery.data(this, "events"), handlers = events[ event.type ]; if ( events && handlers ) { // Clone the handlers to prevent manipulation handlers = handlers.slice(0); for ( var j = 0, l = handlers.length; j < l; j++ ) { var handleObj = handlers[ j ]; // Filter the functions by class if ( all || namespace.test( handleObj.namespace ) ) { // Pass in a reference to the handler function itself // So that we can later remove it event.handler = handleObj.handler; event.data = handleObj.data; event.handleObj = handleObj; var ret = handleObj.handler.apply( this, arguments ); if ( ret !== undefined ) { event.result = ret; if ( ret === false ) { event.preventDefault(); event.stopPropagation(); } } if ( event.isImmediatePropagationStopped() ) { break; } } } } return event.result; }, props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), fix: function( event ) { if ( event[ expando ] ) { return event; } // store a copy of the original event object // and "clone" to set read-only properties var originalEvent = event; event = jQuery.Event( originalEvent ); for ( var i = this.props.length, prop; i; ) { prop = this.props[ --i ]; event[ prop ] = originalEvent[ prop ]; } // Fix target property, if necessary if ( !event.target ) { event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either } // check if target is a textnode (safari) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // Add relatedTarget, if necessary if ( !event.relatedTarget && event.fromElement ) { event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; } // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && event.clientX != null ) { var doc = document.documentElement, body = document.body; event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); } // Add which for key events if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) { event.which = event.charCode || event.keyCode; } // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) if ( !event.metaKey && event.ctrlKey ) { event.metaKey = event.ctrlKey; } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && event.button !== undefined ) { event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); } return event; }, // Deprecated, use jQuery.guid instead guid: 1E8, // Deprecated, use jQuery.proxy instead proxy: jQuery.proxy, special: { ready: { // Make sure the ready event is setup setup: jQuery.bindReady, teardown: jQuery.noop }, live: { add: function( handleObj ) { jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); }, remove: function( handleObj ) { var remove = true, type = handleObj.origType.replace(rnamespaces, ""); jQuery.each( jQuery.data(this, "events").live || [], function() { if ( type === this.origType.replace(rnamespaces, "") ) { remove = false; return false; } }); if ( remove ) { jQuery.event.remove( this, handleObj.origType, liveHandler ); } } }, beforeunload: { setup: function( data, namespaces, eventHandle ) { // We only want to do this special case on windows if ( this.setInterval ) { this.onbeforeunload = eventHandle; } return false; }, teardown: function( namespaces, eventHandle ) { if ( this.onbeforeunload === eventHandle ) { this.onbeforeunload = null; } } } } }; var removeEvent = document.removeEventListener ? function( elem, type, handle ) { elem.removeEventListener( type, handle, false ); } : function( elem, type, handle ) { elem.detachEvent( "on" + type, handle ); }; jQuery.Event = function( src ) { // Allow instantiation without the 'new' keyword if ( !this.preventDefault ) { return new jQuery.Event( src ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Event type } else { this.type = src; } // timeStamp is buggy for some events on Firefox(#3843) // So we won't rely on the native value this.timeStamp = now(); // Mark it as fixed this[ expando ] = true; }; function returnFalse() { return false; } function returnTrue() { return true; } // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { preventDefault: function() { this.isDefaultPrevented = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if preventDefault exists run it on the original event if ( e.preventDefault ) { e.preventDefault(); } // otherwise set the returnValue property of the original event to false (IE) e.returnValue = false; }, stopPropagation: function() { this.isPropagationStopped = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if stopPropagation exists run it on the original event if ( e.stopPropagation ) { e.stopPropagation(); } // otherwise set the cancelBubble property of the original event to true (IE) e.cancelBubble = true; }, stopImmediatePropagation: function() { this.isImmediatePropagationStopped = returnTrue; this.stopPropagation(); }, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse }; // Checks if an event happened on an element within another element // Used in jQuery.event.special.mouseenter and mouseleave handlers var withinElement = function( event ) { // Check if mouse(over|out) are still within the same parent element var parent = event.relatedTarget; // Firefox sometimes assigns relatedTarget a XUL element // which we cannot access the parentNode property of try { // Traverse up the tree while ( parent && parent !== this ) { parent = parent.parentNode; } if ( parent !== this ) { // set the correct event type event.type = event.data; // handle event if we actually just moused on to a non sub-element jQuery.event.handle.apply( this, arguments ); } // assuming we've left the element since we most likely mousedover a xul element } catch(e) { } }, // In case of event delegation, we only need to rename the event.type, // liveHandler will take care of the rest. delegate = function( event ) { event.type = event.data; jQuery.event.handle.apply( this, arguments ); }; // Create mouseenter and mouseleave events jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { setup: function( data ) { jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); }, teardown: function( data ) { jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); } }; }); // submit delegation if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { setup: function( data, namespaces ) { if ( this.nodeName.toLowerCase() !== "form" ) { jQuery.event.add(this, "click.specialSubmit", function( e ) { var elem = e.target, type = elem.type; if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { return trigger( "submit", this, arguments ); } }); jQuery.event.add(this, "keypress.specialSubmit", function( e ) { var elem = e.target, type = elem.type; if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { return trigger( "submit", this, arguments ); } }); } else { return false; } }, teardown: function( namespaces ) { jQuery.event.remove( this, ".specialSubmit" ); } }; } // change delegation, happens here so we have bind. if ( !jQuery.support.changeBubbles ) { var formElems = /textarea|input|select/i, changeFilters, getVal = function( elem ) { var type = elem.type, val = elem.value; if ( type === "radio" || type === "checkbox" ) { val = elem.checked; } else if ( type === "select-multiple" ) { val = elem.selectedIndex > -1 ? jQuery.map( elem.options, function( elem ) { return elem.selected; }).join("-") : ""; } else if ( elem.nodeName.toLowerCase() === "select" ) { val = elem.selectedIndex; } return val; }, testChange = function testChange( e ) { var elem = e.target, data, val; if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { return; } data = jQuery.data( elem, "_change_data" ); val = getVal(elem); // the current data will be also retrieved by beforeactivate if ( e.type !== "focusout" || elem.type !== "radio" ) { jQuery.data( elem, "_change_data", val ); } if ( data === undefined || val === data ) { return; } if ( data != null || val ) { e.type = "change"; return jQuery.event.trigger( e, arguments[1], elem ); } }; jQuery.event.special.change = { filters: { focusout: testChange, click: function( e ) { var elem = e.target, type = elem.type; if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { return testChange.call( this, e ); } }, // Change has to be called before submit // Keydown will be called before keypress, which is used in submit-event delegation keydown: function( e ) { var elem = e.target, type = elem.type; if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || type === "select-multiple" ) { return testChange.call( this, e ); } }, // Beforeactivate happens also before the previous element is blurred // with this event you can't trigger a change event, but you can store // information/focus[in] is not needed anymore beforeactivate: function( e ) { var elem = e.target; jQuery.data( elem, "_change_data", getVal(elem) ); } }, setup: function( data, namespaces ) { if ( this.type === "file" ) { return false; } for ( var type in changeFilters ) { jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); } return formElems.test( this.nodeName ); }, teardown: function( namespaces ) { jQuery.event.remove( this, ".specialChange" ); return formElems.test( this.nodeName ); } }; changeFilters = jQuery.event.special.change.filters; } function trigger( type, elem, args ) { args[0].type = type; return jQuery.event.handle.apply( elem, args ); } // Create "bubbling" focus and blur events if ( document.addEventListener ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { jQuery.event.special[ fix ] = { setup: function() { this.addEventListener( orig, handler, true ); }, teardown: function() { this.removeEventListener( orig, handler, true ); } }; function handler( e ) { e = jQuery.event.fix( e ); e.type = fix; return jQuery.event.handle.call( this, e ); } }); } jQuery.each(["bind", "one"], function( i, name ) { jQuery.fn[ name ] = function( type, data, fn ) { // Handle object literals if ( typeof type === "object" ) { for ( var key in type ) { this[ name ](key, data, type[key], fn); } return this; } if ( jQuery.isFunction( data ) ) { fn = data; data = undefined; } var handler = name === "one" ? jQuery.proxy( fn, function( event ) { jQuery( this ).unbind( event, handler ); return fn.apply( this, arguments ); }) : fn; if ( type === "unload" && name !== "one" ) { this.one( type, data, fn ); } else { for ( var i = 0, l = this.length; i < l; i++ ) { jQuery.event.add( this[i], type, handler, data ); } } return this; }; }); jQuery.fn.extend({ unbind: function( type, fn ) { // Handle object literals if ( typeof type === "object" && !type.preventDefault ) { for ( var key in type ) { this.unbind(key, type[key]); } } else { for ( var i = 0, l = this.length; i < l; i++ ) { jQuery.event.remove( this[i], type, fn ); } } return this; }, delegate: function( selector, types, data, fn ) { return this.live( types, data, fn, selector ); }, undelegate: function( selector, types, fn ) { if ( arguments.length === 0 ) { return this.unbind( "live" ); } else { return this.die( types, null, fn, selector ); } }, trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { if ( this[0] ) { var event = jQuery.Event( type ); event.preventDefault(); event.stopPropagation(); jQuery.event.trigger( event, data, this[0] ); return event.result; } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, i = 1; // link all the functions, so any of them can unbind this click handler while ( i < args.length ) { jQuery.proxy( fn, args[ i++ ] ); } return this.click( jQuery.proxy( fn, function( event ) { // Figure out which function to execute var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); // Make sure that clicks stop event.preventDefault(); // and execute the function return args[ lastToggle ].apply( this, arguments ) || false; })); }, hover: function( fnOver, fnOut ) { return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); } }); var liveMap = { focus: "focusin", blur: "focusout", mouseenter: "mouseover", mouseleave: "mouseout" }; jQuery.each(["live", "die"], function( i, name ) { jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { var type, i = 0, match, namespaces, preType, selector = origSelector || this.selector, context = origSelector ? this : jQuery( this.context ); if ( jQuery.isFunction( data ) ) { fn = data; data = undefined; } types = (types || "").split(" "); while ( (type = types[ i++ ]) != null ) { match = rnamespaces.exec( type ); namespaces = ""; if ( match ) { namespaces = match[0]; type = type.replace( rnamespaces, "" ); } if ( type === "hover" ) { types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); continue; } preType = type; if ( type === "focus" || type === "blur" ) { types.push( liveMap[ type ] + namespaces ); type = type + namespaces; } else { type = (liveMap[ type ] || type) + namespaces; } if ( name === "live" ) { // bind live handler context.each(function(){ jQuery.event.add( this, liveConvert( type, selector ), { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); }); } else { // unbind live handler context.unbind( liveConvert( type, selector ), fn ); } } return this; } }); function liveHandler( event ) { var stop, elems = [], selectors = [], args = arguments, related, match, handleObj, elem, j, i, l, data, events = jQuery.data( this, "events" ); // Make sure we avoid non-left-click bubbling in Firefox (#3861) if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) { return; } event.liveFired = this; var live = events.live.slice(0); for ( j = 0; j < live.length; j++ ) { handleObj = live[j]; if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { selectors.push( handleObj.selector ); } else { live.splice( j--, 1 ); } } match = jQuery( event.target ).closest( selectors, event.currentTarget ); for ( i = 0, l = match.length; i < l; i++ ) { for ( j = 0; j < live.length; j++ ) { handleObj = live[j]; if ( match[i].selector === handleObj.selector ) { elem = match[i].elem; related = null; // Those two events require additional checking if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; } if ( !related || related !== elem ) { elems.push({ elem: elem, handleObj: handleObj }); } } } } for ( i = 0, l = elems.length; i < l; i++ ) { match = elems[i]; event.currentTarget = match.elem; event.data = match.handleObj.data; event.handleObj = match.handleObj; if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) { stop = false; break; } } return stop; } function liveConvert( type, selector ) { return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&"); } jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( fn ) { return fn ? this.bind( name, fn ) : this.trigger( name ); }; if ( jQuery.attrFn ) { jQuery.attrFn[ name ] = true; } }); // Prevent memory leaks in IE // Window isn't included so as not to unbind existing unload events // More info: // - http://isaacschlueter.com/2006/10/msie-memory-leaks/ if ( window.attachEvent && !window.addEventListener ) { window.attachEvent("onunload", function() { for ( var id in jQuery.cache ) { if ( jQuery.cache[ id ].handle ) { // Try/Catch is to handle iframes being unloaded, see #4280 try { jQuery.event.remove( jQuery.cache[ id ].handle.elem ); } catch(e) {} } } }); } /*! * Sizzle CSS Selector Engine - v1.0 * Copyright 2009, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true; // Here we check if the JavaScript engine is using some sort of // optimization where it does not always call our comparision // function. If that is the case, discard the hasDuplicate value. // Thus far that includes Google Chrome. [0, 0].sort(function(){ baseHasDuplicate = false; return 0; }); var Sizzle = function(selector, context, results, seed) { results = results || []; var origContext = context = context || document; if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } if ( !selector || typeof selector !== "string" ) { return results; } var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context), soFar = selector; // Reset the position of the chunker regexp (start from head) while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { soFar = m[3]; parts.push( m[1] ); if ( m[2] ) { extra = m[3]; break; } } if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context ); } else { set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) { selector += parts.shift(); } set = posProcess( selector, set ); } } } else { // Take a shortcut and set the context if the root selector is an ID // (but not if it'll be faster if the inner selector is an ID) if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { var ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } if ( context ) { var ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray(set); } else { prune = false; } while ( parts.length ) { var cur = parts.pop(), pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; } } if ( !checkSet ) { checkSet = set; } if ( !checkSet ) { Sizzle.error( cur || selector ); } if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } else if ( context && context.nodeType === 1 ) { for ( var i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( var i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); } if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); } return results; }; Sizzle.uniqueSort = function(results){ if ( sortOrder ) { hasDuplicate = baseHasDuplicate; results.sort(sortOrder); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { if ( results[i] === results[i-1] ) { results.splice(i--, 1); } } } } return results; }; Sizzle.matches = function(expr, set){ return Sizzle(expr, null, null, set); }; Sizzle.find = function(expr, context, isXML){ var set, match; if ( !expr ) { return []; } for ( var i = 0, l = Expr.order.length; i < l; i++ ) { var type = Expr.order[i], match; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { var left = match[1]; match.splice(1,1); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace(/\\/g, ""); set = Expr.find[ type ]( match, context, isXML ); if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; } } } } if ( !set ) { set = context.getElementsByTagName("*"); } return {set: set, expr: expr}; }; Sizzle.filter = function(expr, set, inplace, not){ var old = expr, result = [], curLoop = set, match, anyFound, isXMLFilter = set && set[0] && isXML(set[0]); while ( expr && set.length ) { for ( var type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { var filter = Expr.filter[ type ], found, item, left = match[1]; anyFound = false; match.splice(1,1); if ( left.substr( left.length - 1 ) === "\\" ) { continue; } if ( curLoop === result ) { result = []; } if ( Expr.preFilter[ type ] ) { match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; } else if ( match === true ) { continue; } } if ( match ) { for ( var i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); var pass = not ^ !!found; if ( inplace && found != null ) { if ( pass ) { anyFound = true; } else { curLoop[i] = false; } } else if ( pass ) { result.push( item ); anyFound = true; } } } } if ( found !== undefined ) { if ( !inplace ) { curLoop = result; } expr = expr.replace( Expr.match[ type ], "" ); if ( !anyFound ) { return []; } break; } } } // Improper expression if ( expr === old ) { if ( anyFound == null ) { Sizzle.error( expr ); } else { break; } } old = expr; } return curLoop; }; Sizzle.error = function( msg ) { throw "Syntax error, unrecognized expression: " + msg; }; var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ }, leftMatch: {}, attrMap: { "class": "className", "for": "htmlFor" }, attrHandle: { href: function(elem){ return elem.getAttribute("href"); } }, relative: { "+": function(checkSet, part){ var isPartStr = typeof part === "string", isTag = isPartStr && !/\W/.test(part), isPartStrNotTag = isPartStr && !isTag; if ( isTag ) { part = part.toLowerCase(); } for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { if ( (elem = checkSet[i]) ) { while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? elem || false : elem === part; } } if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function(checkSet, part){ var isPartStr = typeof part === "string"; if ( isPartStr && !/\W/.test(part) ) { part = part.toLowerCase(); for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; } } } else { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } }, "": function(checkSet, part, isXML){ var doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !/\W/.test(part) ) { var nodeCheck = part = part.toLowerCase(); checkFn = dirNodeCheck; } checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); }, "~": function(checkSet, part, isXML){ var doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !/\W/.test(part) ) { var nodeCheck = part = part.toLowerCase(); checkFn = dirNodeCheck; } checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); } }, find: { ID: function(match, context, isXML){ if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? [m] : []; } }, NAME: function(match, context){ if ( typeof context.getElementsByName !== "undefined" ) { var ret = [], results = context.getElementsByName(match[1]); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { ret.push( results[i] ); } } return ret.length === 0 ? null : ret; } }, TAG: function(match, context){ return context.getElementsByTagName(match[1]); } }, preFilter: { CLASS: function(match, curLoop, inplace, result, not, isXML){ match = " " + match[1].replace(/\\/g, "") + " "; if ( isXML ) { return match; } for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { if ( !inplace ) { result.push( elem ); } } else if ( inplace ) { curLoop[i] = false; } } } return false; }, ID: function(match){ return match[1].replace(/\\/g, ""); }, TAG: function(match, curLoop){ return match[1].toLowerCase(); }, CHILD: function(match){ if ( match[1] === "nth" ) { // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); // calculate the numbers (first)n+(last) including if they are negative match[2] = (test[1] + (test[2] || 1)) - 0; match[3] = test[3] - 0; } // TODO: Move to normal caching system match[0] = done++; return match; }, ATTR: function(match, curLoop, inplace, result, not, isXML){ var name = match[1].replace(/\\/g, ""); if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } if ( match[2] === "~=" ) { match[4] = " " + match[4] + " "; } return match; }, PSEUDO: function(match, curLoop, inplace, result, not){ if ( match[1] === "not" ) { // If we're dealing with a complex expression, or a simple one if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); if ( !inplace ) { result.push.apply( result, ret ); } return false; } } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, POS: function(match){ match.unshift( true ); return match; } }, filters: { enabled: function(elem){ return elem.disabled === false && elem.type !== "hidden"; }, disabled: function(elem){ return elem.disabled === true; }, checked: function(elem){ return elem.checked === true; }, selected: function(elem){ // Accessing this property makes selected-by-default // options in Safari work properly elem.parentNode.selectedIndex; return elem.selected === true; }, parent: function(elem){ return !!elem.firstChild; }, empty: function(elem){ return !elem.firstChild; }, has: function(elem, i, match){ return !!Sizzle( match[3], elem ).length; }, header: function(elem){ return /h\d/i.test( elem.nodeName ); }, text: function(elem){ return "text" === elem.type; }, radio: function(elem){ return "radio" === elem.type; }, checkbox: function(elem){ return "checkbox" === elem.type; }, file: function(elem){ return "file" === elem.type; }, password: function(elem){ return "password" === elem.type; }, submit: function(elem){ return "submit" === elem.type; }, image: function(elem){ return "image" === elem.type; }, reset: function(elem){ return "reset" === elem.type; }, button: function(elem){ return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; }, input: function(elem){ return /input|select|textarea|button/i.test(elem.nodeName); } }, setFilters: { first: function(elem, i){ return i === 0; }, last: function(elem, i, match, array){ return i === array.length - 1; }, even: function(elem, i){ return i % 2 === 0; }, odd: function(elem, i){ return i % 2 === 1; }, lt: function(elem, i, match){ return i < match[3] - 0; }, gt: function(elem, i, match){ return i > match[3] - 0; }, nth: function(elem, i, match){ return match[3] - 0 === i; }, eq: function(elem, i, match){ return match[3] - 0 === i; } }, filter: { PSEUDO: function(elem, match, i, array){ var name = match[1], filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; for ( var i = 0, l = not.length; i < l; i++ ) { if ( not[i] === elem ) { return false; } } return true; } else { Sizzle.error( "Syntax error, unrecognized expression: " + name ); } }, CHILD: function(elem, match){ var type = match[1], node = elem; switch (type) { case 'only': case 'first': while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) { return false; } } if ( type === "first" ) { return true; } node = elem; case 'last': while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) { return false; } } return true; case 'nth': var first = match[2], last = match[3]; if ( first === 1 && last === 0 ) { return true; } var doneName = match[0], parent = elem.parentNode; if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { var count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } parent.sizcache = doneName; } var diff = elem.nodeIndex - last; if ( first === 0 ) { return diff === 0; } else { return ( diff % first === 0 && diff / first >= 0 ); } } }, ID: function(elem, match){ return elem.nodeType === 1 && elem.getAttribute("id") === match; }, TAG: function(elem, match){ return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; }, CLASS: function(elem, match){ return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, ATTR: function(elem, match){ var name = match[1], result = Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : elem.getAttribute( name ), value = result + "", type = match[2], check = match[4]; return result == null ? type === "!=" : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value !== check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false; }, POS: function(elem, match, i, array){ var name = match[2], filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } } } }; var origPOS = Expr.match.POS; for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ return "\\" + (num - 0 + 1); })); } var makeArray = function(array, results) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { results.push.apply( results, array ); return results; } return array; }; // Perform a simple check to determine if the browser is capable of // converting a NodeList to an array using builtin methods. // Also verifies that the returned array holds DOM nodes // (which is not the case in the Blackberry browser) try { Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; // Provide a fallback method if it does not work } catch(e){ makeArray = function(array, results) { var ret = results || []; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); } else { if ( typeof array.length === "number" ) { for ( var i = 0, l = array.length; i < l; i++ ) { ret.push( array[i] ); } } else { for ( var i = 0; array[i]; i++ ) { ret.push( array[i] ); } } } return ret; }; } var sortOrder; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { if ( a == b ) { hasDuplicate = true; } return a.compareDocumentPosition ? -1 : 1; } var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } else if ( "sourceIndex" in document.documentElement ) { sortOrder = function( a, b ) { if ( !a.sourceIndex || !b.sourceIndex ) { if ( a == b ) { hasDuplicate = true; } return a.sourceIndex ? -1 : 1; } var ret = a.sourceIndex - b.sourceIndex; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } else if ( document.createRange ) { sortOrder = function( a, b ) { if ( !a.ownerDocument || !b.ownerDocument ) { if ( a == b ) { hasDuplicate = true; } return a.ownerDocument ? -1 : 1; } var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); aRange.setStart(a, 0); aRange.setEnd(a, 0); bRange.setStart(b, 0); bRange.setEnd(b, 0); var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } // Utility function for retreiving the text value of an array of DOM nodes function getText( elems ) { var ret = "", elem; for ( var i = 0; elems[i]; i++ ) { elem = elems[i]; // Get the text from text nodes and CDATA nodes if ( elem.nodeType === 3 || elem.nodeType === 4 ) { ret += elem.nodeValue; // Traverse everything else, except comment nodes } else if ( elem.nodeType !== 8 ) { ret += getText( elem.childNodes ); } } return ret; } // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ // We're going to inject a fake input element with a specified name var form = document.createElement("div"), id = "script" + (new Date).getTime(); form.innerHTML = ""; // Inject it into the root element, check its status, and remove it quickly var root = document.documentElement; root.insertBefore( form, root.firstChild ); // The workaround has to do additional checks after a getElementById // Which slows things down for other browsers (hence the branching) if ( document.getElementById( id ) ) { Expr.find.ID = function(match, context, isXML){ if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; } }; Expr.filter.ID = function(elem, match){ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); root = form = null; // release memory in IE })(); (function(){ // Check to see if the browser returns only elements // when doing getElementsByTagName("*") // Create a fake element var div = document.createElement("div"); div.appendChild( document.createComment("") ); // Make sure no comments are found if ( div.getElementsByTagName("*").length > 0 ) { Expr.find.TAG = function(match, context){ var results = context.getElementsByTagName(match[1]); // Filter out possible comments if ( match[1] === "*" ) { var tmp = []; for ( var i = 0; results[i]; i++ ) { if ( results[i].nodeType === 1 ) { tmp.push( results[i] ); } } results = tmp; } return results; }; } // Check to see if an attribute returns normalized href attributes div.innerHTML = ""; if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { Expr.attrHandle.href = function(elem){ return elem.getAttribute("href", 2); }; } div = null; // release memory in IE })(); if ( document.querySelectorAll ) { (function(){ var oldSizzle = Sizzle, div = document.createElement("div"); div.innerHTML = "

    "; // Safari can't handle uppercase or unicode characters when // in quirks mode. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } Sizzle = function(query, context, extra, seed){ context = context || document; // Only use querySelectorAll on non-XML documents // (ID selectors don't work in non-HTML documents) if ( !seed && context.nodeType === 9 && !isXML(context) ) { try { return makeArray( context.querySelectorAll(query), extra ); } catch(e){} } return oldSizzle(query, context, extra, seed); }; for ( var prop in oldSizzle ) { Sizzle[ prop ] = oldSizzle[ prop ]; } div = null; // release memory in IE })(); } (function(){ var div = document.createElement("div"); div.innerHTML = "
    "; // Opera can't find a second classname (in 9.6) // Also, make sure that getElementsByClassName actually exists if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { return; } // Safari caches class attributes, doesn't catch changes (in 3.2) div.lastChild.className = "e"; if ( div.getElementsByClassName("e").length === 1 ) { return; } Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function(match, context, isXML) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; div = null; // release memory in IE })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { elem = elem[dir]; var match = false; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ elem.sizcache = doneName; elem.sizset = i; } if ( elem.nodeName.toLowerCase() === cur ) { match = elem; break; } elem = elem[dir]; } checkSet[i] = match; } } } function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { elem = elem[dir]; var match = false; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { elem.sizcache = doneName; elem.sizset = i; } if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; break; } } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { match = elem; break; } } elem = elem[dir]; } checkSet[i] = match; } } } var contains = document.compareDocumentPosition ? function(a, b){ return !!(a.compareDocumentPosition(b) & 16); } : function(a, b){ return a !== b && (a.contains ? a.contains(b) : true); }; var isXML = function(elem){ // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; var posProcess = function(selector, context){ var tmpSet = [], later = "", match, root = context.nodeType ? [context] : context; // Position selectors must be done after the filter // And so must :not(positional) so we move all PSEUDOs to the end while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet ); } return Sizzle.filter( later, tmpSet ); }; // EXPOSE jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.filters; jQuery.unique = Sizzle.uniqueSort; jQuery.text = getText; jQuery.isXMLDoc = isXML; jQuery.contains = contains; return; window.Sizzle = Sizzle; })(); var runtil = /Until$/, rparentsprev = /^(?:parents|prevUntil|prevAll)/, // Note: This RegExp should be improved, or likely pulled from Sizzle rmultiselector = /,/, slice = Array.prototype.slice; // Implement the identical functionality for filter and not var winnow = function( elements, qualifier, keep ) { if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { return !!qualifier.call( elem, i, elem ) === keep; }); } else if ( qualifier.nodeType ) { return jQuery.grep(elements, function( elem, i ) { return (elem === qualifier) === keep; }); } else if ( typeof qualifier === "string" ) { var filtered = jQuery.grep(elements, function( elem ) { return elem.nodeType === 1; }); if ( isSimple.test( qualifier ) ) { return jQuery.filter(qualifier, filtered, !keep); } else { qualifier = jQuery.filter( qualifier, filtered ); } } return jQuery.grep(elements, function( elem, i ) { return (jQuery.inArray( elem, qualifier ) >= 0) === keep; }); }; jQuery.fn.extend({ find: function( selector ) { var ret = this.pushStack( "", "find", selector ), length = 0; for ( var i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique for ( var n = length; n < ret.length; n++ ) { for ( var r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; } } } } } return ret; }, has: function( target ) { var targets = jQuery( target ); return this.filter(function() { for ( var i = 0, l = targets.length; i < l; i++ ) { if ( jQuery.contains( this, targets[i] ) ) { return true; } } }); }, not: function( selector ) { return this.pushStack( winnow(this, selector, false), "not", selector); }, filter: function( selector ) { return this.pushStack( winnow(this, selector, true), "filter", selector ); }, is: function( selector ) { return !!selector && jQuery.filter( selector, this ).length > 0; }, closest: function( selectors, context ) { if ( jQuery.isArray( selectors ) ) { var ret = [], cur = this[0], match, matches = {}, selector; if ( cur && selectors.length ) { for ( var i = 0, l = selectors.length; i < l; i++ ) { selector = selectors[i]; if ( !matches[selector] ) { matches[selector] = jQuery.expr.match.POS.test( selector ) ? jQuery( selector, context || this.context ) : selector; } } while ( cur && cur.ownerDocument && cur !== context ) { for ( selector in matches ) { match = matches[selector]; if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { ret.push({ selector: selector, elem: cur }); delete matches[selector]; } } cur = cur.parentNode; } } return ret; } var pos = jQuery.expr.match.POS.test( selectors ) ? jQuery( selectors, context || this.context ) : null; return this.map(function( i, cur ) { while ( cur && cur.ownerDocument && cur !== context ) { if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) { return cur; } cur = cur.parentNode; } return null; }); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { if ( !elem || typeof elem === "string" ) { return jQuery.inArray( this[0], // If it receives a string, the selector is used // If it receives nothing, the siblings are used elem ? jQuery( elem ) : this.parent().children() ); } // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used elem.jquery ? elem[0] : elem, this ); }, add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context || this.context ) : jQuery.makeArray( selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? all : jQuery.unique( all ) ); }, andSelf: function() { return this.add( this.prevObject ); } }); // A painfully simple check to see if an element is disconnected // from a document (should be improved, where feasible). function isDisconnected( node ) { return !node || !node.parentNode || node.parentNode.nodeType === 11; } jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return jQuery.nth( elem, 2, "nextSibling" ); }, prev: function( elem ) { return jQuery.nth( elem, 2, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( elem.parentNode.firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : jQuery.makeArray( elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ); if ( !runtil.test( name ) ) { selector = until; } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); } ret = this.length > 1 ? jQuery.unique( ret ) : ret; if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { ret = ret.reverse(); } return this.pushStack( ret, name, slice.call(arguments).join(",") ); }; }); jQuery.extend({ filter: function( expr, elems, not ) { if ( not ) { expr = ":not(" + expr + ")"; } return jQuery.find.matches(expr, elems); }, dir: function( elem, dir, until ) { var matched = [], cur = elem[dir]; while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { matched.push( cur ); } cur = cur[dir]; } return matched; }, nth: function( cur, result, dir, elem ) { result = result || 1; var num = 0; for ( ; cur; cur = cur[dir] ) { if ( cur.nodeType === 1 && ++num === result ) { break; } } return cur; }, sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { r.push( n ); } } return r; } }); var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rleadingWhitespace = /^\s+/, rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g, rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i, rtagName = /<([\w:]+)/, rtbody = /"; }, wrapMap = { option: [ 1, "" ], legend: [ 1, "
    ", "
    " ], thead: [ 1, "", "
    " ], tr: [ 2, "", "
    " ], td: [ 3, "", "
    " ], col: [ 2, "", "
    " ], area: [ 1, "", "" ], _default: [ 0, "", "" ] }; wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; // IE can't serialize and