├── test └── example │ ├── __init__.py │ ├── urls.py │ ├── settings.py │ └── media │ └── js │ ├── jquery.scrollTo.js │ ├── sha1.lib.js │ ├── md5.lib.js │ └── jquery.form.js ├── REQUIREMENTS ├── MANIFEST.in ├── src └── djjsmin │ ├── __init__.py │ ├── utils.py │ └── commands.py ├── doc ├── markdoc.yaml └── wiki │ ├── settings.md │ └── index.md ├── .gitignore ├── UNLICENSE ├── setup.py ├── README.md └── distribute_setup.py /test/example/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /REQUIREMENTS: -------------------------------------------------------------------------------- 1 | django-boss>=0.3 2 | jsmin>=2.0.1 3 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include REQUIREMENTS 2 | include distribute_setup.py 3 | -------------------------------------------------------------------------------- /src/djjsmin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | __version__ = '0.2' 4 | 5 | -------------------------------------------------------------------------------- /doc/markdoc.yaml: -------------------------------------------------------------------------------- 1 | wiki-name: django-jsmin Documentation 2 | 3 | markdown: 4 | extensions: 5 | - codehilite 6 | - def_list 7 | - headerid 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pyc 3 | *.pyo 4 | .DS_Store 5 | MANIFEST 6 | build 7 | dist 8 | doc/.html 9 | doc/.tmp 10 | test/example/dev.db 11 | test/example/media/js/*.min.js 12 | -------------------------------------------------------------------------------- /test/example/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # Example: 9 | # (r'^example/', include('example.foo.urls')), 10 | 11 | # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 12 | # to INSTALLED_APPS to enable admin documentation: 13 | # (r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | # (r'^admin/', include(admin.site.urls)), 17 | ) 18 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import re 6 | 7 | from distribute_setup import use_setuptools; use_setuptools() 8 | from setuptools import setup, find_packages 9 | 10 | 11 | rel_file = lambda *args: os.path.join(os.path.dirname(os.path.abspath(__file__)), *args) 12 | 13 | def read_from(filename): 14 | fp = open(filename) 15 | try: 16 | return fp.read() 17 | finally: 18 | fp.close() 19 | 20 | def get_version(): 21 | data = read_from(rel_file('src', 'djjsmin', '__init__.py')) 22 | return re.search(r"__version__ = '([^']+)'", data).group(1) 23 | 24 | def get_requirements(): 25 | data = read_from(rel_file('REQUIREMENTS')) 26 | lines = map(lambda s: s.strip(), data.splitlines()) 27 | return filter(None, lines) 28 | 29 | 30 | setup( 31 | name = 'django-jsmin', 32 | version = get_version(), 33 | author = "Zachary Voase", 34 | author_email = "zacharyvoase@me.com", 35 | url = 'http://github.com/zacharyvoase/django-jsmin', 36 | description = "JavaScript library minification for Django.", 37 | packages = find_packages(where='src'), 38 | package_dir = {'': 'src'}, 39 | install_requires = get_requirements(), 40 | ) 41 | -------------------------------------------------------------------------------- /test/example/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for example project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | ('Zachary Voase', 'zacharyvoase@me.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASE_ENGINE = 'sqlite3' 13 | DATABASE_NAME = 'dev.db' 14 | DATABASE_USER = '' 15 | DATABASE_PASSWORD = '' 16 | DATABASE_HOST = '' 17 | DATABASE_PORT = '' 18 | TIME_ZONE = 'America/Chicago' 19 | LANGUAGE_CODE = 'en-us' 20 | SITE_ID = 1 21 | USE_I18N = True 22 | MEDIA_ROOT = '' 23 | MEDIA_URL = '' 24 | ADMIN_MEDIA_PREFIX = '/media/' 25 | SECRET_KEY = '1(lnvq&ib1(a+=_%(6_)njg0^y$i*2t@e3#0wl1k)zehg*$nf$' 26 | TEMPLATE_LOADERS = ( 27 | 'django.template.loaders.filesystem.load_template_source', 28 | 'django.template.loaders.app_directories.load_template_source', 29 | # 'django.template.loaders.eggs.load_template_source', 30 | ) 31 | MIDDLEWARE_CLASSES = ( 32 | 'django.middleware.common.CommonMiddleware', 33 | 'django.contrib.sessions.middleware.SessionMiddleware', 34 | ) 35 | ROOT_URLCONF = 'example.urls' 36 | TEMPLATE_DIRS = ( 37 | ) 38 | 39 | INSTALLED_APPS = ( 40 | 'django.contrib.contenttypes', 41 | 'django.contrib.sessions', 42 | 'django.contrib.sites', 43 | 'djjsmin', 44 | ) 45 | 46 | JSMIN_INPUT = [ 47 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js', # jQuery framework 48 | 'media/js/jquery.*.js', # jQuery plugins 49 | 'media/js/*.lib.js', # Libraries 50 | ] 51 | 52 | JSMIN_OUTPUT = 'media/js/minified.min.js' 53 | 54 | 55 | import logging 56 | 57 | logging.root.setLevel(logging.DEBUG) 58 | handler = logging.StreamHandler() 59 | handler.setLevel(logging.DEBUG) 60 | logging.root.addHandler(handler) 61 | -------------------------------------------------------------------------------- /doc/wiki/settings.md: -------------------------------------------------------------------------------- 1 | # Settings 2 | 3 | There are a few settings which `django-jsmin` will use to figure out how to build your minified JavaScript library. 4 | 5 | `DEBUG` 6 | : If this is `True`, `django-jsmin` will not (by default) minify the output 7 | JS. This is to help with interactive debugging during development. It can be 8 | overridden with the options to the command-line interface; see the output of 9 | `djboss jsmin --help` for more information. 10 | 11 | `JSMIN_INPUT` (required) 12 | : A list of [glob][] patterns or URLs which `django-jsmin` will expand to get 13 | a list of JavaScript filenames. For example: 14 | 15 | [glob]: http://docs.python.org/library/glob.html 16 | 17 | JSMIN_INPUT = [ 18 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js', 19 | 'media/js/*.js', 20 | 'apps/*/js/*.js', 21 | ] 22 | 23 | First, the jQuery library is downloaded from Google’s servers. The second 24 | item will be expanded to get a list of the JS files in the `media/js/` 25 | directory. Then, any JS files in the `js/` sub-directory of each application 26 | will be included. Note that if a glob doesn’t match anything, it will just 27 | fail silently (by returning an empty list). 28 | 29 | All relative paths in globs are first resolved. `django-jsmin` will check 30 | for the following settings, in this order: 31 | 32 | * `JSMIN_ROOT` 33 | * `PROJECT_DIR` 34 | * `PROJECT_ROOT` 35 | 36 | Finally, if none exist, the directory containing the settings module will be 37 | considered the base path for resolution. 38 | 39 | `JSMIN_OUTPUT` (required) 40 | : The filename to which the minified JS data will be written. Relative output 41 | filenames will be resolved as specified above. 42 | 43 | `JSMIN_ROOT` (optional) 44 | : See the paragraph on relative glob resolution above. 45 | 46 | `JSMIN_PROLOG` (optional) 47 | : A filename (relative or absolute) which contains a piece of text to include 48 | at the beginning of the minified JS file. This will usually be a comment 49 | containing a copyright statement or license information. 50 | -------------------------------------------------------------------------------- /src/djjsmin/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | import os 5 | import tempfile 6 | import urllib2 7 | import urlparse 8 | 9 | 10 | LOG = logging.getLogger('django.djjsmin') 11 | 12 | 13 | ## workaround for Python pre-2.6. 14 | if not hasattr(os.path, 'relpath'): 15 | def relpath(path, start=os.path.curdir): 16 | """Return a relative version of a path""" 17 | 18 | if not path: 19 | raise ValueError("no path specified") 20 | 21 | start_list = os.path.abspath(start).split(os.path.sep) 22 | path_list = os.path.abspath(path).split(os.path.sep) 23 | 24 | # Work out how much of the filepath is shared by start and path. 25 | i = len(os.path.commonprefix([start_list, path_list])) 26 | 27 | rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] 28 | if not rel_list: 29 | return os.path.curdir 30 | return os.path.join(*rel_list) 31 | os.path.relpath = relpath 32 | 33 | 34 | def get_root(settings): 35 | """Get the directory from which to resolve the `JSMIN_INPUT` globs.""" 36 | 37 | if hasattr(settings, 'JSMIN_ROOT'): 38 | return settings.JSMIN_ROOT 39 | elif hasattr(settings, 'PROJECT_DIR'): 40 | return settings.PROJECT_DIR 41 | elif hasattr(settings, 'PROJECT_ROOT'): 42 | return settings.PROJECT_ROOT 43 | return os.path.dirname(os.path.abspath(settings.__file__)) 44 | 45 | 46 | def get_prolog(settings, root): 47 | """Get the prolog data from the `JSMIN_PROLOG` setting.""" 48 | 49 | if hasattr(settings, 'JSMIN_PROLOG'): 50 | filename = make_abs(settings.JSMIN_PROLOG, root) 51 | if not os.path.exists(filename): 52 | LOG.warn("Specified JSMIN_PROLOG does not exist, continuing anyway") 53 | else: 54 | return read_from(filename) 55 | return '' 56 | 57 | 58 | def make_abs(path, root): 59 | """Ensure a path is absolute.""" 60 | 61 | return path if os.path.isabs(path) else os.path.abspath(os.path.join(root, path)) 62 | 63 | 64 | def temp_fetch(url): 65 | """Fetch a URL and save it in a temporary file, returning the filename.""" 66 | 67 | conn = urllib2.urlopen(url) 68 | try: 69 | fp = tempfile.NamedTemporaryFile(delete=False) 70 | LOG.info("Saving %s to a temporary file" % truncate_url(url)) 71 | try: 72 | fp.write(conn.read()) 73 | finally: 74 | fp.close() 75 | finally: 76 | conn.close() 77 | 78 | LOG.info("Saved %s to %s" % (truncate_url(url), os.path.basename(fp.name))) 79 | return fp.name 80 | 81 | 82 | def truncate_url(url): 83 | """Return a short version of a URL.""" 84 | 85 | split = list(urlparse.urlsplit(url)) 86 | 87 | path = split[2] 88 | if path == '/' or path.count('/') <= 2: 89 | pass 90 | elif path.endswith('/'): 91 | split[2] = '/.../' + '/'.join(path.rsplit('/', 2)[-2:]) 92 | else: 93 | split[2] = '/.../' + path.rsplit('/', 1)[-1] 94 | 95 | return urlparse.urlunsplit(split) 96 | 97 | 98 | def read_from(filename): 99 | fp = open(filename) 100 | try: 101 | return fp.read() 102 | finally: 103 | fp.close() 104 | -------------------------------------------------------------------------------- /doc/wiki/index.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # `django-jsmin` Documentation 4 | 5 | `django-jsmin` is a reusable application for [Django][] which simplifies and automates the process of [minifying][] your JavaScript libraries. 6 | 7 | [django]: http://www.djangoproject.com/ 8 | [minifying]: http://www.crockford.com/javascript/jsmin.html 9 | 10 | 11 | ## Why Minify? 12 | 13 | Minified JS is usually much smaller than regular JS. Comments and whitespace are very helpful when developing JavaScript code, but in production they just take up valuable network bandwidth. The effects of minifying code could range from faster page load times to smaller bandwidth bills from your hosting provider. 14 | 15 | Minification can also obfuscate your code (making it difficult for third parties to copy), although effective obfuscation isn’t guaranteed, since it’s more of a side-effect of the minification process. 16 | 17 | 18 | ## Installation and Setup 19 | 20 | * Install the `django-jsmin` library: 21 | 22 | :::bash 23 | $ pip install django-jsmin # OR 24 | $ easy_install django-jsmin 25 | 26 | These commands will both install all the required dependencies. 27 | 28 | * Add `'djjsmin'` to your `INSTALLED_APPS` setting. 29 | 30 | * Add the necessary settings to your `settings.py` file: 31 | 32 | #!python 33 | JSMIN_ROOT = '/path/to/my/project/' 34 | 35 | # JSMIN_INPUT contains a list of all the input files and URLs. 36 | JSMIN_INPUT = [ 37 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js', 38 | 'media/js/jquery.*.js', # jQuery plugins 39 | 'media/js/*.src.js', # project-specific libraries 40 | ] 41 | 42 | JSMIN_OUTPUT = 'media/js/project.min.js' 43 | 44 | More information on the available settings can be found [here](/settings). 45 | 46 | 47 | ## `DEBUG` mode 48 | 49 | If `DEBUG` is set to `True` in your Django project when you run `django-jsmin`, 50 | the JavaScript files will only be concatenated to the output file, not 51 | compressed. This allows you to debug your code with meaningful line numbers 52 | during development, and then use the fully-minified version in production. You 53 | can force specific behaviour with options to the `djboss jsmin` command; see the 54 | output of `djboss jsmin --help` for more information. 55 | 56 | 57 | ## Usage 58 | 59 | `django-jsmin` uses [`django-boss`][djboss], a library/tool for writing and 60 | running Django management commands. This will be installed automatically by 61 | setuptools when you install `django-jsmin`. 62 | 63 | [djboss]: http://github.com/zacharyvoase/django-boss 64 | 65 | Usage is relatively simple: 66 | 67 | :::bash 68 | $ djboss --log-level DEBUG jsmin 69 | Saving http://ajax.googleapis.com/.../jquery.js to a temporary file 70 | Saved http://ajax.googleapis.com/.../jquery.js to tmpN7MAsi 71 | Reading tmpN7MAsi 72 | Reading media/js/jquery.plugin1.js 73 | Reading media/js/jquery.plugin2.js 74 | Reading media/js/app-specific.lib.js 75 | Writing to media/js/minified.min.js 76 | Cleaning temporary file tmpN7MAsi 77 | 78 | The JS file will be output to the filename given by the `JSMIN_OUTPUT` setting, in this case `media/js/minified.min.js`. 79 | 80 | 81 | ## License 82 | 83 | `django-jsmin` is licensed under the following MIT/X11-style license: 84 | 85 | > Copyright (c) 2009 Zachary Voase 86 | > 87 | > Permission is hereby granted, free of charge, to any person 88 | > obtaining a copy of this software and associated documentation 89 | > files (the "Software"), to deal in the Software without 90 | > restriction, including without limitation the rights to use, 91 | > copy, modify, merge, publish, distribute, sublicense, and/or sell 92 | > copies of the Software, and to permit persons to whom the 93 | > Software is furnished to do so, subject to the following 94 | > conditions: 95 | > 96 | > The above copyright notice and this permission notice shall be 97 | > included in all copies or substantial portions of the Software. 98 | > 99 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 100 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 101 | > OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 102 | > NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 103 | > HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 104 | > WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 105 | > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 106 | > OTHER DEALINGS IN THE SOFTWARE. 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `django-jsmin` 2 | 3 | `django-jsmin` is a reusable application for [Django][] which simplifies and automates the process of [minifying][] your JavaScript libraries. 4 | 5 | [django]: http://www.djangoproject.com/ 6 | [minifying]: http://www.crockford.com/javascript/jsmin.html 7 | 8 | 9 | ## Why Minify? 10 | 11 | Minified JS is usually much smaller than regular JS. Comments and whitespace are very helpful when developing JavaScript code, but in production they just take up valuable network bandwidth. The effects of minifying code could range from faster page load times to smaller bandwidth bills from your hosting provider. 12 | 13 | Minification can also obfuscate your code (making it difficult for third parties to copy), although effective obfuscation isn’t guaranteed, since it’s more of a side-effect of the minification process. 14 | 15 | 16 | ## Installation and Setup 17 | 18 | * Install the `django-jsmin` library: 19 | 20 | $ pip install django-jsmin # OR 21 | $ easy_install django-jsmin 22 | 23 | These commands will both install all the required dependencies. 24 | 25 | * Add `'djjsmin'` to your `INSTALLED_APPS` setting. 26 | 27 | * Add the necessary settings to your `settings.py` file: 28 | 29 | ## somewhere in settings.py 30 | JSMIN_ROOT = '/path/to/my/project/' 31 | 32 | # JSMIN_INPUT contains a list of all the input files and URLs. 33 | JSMIN_INPUT = [ 34 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js', 35 | 'media/js/jquery.*.js', # jQuery plugins 36 | 'media/js/*.src.js', # project-specific libraries 37 | ] 38 | 39 | JSMIN_OUTPUT = 'media/js/project.min.js' 40 | 41 | More information on the available settings can be found [here](http://github.com/zacharyvoase/django-jsmin/blob/master/doc/wiki/settings.md). 42 | 43 | 44 | ## `DEBUG` mode 45 | 46 | If `DEBUG` is set to `True` in your Django project when you run `django-jsmin`, 47 | the JavaScript files will only be concatenated to the output file, not 48 | compressed. This allows you to debug your code with meaningful line numbers 49 | during development, and then use the fully-minified version in production. You 50 | can force specific behaviour with options to the `djboss jsmin` command; see the 51 | output of `djboss jsmin --help` for more information. 52 | 53 | 54 | ## Usage 55 | 56 | `django-jsmin` uses [`django-boss`][djboss], a library/tool for writing and 57 | running Django management commands. This will be installed automatically by 58 | setuptools when you install `django-jsmin`. 59 | 60 | [djboss]: http://github.com/zacharyvoase/django-boss 61 | 62 | Usage is relatively simple: 63 | 64 | $ djboss --log-level DEBUG jsmin 65 | Saving http://ajax.googleapis.com/.../jquery.js to a temporary file 66 | Saved http://ajax.googleapis.com/.../jquery.js to tmpN7MAsi 67 | Reading tmpN7MAsi 68 | Reading media/js/jquery.plugin1.js 69 | Reading media/js/jquery.plugin2.js 70 | Reading media/js/app-specific.lib.js 71 | Writing to media/js/minified.min.js 72 | Cleaning temporary file tmpN7MAsi 73 | 74 | The JS file will be output to the filename given by the `JSMIN_OUTPUT` setting, in this case `media/js/minified.min.js`. 75 | 76 | 77 | ## (Un)license 78 | 79 | This is free and unencumbered software released into the public domain. 80 | 81 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 82 | software, either in source code form or as a compiled binary, for any purpose, 83 | commercial or non-commercial, and by any means. 84 | 85 | In jurisdictions that recognize copyright laws, the author or authors of this 86 | software dedicate any and all copyright interest in the software to the public 87 | domain. We make this dedication for the benefit of the public at large and to 88 | the detriment of our heirs and successors. We intend this dedication to be an 89 | overt act of relinquishment in perpetuity of all present and future rights to 90 | this software under copyright law. 91 | 92 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 93 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 94 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE 95 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 96 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 97 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 98 | 99 | For more information, please refer to 100 | -------------------------------------------------------------------------------- /src/djjsmin/commands.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from cStringIO import StringIO 4 | import glob 5 | import logging 6 | import os 7 | import os.path as p 8 | 9 | from django.core.exceptions import ImproperlyConfigured 10 | from djboss.commands import * 11 | import jsmin as libjsmin 12 | 13 | from djjsmin import utils 14 | 15 | 16 | LOG = logging.getLogger('django.djjsmin') 17 | 18 | 19 | def resolve_patterns(patterns, root): 20 | """Resolve a list of globs/URLs into absolute filenames.""" 21 | 22 | input_files, temp_files = [], [] 23 | 24 | for pattern in patterns: 25 | # Handle URLs in the JSMIN_INPUT setting. 26 | if pattern.startswith("http:"): 27 | temp_filename = utils.temp_fetch(pattern) 28 | input_files.append(temp_filename) 29 | temp_files.append(temp_filename) 30 | 31 | else: 32 | # Ensure glob patterns are absolute. 33 | glob_files = glob.glob(utils.make_abs(pattern, root)) 34 | # Sort filenames within the results of a single pattern. 35 | glob_files.sort() 36 | 37 | for filename in glob_files: 38 | # Make sure there are no repetitions. 39 | if filename not in input_files: 40 | input_files.append(filename) 41 | 42 | return input_files, temp_files 43 | 44 | 45 | @command 46 | @argument('-d', '--dev-mode', action='store_true', default=None, dest='development_mode', 47 | help="Don't minify (just concatenate). Defaults to the value of DEBUG.") 48 | @argument('-p', '--prod-mode', action='store_false', dest='development_mode', 49 | help="Minify, even when DEBUG is True.") 50 | def jsmin(args): 51 | """Minify the configured JavaScript libraries.""" 52 | 53 | if not hasattr(args.settings, 'JSMIN_INPUT'): 54 | raise ImproperlyConfigured("Must provide a JSMIN_INPUT setting") 55 | elif not hasattr(args.settings, 'JSMIN_OUTPUT'): 56 | raise ImproperlyConfigured("Must provide a JSMIN_OUTPUT setting") 57 | 58 | root = utils.get_root(args.settings) 59 | 60 | # Set up development mode. If nothing is specified, this will default to the 61 | # value of `settings.DEBUG`. The `-d` and `-p` options override this value. 62 | if args.development_mode is None: 63 | development_mode = args.settings.DEBUG 64 | else: 65 | development_mode = args.development_mode 66 | 67 | # `temp_files` have to be deleted after processing, whether minification was 68 | # successful or not. 69 | input_files, temp_files = resolve_patterns(args.settings.JSMIN_INPUT, root) 70 | 71 | try: 72 | # Get an absolute output filename. 73 | output_file = utils.make_abs(args.settings.JSMIN_OUTPUT, root) 74 | 75 | if output_file in input_files: 76 | # This can happen if you output a '.js' file to the same directory 77 | # you're reading from. Remove it from the input files. 78 | input_files.remove(output_file) 79 | 80 | input_io = StringIO() 81 | try: 82 | # Populate the input StringIO. 83 | for filename in input_files: 84 | if filename in temp_files: 85 | LOG.info("Reading %s" % p.basename(filename)) 86 | else: 87 | LOG.info("Reading %s" % p.relpath(filename)) 88 | 89 | # The additional whitespace/comments will be filtered out by the 90 | # minifier later on, unless we are in development mode, in which 91 | # case we want the whitespace and comments. 92 | input_io.write("/* FILE: %s */" % filename + os.linesep) 93 | input_io.write(utils.read_from(filename)) 94 | input_io.write(os.linesep * 2) 95 | input_io.seek(0) 96 | 97 | output_io = open(output_file, 'w') 98 | try: 99 | output_io.write(utils.get_prolog(args.settings, root)) 100 | 101 | if development_mode: 102 | LOG.info("Writing to %s" % p.relpath(output_file)) 103 | output_io.write(input_io.getvalue()) 104 | else: 105 | # Minify and write the output. 106 | LOG.info("Minifying and writing to %s" % p.relpath(output_file)) 107 | libjsmin.JavascriptMinify(input_io, output_io).minify() 108 | finally: 109 | output_io.close() # Clean up. 110 | finally: 111 | input_io.close() # Clean up. 112 | 113 | finally: 114 | # Clean up. 115 | for temp_filename in temp_files: 116 | LOG.info("Cleaning temporary file %s" % p.basename(temp_filename)) 117 | os.remove(temp_filename) 118 | -------------------------------------------------------------------------------- /test/example/media/js/jquery.scrollTo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery.ScrollTo 3 | * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com 4 | * Dual licensed under MIT and GPL. 5 | * Date: 5/25/2009 6 | * 7 | * @projectDescription Easy element scrolling using jQuery. 8 | * http://flesler.blogspot.com/2007/10/jqueryscrollto.html 9 | * Works with jQuery +1.2.6. Tested on FF 2/3, IE 6/7/8, Opera 9.5/6, Safari 3, Chrome 1 on WinXP. 10 | * 11 | * @author Ariel Flesler 12 | * @version 1.4.2 13 | * 14 | * @id jQuery.scrollTo 15 | * @id jQuery.fn.scrollTo 16 | * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements. 17 | * The different options for target are: 18 | * - A number position (will be applied to all axes). 19 | * - A string position ('44', '100px', '+=90', etc ) will be applied to all axes 20 | * - A jQuery/DOM element ( logically, child of the element to scroll ) 21 | * - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc ) 22 | * - A hash { top:x, left:y }, x and y can be any kind of number/string like above. 23 | * - A percentage of the container's dimension/s, for example: 50% to go to the middle. 24 | * - The string 'max' for go-to-end. 25 | * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead. 26 | * @param {Object,Function} settings Optional set of settings or the onAfter callback. 27 | * @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'. 28 | * @option {Number} duration The OVERALL length of the animation. 29 | * @option {String} easing The easing method for the animation. 30 | * @option {Boolean} margin If true, the margin of the target element will be deducted from the final position. 31 | * @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }. 32 | * @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes. 33 | * @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends. 34 | * @option {Function} onAfter Function to be called after the scrolling ends. 35 | * @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends. 36 | * @return {jQuery} Returns the same jQuery object, for chaining. 37 | * 38 | * @desc Scroll to a fixed position 39 | * @example $('div').scrollTo( 340 ); 40 | * 41 | * @desc Scroll relatively to the actual position 42 | * @example $('div').scrollTo( '+=340px', { axis:'y' } ); 43 | * 44 | * @dec Scroll using a selector (relative to the scrolled element) 45 | * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } ); 46 | * 47 | * @ Scroll to a DOM element (same for jQuery object) 48 | * @example var second_child = document.getElementById('container').firstChild.nextSibling; 49 | * $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){ 50 | * alert('scrolled!!'); 51 | * }}); 52 | * 53 | * @desc Scroll on both axes, to different values 54 | * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } ); 55 | */ 56 | ;(function( $ ){ 57 | 58 | var $scrollTo = $.scrollTo = function( target, duration, settings ){ 59 | $(window).scrollTo( target, duration, settings ); 60 | }; 61 | 62 | $scrollTo.defaults = { 63 | axis:'xy', 64 | duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1 65 | }; 66 | 67 | // Returns the element that needs to be animated to scroll the window. 68 | // Kept for backwards compatibility (specially for localScroll & serialScroll) 69 | $scrollTo.window = function( scope ){ 70 | return $(window)._scrollable(); 71 | }; 72 | 73 | // Hack, hack, hack :) 74 | // Returns the real elements to scroll (supports window/iframes, documents and regular nodes) 75 | $.fn._scrollable = function(){ 76 | return this.map(function(){ 77 | var elem = this, 78 | isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1; 79 | 80 | if( !isWin ) 81 | return elem; 82 | 83 | var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem; 84 | 85 | return $.browser.safari || doc.compatMode == 'BackCompat' ? 86 | doc.body : 87 | doc.documentElement; 88 | }); 89 | }; 90 | 91 | $.fn.scrollTo = function( target, duration, settings ){ 92 | if( typeof duration == 'object' ){ 93 | settings = duration; 94 | duration = 0; 95 | } 96 | if( typeof settings == 'function' ) 97 | settings = { onAfter:settings }; 98 | 99 | if( target == 'max' ) 100 | target = 9e9; 101 | 102 | settings = $.extend( {}, $scrollTo.defaults, settings ); 103 | // Speed is still recognized for backwards compatibility 104 | duration = duration || settings.speed || settings.duration; 105 | // Make sure the settings are given right 106 | settings.queue = settings.queue && settings.axis.length > 1; 107 | 108 | if( settings.queue ) 109 | // Let's keep the overall duration 110 | duration /= 2; 111 | settings.offset = both( settings.offset ); 112 | settings.over = both( settings.over ); 113 | 114 | return this._scrollable().each(function(){ 115 | var elem = this, 116 | $elem = $(elem), 117 | targ = target, toff, attr = {}, 118 | win = $elem.is('html,body'); 119 | 120 | switch( typeof targ ){ 121 | // A number will pass the regex 122 | case 'number': 123 | case 'string': 124 | if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){ 125 | targ = both( targ ); 126 | // We are done 127 | break; 128 | } 129 | // Relative selector, no break! 130 | targ = $(targ,this); 131 | case 'object': 132 | // DOMElement / jQuery 133 | if( targ.is || targ.style ) 134 | // Get the real position of the target 135 | toff = (targ = $(targ)).offset(); 136 | } 137 | $.each( settings.axis.split(''), function( i, axis ){ 138 | var Pos = axis == 'x' ? 'Left' : 'Top', 139 | pos = Pos.toLowerCase(), 140 | key = 'scroll' + Pos, 141 | old = elem[key], 142 | max = $scrollTo.max(elem, axis); 143 | 144 | if( toff ){// jQuery / DOMElement 145 | attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] ); 146 | 147 | // If it's a dom element, reduce the margin 148 | if( settings.margin ){ 149 | attr[key] -= parseInt(targ.css('margin'+Pos)) || 0; 150 | attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0; 151 | } 152 | 153 | attr[key] += settings.offset[pos] || 0; 154 | 155 | if( settings.over[pos] ) 156 | // Scroll to a fraction of its width/height 157 | attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos]; 158 | }else{ 159 | var val = targ[pos]; 160 | // Handle percentage values 161 | attr[key] = val.slice && val.slice(-1) == '%' ? 162 | parseFloat(val) / 100 * max 163 | : val; 164 | } 165 | 166 | // Number or 'number' 167 | if( /^\d+$/.test(attr[key]) ) 168 | // Check the limits 169 | attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max ); 170 | 171 | // Queueing axes 172 | if( !i && settings.queue ){ 173 | // Don't waste time animating, if there's no need. 174 | if( old != attr[key] ) 175 | // Intermediate animation 176 | animate( settings.onAfterFirst ); 177 | // Don't animate this axis again in the next iteration. 178 | delete attr[key]; 179 | } 180 | }); 181 | 182 | animate( settings.onAfter ); 183 | 184 | function animate( callback ){ 185 | $elem.animate( attr, duration, settings.easing, callback && function(){ 186 | callback.call(this, target, settings); 187 | }); 188 | }; 189 | 190 | }).end(); 191 | }; 192 | 193 | // Max scrolling position, works on quirks mode 194 | // It only fails (not too badly) on IE, quirks mode. 195 | $scrollTo.max = function( elem, axis ){ 196 | var Dim = axis == 'x' ? 'Width' : 'Height', 197 | scroll = 'scroll'+Dim; 198 | 199 | if( !$(elem).is('html,body') ) 200 | return elem[scroll] - $(elem)[Dim.toLowerCase()](); 201 | 202 | var size = 'client' + Dim, 203 | html = elem.ownerDocument.documentElement, 204 | body = elem.ownerDocument.body; 205 | 206 | return Math.max( html[scroll], body[scroll] ) 207 | - Math.min( html[size] , body[size] ); 208 | 209 | }; 210 | 211 | function both( val ){ 212 | return typeof val == 'object' ? val : { top:val, left:val }; 213 | }; 214 | 215 | })( jQuery ); -------------------------------------------------------------------------------- /test/example/media/js/sha1.lib.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined 3 | * in FIPS 180-1 4 | * Version 2.2 Copyright Paul Johnston 2000 - 2009. 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for details. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ 16 | 17 | /* 18 | * These are the functions you'll usually want to call 19 | * They take string arguments and return either hex or base-64 encoded strings 20 | */ 21 | function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); } 22 | function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); } 23 | function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); } 24 | function hex_hmac_sha1(k, d) 25 | { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); } 26 | function b64_hmac_sha1(k, d) 27 | { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); } 28 | function any_hmac_sha1(k, d, e) 29 | { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); } 30 | 31 | /* 32 | * Perform a simple self-test to see if the VM is working 33 | */ 34 | function sha1_vm_test() 35 | { 36 | return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d"; 37 | } 38 | 39 | /* 40 | * Calculate the SHA1 of a raw string 41 | */ 42 | function rstr_sha1(s) 43 | { 44 | return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8)); 45 | } 46 | 47 | /* 48 | * Calculate the HMAC-SHA1 of a key and some data (raw strings) 49 | */ 50 | function rstr_hmac_sha1(key, data) 51 | { 52 | var bkey = rstr2binb(key); 53 | if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8); 54 | 55 | var ipad = Array(16), opad = Array(16); 56 | for(var i = 0; i < 16; i++) 57 | { 58 | ipad[i] = bkey[i] ^ 0x36363636; 59 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 60 | } 61 | 62 | var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8); 63 | return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160)); 64 | } 65 | 66 | /* 67 | * Convert a raw string to a hex string 68 | */ 69 | function rstr2hex(input) 70 | { 71 | try { hexcase } catch(e) { hexcase=0; } 72 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 73 | var output = ""; 74 | var x; 75 | for(var i = 0; i < input.length; i++) 76 | { 77 | x = input.charCodeAt(i); 78 | output += hex_tab.charAt((x >>> 4) & 0x0F) 79 | + hex_tab.charAt( x & 0x0F); 80 | } 81 | return output; 82 | } 83 | 84 | /* 85 | * Convert a raw string to a base-64 string 86 | */ 87 | function rstr2b64(input) 88 | { 89 | try { b64pad } catch(e) { b64pad=''; } 90 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 91 | var output = ""; 92 | var len = input.length; 93 | for(var i = 0; i < len; i += 3) 94 | { 95 | var triplet = (input.charCodeAt(i) << 16) 96 | | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) 97 | | (i + 2 < len ? input.charCodeAt(i+2) : 0); 98 | for(var j = 0; j < 4; j++) 99 | { 100 | if(i * 8 + j * 6 > input.length * 8) output += b64pad; 101 | else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); 102 | } 103 | } 104 | return output; 105 | } 106 | 107 | /* 108 | * Convert a raw string to an arbitrary string encoding 109 | */ 110 | function rstr2any(input, encoding) 111 | { 112 | var divisor = encoding.length; 113 | var remainders = Array(); 114 | var i, q, x, quotient; 115 | 116 | /* Convert to an array of 16-bit big-endian values, forming the dividend */ 117 | var dividend = Array(Math.ceil(input.length / 2)); 118 | for(i = 0; i < dividend.length; i++) 119 | { 120 | dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); 121 | } 122 | 123 | /* 124 | * Repeatedly perform a long division. The binary array forms the dividend, 125 | * the length of the encoding is the divisor. Once computed, the quotient 126 | * forms the dividend for the next step. We stop when the dividend is zero. 127 | * All remainders are stored for later use. 128 | */ 129 | while(dividend.length > 0) 130 | { 131 | quotient = Array(); 132 | x = 0; 133 | for(i = 0; i < dividend.length; i++) 134 | { 135 | x = (x << 16) + dividend[i]; 136 | q = Math.floor(x / divisor); 137 | x -= q * divisor; 138 | if(quotient.length > 0 || q > 0) 139 | quotient[quotient.length] = q; 140 | } 141 | remainders[remainders.length] = x; 142 | dividend = quotient; 143 | } 144 | 145 | /* Convert the remainders to the output string */ 146 | var output = ""; 147 | for(i = remainders.length - 1; i >= 0; i--) 148 | output += encoding.charAt(remainders[i]); 149 | 150 | /* Append leading zero equivalents */ 151 | var full_length = Math.ceil(input.length * 8 / 152 | (Math.log(encoding.length) / Math.log(2))) 153 | for(i = output.length; i < full_length; i++) 154 | output = encoding[0] + output; 155 | 156 | return output; 157 | } 158 | 159 | /* 160 | * Encode a string as utf-8. 161 | * For efficiency, this assumes the input is valid utf-16. 162 | */ 163 | function str2rstr_utf8(input) 164 | { 165 | var output = ""; 166 | var i = -1; 167 | var x, y; 168 | 169 | while(++i < input.length) 170 | { 171 | /* Decode utf-16 surrogate pairs */ 172 | x = input.charCodeAt(i); 173 | y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; 174 | if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) 175 | { 176 | x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); 177 | i++; 178 | } 179 | 180 | /* Encode output as utf-8 */ 181 | if(x <= 0x7F) 182 | output += String.fromCharCode(x); 183 | else if(x <= 0x7FF) 184 | output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), 185 | 0x80 | ( x & 0x3F)); 186 | else if(x <= 0xFFFF) 187 | output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), 188 | 0x80 | ((x >>> 6 ) & 0x3F), 189 | 0x80 | ( x & 0x3F)); 190 | else if(x <= 0x1FFFFF) 191 | output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), 192 | 0x80 | ((x >>> 12) & 0x3F), 193 | 0x80 | ((x >>> 6 ) & 0x3F), 194 | 0x80 | ( x & 0x3F)); 195 | } 196 | return output; 197 | } 198 | 199 | /* 200 | * Encode a string as utf-16 201 | */ 202 | function str2rstr_utf16le(input) 203 | { 204 | var output = ""; 205 | for(var i = 0; i < input.length; i++) 206 | output += String.fromCharCode( input.charCodeAt(i) & 0xFF, 207 | (input.charCodeAt(i) >>> 8) & 0xFF); 208 | return output; 209 | } 210 | 211 | function str2rstr_utf16be(input) 212 | { 213 | var output = ""; 214 | for(var i = 0; i < input.length; i++) 215 | output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, 216 | input.charCodeAt(i) & 0xFF); 217 | return output; 218 | } 219 | 220 | /* 221 | * Convert a raw string to an array of big-endian words 222 | * Characters >255 have their high-byte silently ignored. 223 | */ 224 | function rstr2binb(input) 225 | { 226 | var output = Array(input.length >> 2); 227 | for(var i = 0; i < output.length; i++) 228 | output[i] = 0; 229 | for(var i = 0; i < input.length * 8; i += 8) 230 | output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); 231 | return output; 232 | } 233 | 234 | /* 235 | * Convert an array of big-endian words to a string 236 | */ 237 | function binb2rstr(input) 238 | { 239 | var output = ""; 240 | for(var i = 0; i < input.length * 32; i += 8) 241 | output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF); 242 | return output; 243 | } 244 | 245 | /* 246 | * Calculate the SHA-1 of an array of big-endian words, and a bit length 247 | */ 248 | function binb_sha1(x, len) 249 | { 250 | /* append padding */ 251 | x[len >> 5] |= 0x80 << (24 - len % 32); 252 | x[((len + 64 >> 9) << 4) + 15] = len; 253 | 254 | var w = Array(80); 255 | var a = 1732584193; 256 | var b = -271733879; 257 | var c = -1732584194; 258 | var d = 271733878; 259 | var e = -1009589776; 260 | 261 | for(var i = 0; i < x.length; i += 16) 262 | { 263 | var olda = a; 264 | var oldb = b; 265 | var oldc = c; 266 | var oldd = d; 267 | var olde = e; 268 | 269 | for(var j = 0; j < 80; j++) 270 | { 271 | if(j < 16) w[j] = x[i + j]; 272 | else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); 273 | var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), 274 | safe_add(safe_add(e, w[j]), sha1_kt(j))); 275 | e = d; 276 | d = c; 277 | c = bit_rol(b, 30); 278 | b = a; 279 | a = t; 280 | } 281 | 282 | a = safe_add(a, olda); 283 | b = safe_add(b, oldb); 284 | c = safe_add(c, oldc); 285 | d = safe_add(d, oldd); 286 | e = safe_add(e, olde); 287 | } 288 | return Array(a, b, c, d, e); 289 | 290 | } 291 | 292 | /* 293 | * Perform the appropriate triplet combination function for the current 294 | * iteration 295 | */ 296 | function sha1_ft(t, b, c, d) 297 | { 298 | if(t < 20) return (b & c) | ((~b) & d); 299 | if(t < 40) return b ^ c ^ d; 300 | if(t < 60) return (b & c) | (b & d) | (c & d); 301 | return b ^ c ^ d; 302 | } 303 | 304 | /* 305 | * Determine the appropriate additive constant for the current iteration 306 | */ 307 | function sha1_kt(t) 308 | { 309 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : 310 | (t < 60) ? -1894007588 : -899497514; 311 | } 312 | 313 | /* 314 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 315 | * to work around bugs in some JS interpreters. 316 | */ 317 | function safe_add(x, y) 318 | { 319 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 320 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 321 | return (msw << 16) | (lsw & 0xFFFF); 322 | } 323 | 324 | /* 325 | * Bitwise rotate a 32-bit number to the left. 326 | */ 327 | function bit_rol(num, cnt) 328 | { 329 | return (num << cnt) | (num >>> (32 - cnt)); 330 | } 331 | -------------------------------------------------------------------------------- /test/example/media/js/md5.lib.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 3 | * Digest Algorithm, as defined in RFC 1321. 4 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for more info. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ 16 | 17 | /* 18 | * These are the functions you'll usually want to call 19 | * They take string arguments and return either hex or base-64 encoded strings 20 | */ 21 | function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); } 22 | function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); } 23 | function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); } 24 | function hex_hmac_md5(k, d) 25 | { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } 26 | function b64_hmac_md5(k, d) 27 | { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } 28 | function any_hmac_md5(k, d, e) 29 | { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); } 30 | 31 | /* 32 | * Perform a simple self-test to see if the VM is working 33 | */ 34 | function md5_vm_test() 35 | { 36 | return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72"; 37 | } 38 | 39 | /* 40 | * Calculate the MD5 of a raw string 41 | */ 42 | function rstr_md5(s) 43 | { 44 | return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); 45 | } 46 | 47 | /* 48 | * Calculate the HMAC-MD5, of a key and some data (raw strings) 49 | */ 50 | function rstr_hmac_md5(key, data) 51 | { 52 | var bkey = rstr2binl(key); 53 | if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); 54 | 55 | var ipad = Array(16), opad = Array(16); 56 | for(var i = 0; i < 16; i++) 57 | { 58 | ipad[i] = bkey[i] ^ 0x36363636; 59 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 60 | } 61 | 62 | var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); 63 | return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); 64 | } 65 | 66 | /* 67 | * Convert a raw string to a hex string 68 | */ 69 | function rstr2hex(input) 70 | { 71 | try { hexcase } catch(e) { hexcase=0; } 72 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 73 | var output = ""; 74 | var x; 75 | for(var i = 0; i < input.length; i++) 76 | { 77 | x = input.charCodeAt(i); 78 | output += hex_tab.charAt((x >>> 4) & 0x0F) 79 | + hex_tab.charAt( x & 0x0F); 80 | } 81 | return output; 82 | } 83 | 84 | /* 85 | * Convert a raw string to a base-64 string 86 | */ 87 | function rstr2b64(input) 88 | { 89 | try { b64pad } catch(e) { b64pad=''; } 90 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 91 | var output = ""; 92 | var len = input.length; 93 | for(var i = 0; i < len; i += 3) 94 | { 95 | var triplet = (input.charCodeAt(i) << 16) 96 | | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) 97 | | (i + 2 < len ? input.charCodeAt(i+2) : 0); 98 | for(var j = 0; j < 4; j++) 99 | { 100 | if(i * 8 + j * 6 > input.length * 8) output += b64pad; 101 | else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); 102 | } 103 | } 104 | return output; 105 | } 106 | 107 | /* 108 | * Convert a raw string to an arbitrary string encoding 109 | */ 110 | function rstr2any(input, encoding) 111 | { 112 | var divisor = encoding.length; 113 | var i, j, q, x, quotient; 114 | 115 | /* Convert to an array of 16-bit big-endian values, forming the dividend */ 116 | var dividend = Array(Math.ceil(input.length / 2)); 117 | for(i = 0; i < dividend.length; i++) 118 | { 119 | dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); 120 | } 121 | 122 | /* 123 | * Repeatedly perform a long division. The binary array forms the dividend, 124 | * the length of the encoding is the divisor. Once computed, the quotient 125 | * forms the dividend for the next step. All remainders are stored for later 126 | * use. 127 | */ 128 | var full_length = Math.ceil(input.length * 8 / 129 | (Math.log(encoding.length) / Math.log(2))); 130 | var remainders = Array(full_length); 131 | for(j = 0; j < full_length; j++) 132 | { 133 | quotient = Array(); 134 | x = 0; 135 | for(i = 0; i < dividend.length; i++) 136 | { 137 | x = (x << 16) + dividend[i]; 138 | q = Math.floor(x / divisor); 139 | x -= q * divisor; 140 | if(quotient.length > 0 || q > 0) 141 | quotient[quotient.length] = q; 142 | } 143 | remainders[j] = x; 144 | dividend = quotient; 145 | } 146 | 147 | /* Convert the remainders to the output string */ 148 | var output = ""; 149 | for(i = remainders.length - 1; i >= 0; i--) 150 | output += encoding.charAt(remainders[i]); 151 | 152 | return output; 153 | } 154 | 155 | /* 156 | * Encode a string as utf-8. 157 | * For efficiency, this assumes the input is valid utf-16. 158 | */ 159 | function str2rstr_utf8(input) 160 | { 161 | var output = ""; 162 | var i = -1; 163 | var x, y; 164 | 165 | while(++i < input.length) 166 | { 167 | /* Decode utf-16 surrogate pairs */ 168 | x = input.charCodeAt(i); 169 | y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; 170 | if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) 171 | { 172 | x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); 173 | i++; 174 | } 175 | 176 | /* Encode output as utf-8 */ 177 | if(x <= 0x7F) 178 | output += String.fromCharCode(x); 179 | else if(x <= 0x7FF) 180 | output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), 181 | 0x80 | ( x & 0x3F)); 182 | else if(x <= 0xFFFF) 183 | output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), 184 | 0x80 | ((x >>> 6 ) & 0x3F), 185 | 0x80 | ( x & 0x3F)); 186 | else if(x <= 0x1FFFFF) 187 | output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), 188 | 0x80 | ((x >>> 12) & 0x3F), 189 | 0x80 | ((x >>> 6 ) & 0x3F), 190 | 0x80 | ( x & 0x3F)); 191 | } 192 | return output; 193 | } 194 | 195 | /* 196 | * Encode a string as utf-16 197 | */ 198 | function str2rstr_utf16le(input) 199 | { 200 | var output = ""; 201 | for(var i = 0; i < input.length; i++) 202 | output += String.fromCharCode( input.charCodeAt(i) & 0xFF, 203 | (input.charCodeAt(i) >>> 8) & 0xFF); 204 | return output; 205 | } 206 | 207 | function str2rstr_utf16be(input) 208 | { 209 | var output = ""; 210 | for(var i = 0; i < input.length; i++) 211 | output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, 212 | input.charCodeAt(i) & 0xFF); 213 | return output; 214 | } 215 | 216 | /* 217 | * Convert a raw string to an array of little-endian words 218 | * Characters >255 have their high-byte silently ignored. 219 | */ 220 | function rstr2binl(input) 221 | { 222 | var output = Array(input.length >> 2); 223 | for(var i = 0; i < output.length; i++) 224 | output[i] = 0; 225 | for(var i = 0; i < input.length * 8; i += 8) 226 | output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32); 227 | return output; 228 | } 229 | 230 | /* 231 | * Convert an array of little-endian words to a string 232 | */ 233 | function binl2rstr(input) 234 | { 235 | var output = ""; 236 | for(var i = 0; i < input.length * 32; i += 8) 237 | output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF); 238 | return output; 239 | } 240 | 241 | /* 242 | * Calculate the MD5 of an array of little-endian words, and a bit length. 243 | */ 244 | function binl_md5(x, len) 245 | { 246 | /* append padding */ 247 | x[len >> 5] |= 0x80 << ((len) % 32); 248 | x[(((len + 64) >>> 9) << 4) + 14] = len; 249 | 250 | var a = 1732584193; 251 | var b = -271733879; 252 | var c = -1732584194; 253 | var d = 271733878; 254 | 255 | for(var i = 0; i < x.length; i += 16) 256 | { 257 | var olda = a; 258 | var oldb = b; 259 | var oldc = c; 260 | var oldd = d; 261 | 262 | a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); 263 | d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); 264 | c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); 265 | b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); 266 | a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); 267 | d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); 268 | c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); 269 | b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); 270 | a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); 271 | d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); 272 | c = md5_ff(c, d, a, b, x[i+10], 17, -42063); 273 | b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); 274 | a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); 275 | d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); 276 | c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); 277 | b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); 278 | 279 | a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); 280 | d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); 281 | c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); 282 | b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); 283 | a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); 284 | d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); 285 | c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); 286 | b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); 287 | a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); 288 | d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); 289 | c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); 290 | b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); 291 | a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); 292 | d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); 293 | c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); 294 | b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); 295 | 296 | a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); 297 | d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); 298 | c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); 299 | b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); 300 | a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); 301 | d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); 302 | c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); 303 | b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); 304 | a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); 305 | d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); 306 | c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); 307 | b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); 308 | a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); 309 | d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); 310 | c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); 311 | b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); 312 | 313 | a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); 314 | d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); 315 | c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); 316 | b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); 317 | a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); 318 | d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); 319 | c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); 320 | b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); 321 | a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); 322 | d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); 323 | c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); 324 | b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); 325 | a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); 326 | d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); 327 | c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); 328 | b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); 329 | 330 | a = safe_add(a, olda); 331 | b = safe_add(b, oldb); 332 | c = safe_add(c, oldc); 333 | d = safe_add(d, oldd); 334 | } 335 | return Array(a, b, c, d); 336 | } 337 | 338 | /* 339 | * These functions implement the four basic operations the algorithm uses. 340 | */ 341 | function md5_cmn(q, a, b, x, s, t) 342 | { 343 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); 344 | } 345 | function md5_ff(a, b, c, d, x, s, t) 346 | { 347 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); 348 | } 349 | function md5_gg(a, b, c, d, x, s, t) 350 | { 351 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); 352 | } 353 | function md5_hh(a, b, c, d, x, s, t) 354 | { 355 | return md5_cmn(b ^ c ^ d, a, b, x, s, t); 356 | } 357 | function md5_ii(a, b, c, d, x, s, t) 358 | { 359 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); 360 | } 361 | 362 | /* 363 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 364 | * to work around bugs in some JS interpreters. 365 | */ 366 | function safe_add(x, y) 367 | { 368 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 369 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 370 | return (msw << 16) | (lsw & 0xFFFF); 371 | } 372 | 373 | /* 374 | * Bitwise rotate a 32-bit number to the left. 375 | */ 376 | function bit_rol(num, cnt) 377 | { 378 | return (num << cnt) | (num >>> (32 - cnt)); 379 | } 380 | -------------------------------------------------------------------------------- /distribute_setup.py: -------------------------------------------------------------------------------- 1 | #!python 2 | """Bootstrap distribute installation 3 | 4 | If you want to use setuptools in your package's setup.py, just include this 5 | file in the same directory with it, and add this to the top of your setup.py:: 6 | 7 | from distribute_setup import use_setuptools 8 | use_setuptools() 9 | 10 | If you want to require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, you can do so by supplying 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import os 17 | import sys 18 | import time 19 | import fnmatch 20 | import tempfile 21 | import tarfile 22 | from distutils import log 23 | 24 | try: 25 | from site import USER_SITE 26 | except ImportError: 27 | USER_SITE = None 28 | 29 | try: 30 | import subprocess 31 | 32 | def _python_cmd(*args): 33 | args = (sys.executable,) + args 34 | return subprocess.call(args) == 0 35 | 36 | except ImportError: 37 | # will be used for python 2.3 38 | def _python_cmd(*args): 39 | args = (sys.executable,) + args 40 | # quoting arguments if windows 41 | if sys.platform == 'win32': 42 | def quote(arg): 43 | if ' ' in arg: 44 | return '"%s"' % arg 45 | return arg 46 | args = [quote(arg) for arg in args] 47 | return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 48 | 49 | DEFAULT_VERSION = "0.6.10" 50 | DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" 51 | SETUPTOOLS_FAKED_VERSION = "0.6c11" 52 | 53 | SETUPTOOLS_PKG_INFO = """\ 54 | Metadata-Version: 1.0 55 | Name: setuptools 56 | Version: %s 57 | Summary: xxxx 58 | Home-page: xxx 59 | Author: xxx 60 | Author-email: xxx 61 | License: xxx 62 | Description: xxx 63 | """ % SETUPTOOLS_FAKED_VERSION 64 | 65 | 66 | def _install(tarball): 67 | # extracting the tarball 68 | tmpdir = tempfile.mkdtemp() 69 | log.warn('Extracting in %s', tmpdir) 70 | old_wd = os.getcwd() 71 | try: 72 | os.chdir(tmpdir) 73 | tar = tarfile.open(tarball) 74 | _extractall(tar) 75 | tar.close() 76 | 77 | # going in the directory 78 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 79 | os.chdir(subdir) 80 | log.warn('Now working in %s', subdir) 81 | 82 | # installing 83 | log.warn('Installing Distribute') 84 | if not _python_cmd('setup.py', 'install'): 85 | log.warn('Something went wrong during the installation.') 86 | log.warn('See the error message above.') 87 | finally: 88 | os.chdir(old_wd) 89 | 90 | 91 | def _build_egg(egg, tarball, to_dir): 92 | # extracting the tarball 93 | tmpdir = tempfile.mkdtemp() 94 | log.warn('Extracting in %s', tmpdir) 95 | old_wd = os.getcwd() 96 | try: 97 | os.chdir(tmpdir) 98 | tar = tarfile.open(tarball) 99 | _extractall(tar) 100 | tar.close() 101 | 102 | # going in the directory 103 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 104 | os.chdir(subdir) 105 | log.warn('Now working in %s', subdir) 106 | 107 | # building an egg 108 | log.warn('Building a Distribute egg in %s', to_dir) 109 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) 110 | 111 | finally: 112 | os.chdir(old_wd) 113 | # returning the result 114 | log.warn(egg) 115 | if not os.path.exists(egg): 116 | raise IOError('Could not build the egg.') 117 | 118 | 119 | def _do_download(version, download_base, to_dir, download_delay): 120 | egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' 121 | % (version, sys.version_info[0], sys.version_info[1])) 122 | if not os.path.exists(egg): 123 | tarball = download_setuptools(version, download_base, 124 | to_dir, download_delay) 125 | _build_egg(egg, tarball, to_dir) 126 | sys.path.insert(0, egg) 127 | import setuptools 128 | setuptools.bootstrap_install_from = egg 129 | 130 | 131 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 132 | to_dir=os.curdir, download_delay=15, no_fake=True): 133 | # making sure we use the absolute path 134 | to_dir = os.path.abspath(to_dir) 135 | was_imported = 'pkg_resources' in sys.modules or \ 136 | 'setuptools' in sys.modules 137 | try: 138 | try: 139 | import pkg_resources 140 | if not hasattr(pkg_resources, '_distribute'): 141 | if not no_fake: 142 | _fake_setuptools() 143 | raise ImportError 144 | except ImportError: 145 | return _do_download(version, download_base, to_dir, download_delay) 146 | try: 147 | pkg_resources.require("distribute>="+version) 148 | return 149 | except pkg_resources.VersionConflict: 150 | e = sys.exc_info()[1] 151 | if was_imported: 152 | sys.stderr.write( 153 | "The required version of distribute (>=%s) is not available,\n" 154 | "and can't be installed while this script is running. Please\n" 155 | "install a more recent version first, using\n" 156 | "'easy_install -U distribute'." 157 | "\n\n(Currently using %r)\n" % (version, e.args[0])) 158 | sys.exit(2) 159 | else: 160 | del pkg_resources, sys.modules['pkg_resources'] # reload ok 161 | return _do_download(version, download_base, to_dir, 162 | download_delay) 163 | except pkg_resources.DistributionNotFound: 164 | return _do_download(version, download_base, to_dir, 165 | download_delay) 166 | finally: 167 | if not no_fake: 168 | _create_fake_setuptools_pkg_info(to_dir) 169 | 170 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 171 | to_dir=os.curdir, delay=15): 172 | """Download distribute from a specified location and return its filename 173 | 174 | `version` should be a valid distribute version number that is available 175 | as an egg for download under the `download_base` URL (which should end 176 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 177 | `delay` is the number of seconds to pause before an actual download 178 | attempt. 179 | """ 180 | # making sure we use the absolute path 181 | to_dir = os.path.abspath(to_dir) 182 | try: 183 | from urllib.request import urlopen 184 | except ImportError: 185 | from urllib2 import urlopen 186 | tgz_name = "distribute-%s.tar.gz" % version 187 | url = download_base + tgz_name 188 | saveto = os.path.join(to_dir, tgz_name) 189 | src = dst = None 190 | if not os.path.exists(saveto): # Avoid repeated downloads 191 | try: 192 | log.warn("Downloading %s", url) 193 | src = urlopen(url) 194 | # Read/write all in one block, so we don't create a corrupt file 195 | # if the download is interrupted. 196 | data = src.read() 197 | dst = open(saveto, "wb") 198 | dst.write(data) 199 | finally: 200 | if src: 201 | src.close() 202 | if dst: 203 | dst.close() 204 | return os.path.realpath(saveto) 205 | 206 | 207 | def _patch_file(path, content): 208 | """Will backup the file then patch it""" 209 | existing_content = open(path).read() 210 | if existing_content == content: 211 | # already patched 212 | log.warn('Already patched.') 213 | return False 214 | log.warn('Patching...') 215 | _rename_path(path) 216 | f = open(path, 'w') 217 | try: 218 | f.write(content) 219 | finally: 220 | f.close() 221 | return True 222 | 223 | 224 | def _same_content(path, content): 225 | return open(path).read() == content 226 | 227 | def _no_sandbox(function): 228 | def __no_sandbox(*args, **kw): 229 | try: 230 | from setuptools.sandbox import DirectorySandbox 231 | def violation(*args): 232 | pass 233 | DirectorySandbox._old = DirectorySandbox._violation 234 | DirectorySandbox._violation = violation 235 | patched = True 236 | except ImportError: 237 | patched = False 238 | 239 | try: 240 | return function(*args, **kw) 241 | finally: 242 | if patched: 243 | DirectorySandbox._violation = DirectorySandbox._old 244 | del DirectorySandbox._old 245 | 246 | return __no_sandbox 247 | 248 | @_no_sandbox 249 | def _rename_path(path): 250 | new_name = path + '.OLD.%s' % time.time() 251 | log.warn('Renaming %s into %s', path, new_name) 252 | os.rename(path, new_name) 253 | return new_name 254 | 255 | def _remove_flat_installation(placeholder): 256 | if not os.path.isdir(placeholder): 257 | log.warn('Unkown installation at %s', placeholder) 258 | return False 259 | found = False 260 | for file in os.listdir(placeholder): 261 | if fnmatch.fnmatch(file, 'setuptools*.egg-info'): 262 | found = True 263 | break 264 | if not found: 265 | log.warn('Could not locate setuptools*.egg-info') 266 | return 267 | 268 | log.warn('Removing elements out of the way...') 269 | pkg_info = os.path.join(placeholder, file) 270 | if os.path.isdir(pkg_info): 271 | patched = _patch_egg_dir(pkg_info) 272 | else: 273 | patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) 274 | 275 | if not patched: 276 | log.warn('%s already patched.', pkg_info) 277 | return False 278 | # now let's move the files out of the way 279 | for element in ('setuptools', 'pkg_resources.py', 'site.py'): 280 | element = os.path.join(placeholder, element) 281 | if os.path.exists(element): 282 | _rename_path(element) 283 | else: 284 | log.warn('Could not find the %s element of the ' 285 | 'Setuptools distribution', element) 286 | return True 287 | 288 | 289 | def _after_install(dist): 290 | log.warn('After install bootstrap.') 291 | placeholder = dist.get_command_obj('install').install_purelib 292 | _create_fake_setuptools_pkg_info(placeholder) 293 | 294 | @_no_sandbox 295 | def _create_fake_setuptools_pkg_info(placeholder): 296 | if not placeholder or not os.path.exists(placeholder): 297 | log.warn('Could not find the install location') 298 | return 299 | pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) 300 | setuptools_file = 'setuptools-%s-py%s.egg-info' % \ 301 | (SETUPTOOLS_FAKED_VERSION, pyver) 302 | pkg_info = os.path.join(placeholder, setuptools_file) 303 | if os.path.exists(pkg_info): 304 | log.warn('%s already exists', pkg_info) 305 | return 306 | 307 | log.warn('Creating %s', pkg_info) 308 | f = open(pkg_info, 'w') 309 | try: 310 | f.write(SETUPTOOLS_PKG_INFO) 311 | finally: 312 | f.close() 313 | 314 | pth_file = os.path.join(placeholder, 'setuptools.pth') 315 | log.warn('Creating %s', pth_file) 316 | f = open(pth_file, 'w') 317 | try: 318 | f.write(os.path.join(os.curdir, setuptools_file)) 319 | finally: 320 | f.close() 321 | 322 | def _patch_egg_dir(path): 323 | # let's check if it's already patched 324 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 325 | if os.path.exists(pkg_info): 326 | if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): 327 | log.warn('%s already patched.', pkg_info) 328 | return False 329 | _rename_path(path) 330 | os.mkdir(path) 331 | os.mkdir(os.path.join(path, 'EGG-INFO')) 332 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 333 | f = open(pkg_info, 'w') 334 | try: 335 | f.write(SETUPTOOLS_PKG_INFO) 336 | finally: 337 | f.close() 338 | return True 339 | 340 | 341 | def _before_install(): 342 | log.warn('Before install bootstrap.') 343 | _fake_setuptools() 344 | 345 | 346 | def _under_prefix(location): 347 | if 'install' not in sys.argv: 348 | return True 349 | args = sys.argv[sys.argv.index('install')+1:] 350 | for index, arg in enumerate(args): 351 | for option in ('--root', '--prefix'): 352 | if arg.startswith('%s=' % option): 353 | top_dir = arg.split('root=')[-1] 354 | return location.startswith(top_dir) 355 | elif arg == option: 356 | if len(args) > index: 357 | top_dir = args[index+1] 358 | return location.startswith(top_dir) 359 | elif option == '--user' and USER_SITE is not None: 360 | return location.startswith(USER_SITE) 361 | return True 362 | 363 | 364 | def _fake_setuptools(): 365 | log.warn('Scanning installed packages') 366 | try: 367 | import pkg_resources 368 | except ImportError: 369 | # we're cool 370 | log.warn('Setuptools or Distribute does not seem to be installed.') 371 | return 372 | ws = pkg_resources.working_set 373 | try: 374 | setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', 375 | replacement=False)) 376 | except TypeError: 377 | # old distribute API 378 | setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) 379 | 380 | if setuptools_dist is None: 381 | log.warn('No setuptools distribution found') 382 | return 383 | # detecting if it was already faked 384 | setuptools_location = setuptools_dist.location 385 | log.warn('Setuptools installation detected at %s', setuptools_location) 386 | 387 | # if --root or --preix was provided, and if 388 | # setuptools is not located in them, we don't patch it 389 | if not _under_prefix(setuptools_location): 390 | log.warn('Not patching, --root or --prefix is installing Distribute' 391 | ' in another location') 392 | return 393 | 394 | # let's see if its an egg 395 | if not setuptools_location.endswith('.egg'): 396 | log.warn('Non-egg installation') 397 | res = _remove_flat_installation(setuptools_location) 398 | if not res: 399 | return 400 | else: 401 | log.warn('Egg installation') 402 | pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') 403 | if (os.path.exists(pkg_info) and 404 | _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): 405 | log.warn('Already patched.') 406 | return 407 | log.warn('Patching...') 408 | # let's create a fake egg replacing setuptools one 409 | res = _patch_egg_dir(setuptools_location) 410 | if not res: 411 | return 412 | log.warn('Patched done.') 413 | _relaunch() 414 | 415 | 416 | def _relaunch(): 417 | log.warn('Relaunching...') 418 | # we have to relaunch the process 419 | args = [sys.executable] + sys.argv 420 | sys.exit(subprocess.call(args)) 421 | 422 | 423 | def _extractall(self, path=".", members=None): 424 | """Extract all members from the archive to the current working 425 | directory and set owner, modification time and permissions on 426 | directories afterwards. `path' specifies a different directory 427 | to extract to. `members' is optional and must be a subset of the 428 | list returned by getmembers(). 429 | """ 430 | import copy 431 | import operator 432 | from tarfile import ExtractError 433 | directories = [] 434 | 435 | if members is None: 436 | members = self 437 | 438 | for tarinfo in members: 439 | if tarinfo.isdir(): 440 | # Extract directories with a safe mode. 441 | directories.append(tarinfo) 442 | tarinfo = copy.copy(tarinfo) 443 | tarinfo.mode = 448 # decimal for oct 0700 444 | self.extract(tarinfo, path) 445 | 446 | # Reverse sort directories. 447 | if sys.version_info < (2, 4): 448 | def sorter(dir1, dir2): 449 | return cmp(dir1.name, dir2.name) 450 | directories.sort(sorter) 451 | directories.reverse() 452 | else: 453 | directories.sort(key=operator.attrgetter('name'), reverse=True) 454 | 455 | # Set correct owner, mtime and filemode on directories. 456 | for tarinfo in directories: 457 | dirpath = os.path.join(path, tarinfo.name) 458 | try: 459 | self.chown(tarinfo, dirpath) 460 | self.utime(tarinfo, dirpath) 461 | self.chmod(tarinfo, dirpath) 462 | except ExtractError: 463 | e = sys.exc_info()[1] 464 | if self.errorlevel > 1: 465 | raise 466 | else: 467 | self._dbg(1, "tarfile: %s" % e) 468 | 469 | 470 | def main(argv, version=DEFAULT_VERSION): 471 | """Install or upgrade setuptools and EasyInstall""" 472 | tarball = download_setuptools() 473 | _install(tarball) 474 | 475 | 476 | if __name__ == '__main__': 477 | main(sys.argv[1:]) 478 | -------------------------------------------------------------------------------- /test/example/media/js/jquery.form.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Form Plugin 3 | * version: 2.36 (07-NOV-2009) 4 | * @requires jQuery v1.2.6 or later 5 | * 6 | * Examples and documentation at: http://malsup.com/jquery/form/ 7 | * Dual licensed under the MIT and GPL licenses: 8 | * http://www.opensource.org/licenses/mit-license.php 9 | * http://www.gnu.org/licenses/gpl.html 10 | */ 11 | ;(function($) { 12 | 13 | /* 14 | Usage Note: 15 | ----------- 16 | Do not use both ajaxSubmit and ajaxForm on the same form. These 17 | functions are intended to be exclusive. Use ajaxSubmit if you want 18 | to bind your own submit handler to the form. For example, 19 | 20 | $(document).ready(function() { 21 | $('#myForm').bind('submit', function() { 22 | $(this).ajaxSubmit({ 23 | target: '#output' 24 | }); 25 | return false; // <-- important! 26 | }); 27 | }); 28 | 29 | Use ajaxForm when you want the plugin to manage all the event binding 30 | for you. For example, 31 | 32 | $(document).ready(function() { 33 | $('#myForm').ajaxForm({ 34 | target: '#output' 35 | }); 36 | }); 37 | 38 | When using ajaxForm, the ajaxSubmit function will be invoked for you 39 | at the appropriate time. 40 | */ 41 | 42 | /** 43 | * ajaxSubmit() provides a mechanism for immediately submitting 44 | * an HTML form using AJAX. 45 | */ 46 | $.fn.ajaxSubmit = function(options) { 47 | // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) 48 | if (!this.length) { 49 | log('ajaxSubmit: skipping submit process - no element selected'); 50 | return this; 51 | } 52 | 53 | if (typeof options == 'function') 54 | options = { success: options }; 55 | 56 | var url = $.trim(this.attr('action')); 57 | if (url) { 58 | // clean url (don't include hash vaue) 59 | url = (url.match(/^([^#]+)/)||[])[1]; 60 | } 61 | url = url || window.location.href || ''; 62 | 63 | options = $.extend({ 64 | url: url, 65 | type: this.attr('method') || 'GET', 66 | iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 67 | }, options || {}); 68 | 69 | // hook for manipulating the form data before it is extracted; 70 | // convenient for use with rich editors like tinyMCE or FCKEditor 71 | var veto = {}; 72 | this.trigger('form-pre-serialize', [this, options, veto]); 73 | if (veto.veto) { 74 | log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 75 | return this; 76 | } 77 | 78 | // provide opportunity to alter form data before it is serialized 79 | if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 80 | log('ajaxSubmit: submit aborted via beforeSerialize callback'); 81 | return this; 82 | } 83 | 84 | var a = this.formToArray(options.semantic); 85 | if (options.data) { 86 | options.extraData = options.data; 87 | for (var n in options.data) { 88 | if(options.data[n] instanceof Array) { 89 | for (var k in options.data[n]) 90 | a.push( { name: n, value: options.data[n][k] } ); 91 | } 92 | else 93 | a.push( { name: n, value: options.data[n] } ); 94 | } 95 | } 96 | 97 | // give pre-submit callback an opportunity to abort the submit 98 | if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 99 | log('ajaxSubmit: submit aborted via beforeSubmit callback'); 100 | return this; 101 | } 102 | 103 | // fire vetoable 'validate' event 104 | this.trigger('form-submit-validate', [a, this, options, veto]); 105 | if (veto.veto) { 106 | log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 107 | return this; 108 | } 109 | 110 | var q = $.param(a); 111 | 112 | if (options.type.toUpperCase() == 'GET') { 113 | options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 114 | options.data = null; // data is null for 'get' 115 | } 116 | else 117 | options.data = q; // data is the query string for 'post' 118 | 119 | var $form = this, callbacks = []; 120 | if (options.resetForm) callbacks.push(function() { $form.resetForm(); }); 121 | if (options.clearForm) callbacks.push(function() { $form.clearForm(); }); 122 | 123 | // perform a load on the target only if dataType is not provided 124 | if (!options.dataType && options.target) { 125 | var oldSuccess = options.success || function(){}; 126 | callbacks.push(function(data) { 127 | $(options.target).html(data).each(oldSuccess, arguments); 128 | }); 129 | } 130 | else if (options.success) 131 | callbacks.push(options.success); 132 | 133 | options.success = function(data, status) { 134 | for (var i=0, max=callbacks.length; i < max; i++) 135 | callbacks[i].apply(options, [data, status, $form]); 136 | }; 137 | 138 | // are there files to upload? 139 | var files = $('input:file', this).fieldValue(); 140 | var found = false; 141 | for (var j=0; j < files.length; j++) 142 | if (files[j]) 143 | found = true; 144 | 145 | var multipart = false; 146 | // var mp = 'multipart/form-data'; 147 | // multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 148 | 149 | // options.iframe allows user to force iframe mode 150 | // 06-NOV-09: now defaulting to iframe mode if file input is detected 151 | if ((files.length && options.iframe !== false) || options.iframe || found || multipart) { 152 | // hack to fix Safari hang (thanks to Tim Molendijk for this) 153 | // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 154 | if (options.closeKeepAlive) 155 | $.get(options.closeKeepAlive, fileUpload); 156 | else 157 | fileUpload(); 158 | } 159 | else 160 | $.ajax(options); 161 | 162 | // fire 'notify' event 163 | this.trigger('form-submit-notify', [this, options]); 164 | return this; 165 | 166 | 167 | // private function for handling file uploads (hat tip to YAHOO!) 168 | function fileUpload() { 169 | var form = $form[0]; 170 | 171 | if ($(':input[name=submit]', form).length) { 172 | alert('Error: Form elements must not be named "submit".'); 173 | return; 174 | } 175 | 176 | var opts = $.extend({}, $.ajaxSettings, options); 177 | var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts); 178 | 179 | var id = 'jqFormIO' + (new Date().getTime()); 180 | var $io = $('