├── .gitignore ├── LICENSE ├── Procfile ├── Procfile.dev ├── README.md ├── app.json ├── dev.env ├── manage.py ├── memcachier_algebra ├── __init__.py ├── settings.py ├── static │ ├── .gitkeep │ ├── bootstrap-responsive.min.css │ ├── bootstrap.js │ ├── bootstrap.min.css │ ├── favicon.ico │ ├── html5shiv.js │ ├── jquery-1.7.2.js │ ├── main.js │ └── memcachier-small.png ├── templates │ └── index.html ├── urls.py ├── views.py └── wsgi.py ├── pylibmc_test.py ├── requirements.txt └── runtime.txt /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | *.pyc 3 | .env 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, MemCachier Inc. 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the author nor the names of his contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 21 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 24 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn memcachier_algebra.wsgi --log-file - 2 | -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | web: python manage.py runserver 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MemCachier Django Example App 2 | 3 | This is an example Django app that uses 4 | [MemCachier](http://www.memcachier.com) to cache algebraic 5 | computations. 6 | 7 | **This example is written with Django 1.8.16. Unless you specifically 8 | need an old Django version you should check out a newer 9 | [example](https://github.com/memcachier/examples-django-tasklist).** 10 | 11 | You can view a working version of this app 12 | [here](http://memcachier-examples-django.herokuapp.com) that uses 13 | [MemCachier on Heroku](https://addons.heroku.com/memcachier). 14 | Running this app on your local machine in development will work as 15 | well, although then you won't be using MemCachier -- you'll be using a 16 | local dummy cache. MemCachier is currently only available with various 17 | cloud providers. 18 | 19 | Setting up MemCachier to work in Django is very easy. You need to 20 | make changes to requirements.txt, settings.py, and any app code that 21 | you want cached. These changes are covered in detail below. 22 | 23 | ## Deploy to Heroku 24 | 25 | You can deploy this app yourself to Heroku to play with. 26 | 27 | [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) 28 | 29 | ## Building 30 | 31 | It is best to use the python `virtualenv` tool to build locally: 32 | 33 | ```sh 34 | $ virtualenv-2.7 venv 35 | $ source venv/bin/activate 36 | $ pip install -r requirements.txt 37 | $ DEVELOPMENT=1 python manage.py runserver 38 | ``` 39 | 40 | Then visit `http://localhost:8000` to view the app. Alternatively you 41 | can use foreman and gunicorn to run the server locally (after copying 42 | `dev.env` to `.env`): 43 | 44 | ```sh 45 | $ foreman start 46 | ``` 47 | 48 | ## Deploy to Heroku 49 | 50 | Run the following commands to deploy the app to Heroku: 51 | 52 | ```sh 53 | $ git clone https://github.com/memcachier/examples-django.git 54 | $ cd examples-django 55 | $ heroku create 56 | $ heroku addons:add memcachier:dev 57 | $ git push heroku master:master 58 | $ heroku open 59 | ``` 60 | 61 | ## requirements.txt 62 | 63 | MemCachier has been tested with the pylibmc memcache client, but the 64 | default client doesn't support SASL authentication. Run the following 65 | commands to install the necessary pips: 66 | 67 | ```sh 68 | $ sudo brew install libmemcached 69 | $ pip install django-pylibmc pylibmc 70 | ``` 71 | 72 | Don't forget to update your requirements.txt file with these new pips. 73 | requirements.txt should have the following two lines: 74 | 75 | ``` 76 | django-pylibmc==0.6.1 77 | pylibmc==1.5.1 78 | ``` 79 | 80 | ## Configuring MemCachier (settings.py) 81 | 82 | To configure Django to use pylibmc with SASL authentication. You'll also need 83 | to setup your environment, because pylibmc expects different environment 84 | variables than MemCachier provides. Somewhere in your `settings.py` file you 85 | should have the following lines: 86 | 87 | ```python 88 | os.environ['MEMCACHE_SERVERS'] = os.environ.get('MEMCACHIER_SERVERS', '').replace(',', ';') 89 | os.environ['MEMCACHE_USERNAME'] = os.environ.get('MEMCACHIER_USERNAME', '') 90 | os.environ['MEMCACHE_PASSWORD'] = os.environ.get('MEMCACHIER_PASSWORD', '') 91 | 92 | CACHES = { 93 | 'default': { 94 | # Use pylibmc 95 | 'BACKEND': 'django_pylibmc.memcached.PyLibMCCache', 96 | 97 | # Use binary memcache protocol (needed for authentication) 98 | 'BINARY': True, 99 | 100 | # TIMEOUT is not the connection timeout! It's the default expiration 101 | # timeout that should be applied to keys! Setting it to `None` 102 | # disables expiration. 103 | 'TIMEOUT': None, 104 | 'OPTIONS': { 105 | # Enable faster IO 106 | 'tcp_nodelay': True, 107 | 108 | # Keep connection alive 109 | 'tcp_keepalive': True, 110 | 111 | # Timeout settings 112 | 'connect_timeout': 2000, # ms 113 | 'send_timeout': 750 * 1000, # us 114 | 'receive_timeout': 750 * 1000, # us 115 | '_poll_timeout': 2000, # ms 116 | 117 | # Better failover 118 | 'ketama': True, 119 | 'remove_failed': 1, 120 | 'retry_timeout': 2, 121 | 'dead_timeout': 30, 122 | } 123 | } 124 | } 125 | ``` 126 | 127 | ## Persistent Connections 128 | 129 | By default, Django doesn't use persistent connections with memcached. This is a 130 | huge performance problem, especially when using SASL authentication as the 131 | connection setup is even more expensive than normal. 132 | 133 | You can fix this by putting the following code in your `wsgi.py` file: 134 | 135 | ```python 136 | # Fix django closing connection to MemCachier after every request (#11331) 137 | from django.core.cache.backends.memcached import BaseMemcachedCache 138 | BaseMemcachedCache.close = lambda self, **kwargs: None 139 | ``` 140 | 141 | There is a bug file against Django for this issue 142 | ([#11331](https://code.djangoproject.com/ticket/11331)). 143 | 144 | ## Application Code 145 | 146 | In your application, use django.core.cache methods to access 147 | MemCachier. A description of the low-level caching API can be found 148 | [here](https://docs.djangoproject.com/en/1.8/topics/cache/#the-low-level-cache-api). 149 | All the built-in Django caching tools will work, too. 150 | 151 | Take a look at 152 | [memcachier_algebra/views.py](https://github.com/memcachier/examples-django/blob/master/memcachier_algebra/views.py) 153 | in this repository for an example. 154 | 155 | ## Get involved! 156 | 157 | We are happy to receive bug reports, fixes, documentation enhancements, 158 | and other improvements. 159 | 160 | Please report bugs via the 161 | [github issue tracker](http://github.com/memcachier/examples-django/issues). 162 | 163 | Master [git repository](http://github.com/memcachier/examples-django): 164 | 165 | * `git clone git://github.com/memcachier/examples-django.git` 166 | 167 | ## Licensing 168 | 169 | This library is BSD-licensed. 170 | 171 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MemCachier Django Example App", 3 | "description": "Django app illustrating how to use MemCachier to cache computations", 4 | "keywords": ["python", "django", "memcache", "memcachier", "caching" ], 5 | "keywords": ["python", "django", "memcache", "memcachier", "caching", "performance", "pylibmc" ], 6 | "logo": "https://www.memcachier.com/assets/logo-large.png", 7 | "image": "heroku/python", 8 | "website": "https://www.memcachier.com", 9 | "repository": "https://github.com/memcachier/examples-django", 10 | "addons": [ "memcachier" ] 11 | } 12 | -------------------------------------------------------------------------------- /dev.env: -------------------------------------------------------------------------------- 1 | DEVELOPMENT=1 2 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "memcachier_algebra.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /memcachier_algebra/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/memcachier/examples-django/9c044e22b9cc076459d5c491cb9c2ee89f1360d0/memcachier_algebra/__init__.py -------------------------------------------------------------------------------- /memcachier_algebra/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for MemCachier django example. 2 | import os 3 | 4 | ## MemCachier Settings 5 | ## =================== 6 | # Docs: http://sendapatch.se/projects/pylibmc/behaviors.html 7 | # http://docs.libmemcached.org/memcached_behavior.html 8 | # https://github.com/django-pylibmc/django-pylibmc 9 | # https://docs.djangoproject.com/en/1.8/topics/cache 10 | if os.environ.get('DEVELOPMENT', None): 11 | CACHES = { 12 | 'default': { 13 | 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache' 14 | } 15 | } 16 | else: 17 | # Configure server credentials 18 | os.environ['MEMCACHE_SERVERS'] = os.environ.get('MEMCACHIER_SERVERS', '').replace(',', ';') 19 | os.environ['MEMCACHE_USERNAME'] = os.environ.get('MEMCACHIER_USERNAME', '') 20 | os.environ['MEMCACHE_PASSWORD'] = os.environ.get('MEMCACHIER_PASSWORD', '') 21 | 22 | # Configure cache settings 23 | CACHES = { 24 | 'default': { 25 | # Use pylibmc 26 | 'BACKEND': 'django_pylibmc.memcached.PyLibMCCache', 27 | 28 | # Use binary memcache protocol (needed for authentication) 29 | 'BINARY': True, 30 | 31 | # TIMEOUT is not the connection timeout! It's the default expiration 32 | # timeout that should be applied to keys! Setting it to `None` 33 | # disables expiration. 34 | 'TIMEOUT': None, 35 | 36 | 'OPTIONS': { 37 | # Enable faster IO 38 | 'tcp_nodelay': True, 39 | 40 | # Keep connection alive 41 | 'tcp_keepalive': True, 42 | 43 | # Timeout settings 44 | 'connect_timeout': 2000, # ms 45 | 'send_timeout': 750 * 1000, # us 46 | 'receive_timeout': 750 * 1000, # us 47 | '_poll_timeout': 2000, # ms 48 | 49 | # Better failover 50 | 'ketama': True, 51 | 'remove_failed': 1, 52 | 'retry_timeout': 2, 53 | 'dead_timeout': 30, 54 | } 55 | } 56 | } 57 | 58 | ## ====================================================================== 59 | ## EVERYTHING BELOW IS CONFIGURATION UNRELATED TO THIS MEMCACHIER EXAMPLE 60 | ## ====================================================================== 61 | 62 | ## Database Settings (none) 63 | ## ======================== 64 | DATABASES = { 65 | 'default': { 66 | 'ENGINE': 'django.db.backends.', 67 | 'NAME': '', 68 | 'USER': '', 69 | 'PASSWORD': '', 70 | 'HOST': '', 71 | 'PORT': '', 72 | } 73 | } 74 | 75 | ## Static Assets & Heroku 76 | ## ====================== 77 | PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) 78 | STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles') 79 | STATIC_URL = '/static/' 80 | STATICFILES_DIRS = [ 81 | os.path.join(PROJECT_ROOT, 'static') 82 | ] 83 | STATICFILES_FINDERS = ( 84 | 'django.contrib.staticfiles.finders.FileSystemFinder', 85 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 86 | ) 87 | 88 | ## Templates 89 | ## ========= 90 | 91 | TEMPLATE_LOADERS = ( 92 | 'django.template.loaders.filesystem.Loader', 93 | 'django.template.loaders.app_directories.Loader', 94 | ) 95 | TEMPLATE_DIRS = ( 96 | os.path.join(PROJECT_ROOT, 'templates'), 97 | ) 98 | 99 | ## Other Settings 100 | ## ============== 101 | DEBUG = True 102 | ADMINS = () 103 | MANAGERS = ADMINS 104 | TIME_ZONE = 'America/Los_Angeles' 105 | LANGUAGE_CODE = 'en-us' 106 | SITE_ID = 1 107 | USE_I18N = True 108 | USE_L10N = True 109 | USE_TZ = True 110 | MEDIA_ROOT = '' 111 | MEDIA_URL = '' 112 | 113 | # Allow all host headers 114 | ALLOWED_HOSTS = ['*'] 115 | 116 | SECRET_KEY = 'l&nd6u%i-s)2c)s5=^i2#v*4)%i9j-g^yo=)z#(#+5pe)o_=%v' 117 | 118 | MIDDLEWARE_CLASSES = ( 119 | 'django.middleware.common.CommonMiddleware', 120 | 'django.contrib.sessions.middleware.SessionMiddleware', 121 | 'django.middleware.csrf.CsrfViewMiddleware', 122 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 123 | 'django.contrib.messages.middleware.MessageMiddleware', 124 | ) 125 | 126 | ROOT_URLCONF = 'memcachier_algebra.urls' 127 | 128 | WSGI_APPLICATION = 'memcachier_algebra.wsgi.application' 129 | 130 | INSTALLED_APPS = ( 131 | 'django.contrib.auth', 132 | 'django.contrib.contenttypes', 133 | 'django.contrib.sessions', 134 | 'django.contrib.sites', 135 | 'django.contrib.messages', 136 | 'django.contrib.staticfiles', 137 | ) 138 | 139 | LOGGING = { 140 | 'version': 1, 141 | 'disable_existing_loggers': False, 142 | 'filters': { 143 | 'require_debug_false': { 144 | '()': 'django.utils.log.RequireDebugFalse' 145 | } 146 | }, 147 | 'handlers': { 148 | 'mail_admins': { 149 | 'level': 'ERROR', 150 | 'filters': ['require_debug_false'], 151 | 'class': 'django.utils.log.AdminEmailHandler' 152 | } 153 | }, 154 | 'loggers': { 155 | 'django.request': { 156 | 'handlers': ['mail_admins'], 157 | 'level': 'ERROR', 158 | 'propagate': True, 159 | }, 160 | } 161 | } 162 | 163 | TEST_RUNNER = 'django.test.runner.DiscoverRunner' 164 | -------------------------------------------------------------------------------- /memcachier_algebra/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/memcachier/examples-django/9c044e22b9cc076459d5c491cb9c2ee89f1360d0/memcachier_algebra/static/.gitkeep -------------------------------------------------------------------------------- /memcachier_algebra/static/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.2.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /memcachier_algebra/static/bootstrap.js: -------------------------------------------------------------------------------- 1 | /* =================================================== 2 | * bootstrap-transition.js v2.0.3 3 | * http://twitter.github.com/bootstrap/javascript.html#transitions 4 | * =================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================== */ 19 | 20 | 21 | !function ($) { 22 | 23 | $(function () { 24 | 25 | "use strict"; // jshint ;_; 26 | 27 | 28 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) 29 | * ======================================================= */ 30 | 31 | $.support.transition = (function () { 32 | 33 | var transitionEnd = (function () { 34 | 35 | var el = document.createElement('bootstrap') 36 | , transEndEventNames = { 37 | 'WebkitTransition' : 'webkitTransitionEnd' 38 | , 'MozTransition' : 'transitionend' 39 | , 'OTransition' : 'oTransitionEnd' 40 | , 'msTransition' : 'MSTransitionEnd' 41 | , 'transition' : 'transitionend' 42 | } 43 | , name 44 | 45 | for (name in transEndEventNames){ 46 | if (el.style[name] !== undefined) { 47 | return transEndEventNames[name] 48 | } 49 | } 50 | 51 | }()) 52 | 53 | return transitionEnd && { 54 | end: transitionEnd 55 | } 56 | 57 | })() 58 | 59 | }) 60 | 61 | }(window.jQuery);/* ========================================================== 62 | * bootstrap-alert.js v2.0.3 63 | * http://twitter.github.com/bootstrap/javascript.html#alerts 64 | * ========================================================== 65 | * Copyright 2012 Twitter, Inc. 66 | * 67 | * Licensed under the Apache License, Version 2.0 (the "License"); 68 | * you may not use this file except in compliance with the License. 69 | * You may obtain a copy of the License at 70 | * 71 | * http://www.apache.org/licenses/LICENSE-2.0 72 | * 73 | * Unless required by applicable law or agreed to in writing, software 74 | * distributed under the License is distributed on an "AS IS" BASIS, 75 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 76 | * See the License for the specific language governing permissions and 77 | * limitations under the License. 78 | * ========================================================== */ 79 | 80 | 81 | !function ($) { 82 | 83 | "use strict"; // jshint ;_; 84 | 85 | 86 | /* ALERT CLASS DEFINITION 87 | * ====================== */ 88 | 89 | var dismiss = '[data-dismiss="alert"]' 90 | , Alert = function (el) { 91 | $(el).on('click', dismiss, this.close) 92 | } 93 | 94 | Alert.prototype.close = function (e) { 95 | var $this = $(this) 96 | , selector = $this.attr('data-target') 97 | , $parent 98 | 99 | if (!selector) { 100 | selector = $this.attr('href') 101 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 102 | } 103 | 104 | $parent = $(selector) 105 | 106 | e && e.preventDefault() 107 | 108 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) 109 | 110 | $parent.trigger(e = $.Event('close')) 111 | 112 | if (e.isDefaultPrevented()) return 113 | 114 | $parent.removeClass('in') 115 | 116 | function removeElement() { 117 | $parent 118 | .trigger('closed') 119 | .remove() 120 | } 121 | 122 | $.support.transition && $parent.hasClass('fade') ? 123 | $parent.on($.support.transition.end, removeElement) : 124 | removeElement() 125 | } 126 | 127 | 128 | /* ALERT PLUGIN DEFINITION 129 | * ======================= */ 130 | 131 | $.fn.alert = function (option) { 132 | return this.each(function () { 133 | var $this = $(this) 134 | , data = $this.data('alert') 135 | if (!data) $this.data('alert', (data = new Alert(this))) 136 | if (typeof option == 'string') data[option].call($this) 137 | }) 138 | } 139 | 140 | $.fn.alert.Constructor = Alert 141 | 142 | 143 | /* ALERT DATA-API 144 | * ============== */ 145 | 146 | $(function () { 147 | $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) 148 | }) 149 | 150 | }(window.jQuery);/* ============================================================ 151 | * bootstrap-button.js v2.0.3 152 | * http://twitter.github.com/bootstrap/javascript.html#buttons 153 | * ============================================================ 154 | * Copyright 2012 Twitter, Inc. 155 | * 156 | * Licensed under the Apache License, Version 2.0 (the "License"); 157 | * you may not use this file except in compliance with the License. 158 | * You may obtain a copy of the License at 159 | * 160 | * http://www.apache.org/licenses/LICENSE-2.0 161 | * 162 | * Unless required by applicable law or agreed to in writing, software 163 | * distributed under the License is distributed on an "AS IS" BASIS, 164 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 165 | * See the License for the specific language governing permissions and 166 | * limitations under the License. 167 | * ============================================================ */ 168 | 169 | 170 | !function ($) { 171 | 172 | "use strict"; // jshint ;_; 173 | 174 | 175 | /* BUTTON PUBLIC CLASS DEFINITION 176 | * ============================== */ 177 | 178 | var Button = function (element, options) { 179 | this.$element = $(element) 180 | this.options = $.extend({}, $.fn.button.defaults, options) 181 | } 182 | 183 | Button.prototype.setState = function (state) { 184 | var d = 'disabled' 185 | , $el = this.$element 186 | , data = $el.data() 187 | , val = $el.is('input') ? 'val' : 'html' 188 | 189 | state = state + 'Text' 190 | data.resetText || $el.data('resetText', $el[val]()) 191 | 192 | $el[val](data[state] || this.options[state]) 193 | 194 | // push to event loop to allow forms to submit 195 | setTimeout(function () { 196 | state == 'loadingText' ? 197 | $el.addClass(d).attr(d, d) : 198 | $el.removeClass(d).removeAttr(d) 199 | }, 0) 200 | } 201 | 202 | Button.prototype.toggle = function () { 203 | var $parent = this.$element.parent('[data-toggle="buttons-radio"]') 204 | 205 | $parent && $parent 206 | .find('.active') 207 | .removeClass('active') 208 | 209 | this.$element.toggleClass('active') 210 | } 211 | 212 | 213 | /* BUTTON PLUGIN DEFINITION 214 | * ======================== */ 215 | 216 | $.fn.button = function (option) { 217 | return this.each(function () { 218 | var $this = $(this) 219 | , data = $this.data('button') 220 | , options = typeof option == 'object' && option 221 | if (!data) $this.data('button', (data = new Button(this, options))) 222 | if (option == 'toggle') data.toggle() 223 | else if (option) data.setState(option) 224 | }) 225 | } 226 | 227 | $.fn.button.defaults = { 228 | loadingText: 'loading...' 229 | } 230 | 231 | $.fn.button.Constructor = Button 232 | 233 | 234 | /* BUTTON DATA-API 235 | * =============== */ 236 | 237 | $(function () { 238 | $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { 239 | var $btn = $(e.target) 240 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 241 | $btn.button('toggle') 242 | }) 243 | }) 244 | 245 | }(window.jQuery);/* ========================================================== 246 | * bootstrap-carousel.js v2.0.3 247 | * http://twitter.github.com/bootstrap/javascript.html#carousel 248 | * ========================================================== 249 | * Copyright 2012 Twitter, Inc. 250 | * 251 | * Licensed under the Apache License, Version 2.0 (the "License"); 252 | * you may not use this file except in compliance with the License. 253 | * You may obtain a copy of the License at 254 | * 255 | * http://www.apache.org/licenses/LICENSE-2.0 256 | * 257 | * Unless required by applicable law or agreed to in writing, software 258 | * distributed under the License is distributed on an "AS IS" BASIS, 259 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 260 | * See the License for the specific language governing permissions and 261 | * limitations under the License. 262 | * ========================================================== */ 263 | 264 | 265 | !function ($) { 266 | 267 | "use strict"; // jshint ;_; 268 | 269 | 270 | /* CAROUSEL CLASS DEFINITION 271 | * ========================= */ 272 | 273 | var Carousel = function (element, options) { 274 | this.$element = $(element) 275 | this.options = options 276 | this.options.slide && this.slide(this.options.slide) 277 | this.options.pause == 'hover' && this.$element 278 | .on('mouseenter', $.proxy(this.pause, this)) 279 | .on('mouseleave', $.proxy(this.cycle, this)) 280 | } 281 | 282 | Carousel.prototype = { 283 | 284 | cycle: function (e) { 285 | if (!e) this.paused = false 286 | this.options.interval 287 | && !this.paused 288 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 289 | return this 290 | } 291 | 292 | , to: function (pos) { 293 | var $active = this.$element.find('.active') 294 | , children = $active.parent().children() 295 | , activePos = children.index($active) 296 | , that = this 297 | 298 | if (pos > (children.length - 1) || pos < 0) return 299 | 300 | if (this.sliding) { 301 | return this.$element.one('slid', function () { 302 | that.to(pos) 303 | }) 304 | } 305 | 306 | if (activePos == pos) { 307 | return this.pause().cycle() 308 | } 309 | 310 | return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) 311 | } 312 | 313 | , pause: function (e) { 314 | if (!e) this.paused = true 315 | clearInterval(this.interval) 316 | this.interval = null 317 | return this 318 | } 319 | 320 | , next: function () { 321 | if (this.sliding) return 322 | return this.slide('next') 323 | } 324 | 325 | , prev: function () { 326 | if (this.sliding) return 327 | return this.slide('prev') 328 | } 329 | 330 | , slide: function (type, next) { 331 | var $active = this.$element.find('.active') 332 | , $next = next || $active[type]() 333 | , isCycling = this.interval 334 | , direction = type == 'next' ? 'left' : 'right' 335 | , fallback = type == 'next' ? 'first' : 'last' 336 | , that = this 337 | , e = $.Event('slide') 338 | 339 | this.sliding = true 340 | 341 | isCycling && this.pause() 342 | 343 | $next = $next.length ? $next : this.$element.find('.item')[fallback]() 344 | 345 | if ($next.hasClass('active')) return 346 | 347 | if ($.support.transition && this.$element.hasClass('slide')) { 348 | this.$element.trigger(e) 349 | if (e.isDefaultPrevented()) return 350 | $next.addClass(type) 351 | $next[0].offsetWidth // force reflow 352 | $active.addClass(direction) 353 | $next.addClass(direction) 354 | this.$element.one($.support.transition.end, function () { 355 | $next.removeClass([type, direction].join(' ')).addClass('active') 356 | $active.removeClass(['active', direction].join(' ')) 357 | that.sliding = false 358 | setTimeout(function () { that.$element.trigger('slid') }, 0) 359 | }) 360 | } else { 361 | this.$element.trigger(e) 362 | if (e.isDefaultPrevented()) return 363 | $active.removeClass('active') 364 | $next.addClass('active') 365 | this.sliding = false 366 | this.$element.trigger('slid') 367 | } 368 | 369 | isCycling && this.cycle() 370 | 371 | return this 372 | } 373 | 374 | } 375 | 376 | 377 | /* CAROUSEL PLUGIN DEFINITION 378 | * ========================== */ 379 | 380 | $.fn.carousel = function (option) { 381 | return this.each(function () { 382 | var $this = $(this) 383 | , data = $this.data('carousel') 384 | , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) 385 | if (!data) $this.data('carousel', (data = new Carousel(this, options))) 386 | if (typeof option == 'number') data.to(option) 387 | else if (typeof option == 'string' || (option = options.slide)) data[option]() 388 | else if (options.interval) data.cycle() 389 | }) 390 | } 391 | 392 | $.fn.carousel.defaults = { 393 | interval: 5000 394 | , pause: 'hover' 395 | } 396 | 397 | $.fn.carousel.Constructor = Carousel 398 | 399 | 400 | /* CAROUSEL DATA-API 401 | * ================= */ 402 | 403 | $(function () { 404 | $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { 405 | var $this = $(this), href 406 | , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 407 | , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) 408 | $target.carousel(options) 409 | e.preventDefault() 410 | }) 411 | }) 412 | 413 | }(window.jQuery);/* ============================================================= 414 | * bootstrap-collapse.js v2.0.3 415 | * http://twitter.github.com/bootstrap/javascript.html#collapse 416 | * ============================================================= 417 | * Copyright 2012 Twitter, Inc. 418 | * 419 | * Licensed under the Apache License, Version 2.0 (the "License"); 420 | * you may not use this file except in compliance with the License. 421 | * You may obtain a copy of the License at 422 | * 423 | * http://www.apache.org/licenses/LICENSE-2.0 424 | * 425 | * Unless required by applicable law or agreed to in writing, software 426 | * distributed under the License is distributed on an "AS IS" BASIS, 427 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 428 | * See the License for the specific language governing permissions and 429 | * limitations under the License. 430 | * ============================================================ */ 431 | 432 | 433 | !function ($) { 434 | 435 | "use strict"; // jshint ;_; 436 | 437 | 438 | /* COLLAPSE PUBLIC CLASS DEFINITION 439 | * ================================ */ 440 | 441 | var Collapse = function (element, options) { 442 | this.$element = $(element) 443 | this.options = $.extend({}, $.fn.collapse.defaults, options) 444 | 445 | if (this.options.parent) { 446 | this.$parent = $(this.options.parent) 447 | } 448 | 449 | this.options.toggle && this.toggle() 450 | } 451 | 452 | Collapse.prototype = { 453 | 454 | constructor: Collapse 455 | 456 | , dimension: function () { 457 | var hasWidth = this.$element.hasClass('width') 458 | return hasWidth ? 'width' : 'height' 459 | } 460 | 461 | , show: function () { 462 | var dimension 463 | , scroll 464 | , actives 465 | , hasData 466 | 467 | if (this.transitioning) return 468 | 469 | dimension = this.dimension() 470 | scroll = $.camelCase(['scroll', dimension].join('-')) 471 | actives = this.$parent && this.$parent.find('> .accordion-group > .in') 472 | 473 | if (actives && actives.length) { 474 | hasData = actives.data('collapse') 475 | if (hasData && hasData.transitioning) return 476 | actives.collapse('hide') 477 | hasData || actives.data('collapse', null) 478 | } 479 | 480 | this.$element[dimension](0) 481 | this.transition('addClass', $.Event('show'), 'shown') 482 | this.$element[dimension](this.$element[0][scroll]) 483 | } 484 | 485 | , hide: function () { 486 | var dimension 487 | if (this.transitioning) return 488 | dimension = this.dimension() 489 | this.reset(this.$element[dimension]()) 490 | this.transition('removeClass', $.Event('hide'), 'hidden') 491 | this.$element[dimension](0) 492 | } 493 | 494 | , reset: function (size) { 495 | var dimension = this.dimension() 496 | 497 | this.$element 498 | .removeClass('collapse') 499 | [dimension](size || 'auto') 500 | [0].offsetWidth 501 | 502 | this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') 503 | 504 | return this 505 | } 506 | 507 | , transition: function (method, startEvent, completeEvent) { 508 | var that = this 509 | , complete = function () { 510 | if (startEvent.type == 'show') that.reset() 511 | that.transitioning = 0 512 | that.$element.trigger(completeEvent) 513 | } 514 | 515 | this.$element.trigger(startEvent) 516 | 517 | if (startEvent.isDefaultPrevented()) return 518 | 519 | this.transitioning = 1 520 | 521 | this.$element[method]('in') 522 | 523 | $.support.transition && this.$element.hasClass('collapse') ? 524 | this.$element.one($.support.transition.end, complete) : 525 | complete() 526 | } 527 | 528 | , toggle: function () { 529 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 530 | } 531 | 532 | } 533 | 534 | 535 | /* COLLAPSIBLE PLUGIN DEFINITION 536 | * ============================== */ 537 | 538 | $.fn.collapse = function (option) { 539 | return this.each(function () { 540 | var $this = $(this) 541 | , data = $this.data('collapse') 542 | , options = typeof option == 'object' && option 543 | if (!data) $this.data('collapse', (data = new Collapse(this, options))) 544 | if (typeof option == 'string') data[option]() 545 | }) 546 | } 547 | 548 | $.fn.collapse.defaults = { 549 | toggle: true 550 | } 551 | 552 | $.fn.collapse.Constructor = Collapse 553 | 554 | 555 | /* COLLAPSIBLE DATA-API 556 | * ==================== */ 557 | 558 | $(function () { 559 | $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { 560 | var $this = $(this), href 561 | , target = $this.attr('data-target') 562 | || e.preventDefault() 563 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 564 | , option = $(target).data('collapse') ? 'toggle' : $this.data() 565 | $(target).collapse(option) 566 | }) 567 | }) 568 | 569 | }(window.jQuery);/* ============================================================ 570 | * bootstrap-dropdown.js v2.0.3 571 | * http://twitter.github.com/bootstrap/javascript.html#dropdowns 572 | * ============================================================ 573 | * Copyright 2012 Twitter, Inc. 574 | * 575 | * Licensed under the Apache License, Version 2.0 (the "License"); 576 | * you may not use this file except in compliance with the License. 577 | * You may obtain a copy of the License at 578 | * 579 | * http://www.apache.org/licenses/LICENSE-2.0 580 | * 581 | * Unless required by applicable law or agreed to in writing, software 582 | * distributed under the License is distributed on an "AS IS" BASIS, 583 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 584 | * See the License for the specific language governing permissions and 585 | * limitations under the License. 586 | * ============================================================ */ 587 | 588 | 589 | !function ($) { 590 | 591 | "use strict"; // jshint ;_; 592 | 593 | 594 | /* DROPDOWN CLASS DEFINITION 595 | * ========================= */ 596 | 597 | var toggle = '[data-toggle="dropdown"]' 598 | , Dropdown = function (element) { 599 | var $el = $(element).on('click.dropdown.data-api', this.toggle) 600 | $('html').on('click.dropdown.data-api', function () { 601 | $el.parent().removeClass('open') 602 | }) 603 | } 604 | 605 | Dropdown.prototype = { 606 | 607 | constructor: Dropdown 608 | 609 | , toggle: function (e) { 610 | var $this = $(this) 611 | , $parent 612 | , selector 613 | , isActive 614 | 615 | if ($this.is('.disabled, :disabled')) return 616 | 617 | selector = $this.attr('data-target') 618 | 619 | if (!selector) { 620 | selector = $this.attr('href') 621 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 622 | } 623 | 624 | $parent = $(selector) 625 | $parent.length || ($parent = $this.parent()) 626 | 627 | isActive = $parent.hasClass('open') 628 | 629 | clearMenus() 630 | 631 | if (!isActive) $parent.toggleClass('open') 632 | 633 | return false 634 | } 635 | 636 | } 637 | 638 | function clearMenus() { 639 | $(toggle).parent().removeClass('open') 640 | } 641 | 642 | 643 | /* DROPDOWN PLUGIN DEFINITION 644 | * ========================== */ 645 | 646 | $.fn.dropdown = function (option) { 647 | return this.each(function () { 648 | var $this = $(this) 649 | , data = $this.data('dropdown') 650 | if (!data) $this.data('dropdown', (data = new Dropdown(this))) 651 | if (typeof option == 'string') data[option].call($this) 652 | }) 653 | } 654 | 655 | $.fn.dropdown.Constructor = Dropdown 656 | 657 | 658 | /* APPLY TO STANDARD DROPDOWN ELEMENTS 659 | * =================================== */ 660 | 661 | $(function () { 662 | $('html').on('click.dropdown.data-api', clearMenus) 663 | $('body') 664 | .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() }) 665 | .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) 666 | }) 667 | 668 | }(window.jQuery);/* ========================================================= 669 | * bootstrap-modal.js v2.0.3 670 | * http://twitter.github.com/bootstrap/javascript.html#modals 671 | * ========================================================= 672 | * Copyright 2012 Twitter, Inc. 673 | * 674 | * Licensed under the Apache License, Version 2.0 (the "License"); 675 | * you may not use this file except in compliance with the License. 676 | * You may obtain a copy of the License at 677 | * 678 | * http://www.apache.org/licenses/LICENSE-2.0 679 | * 680 | * Unless required by applicable law or agreed to in writing, software 681 | * distributed under the License is distributed on an "AS IS" BASIS, 682 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 683 | * See the License for the specific language governing permissions and 684 | * limitations under the License. 685 | * ========================================================= */ 686 | 687 | 688 | !function ($) { 689 | 690 | "use strict"; // jshint ;_; 691 | 692 | 693 | /* MODAL CLASS DEFINITION 694 | * ====================== */ 695 | 696 | var Modal = function (content, options) { 697 | this.options = options 698 | this.$element = $(content) 699 | .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) 700 | } 701 | 702 | Modal.prototype = { 703 | 704 | constructor: Modal 705 | 706 | , toggle: function () { 707 | return this[!this.isShown ? 'show' : 'hide']() 708 | } 709 | 710 | , show: function () { 711 | var that = this 712 | , e = $.Event('show') 713 | 714 | this.$element.trigger(e) 715 | 716 | if (this.isShown || e.isDefaultPrevented()) return 717 | 718 | $('body').addClass('modal-open') 719 | 720 | this.isShown = true 721 | 722 | escape.call(this) 723 | backdrop.call(this, function () { 724 | var transition = $.support.transition && that.$element.hasClass('fade') 725 | 726 | if (!that.$element.parent().length) { 727 | that.$element.appendTo(document.body) //don't move modals dom position 728 | } 729 | 730 | that.$element 731 | .show() 732 | 733 | if (transition) { 734 | that.$element[0].offsetWidth // force reflow 735 | } 736 | 737 | that.$element.addClass('in') 738 | 739 | transition ? 740 | that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : 741 | that.$element.trigger('shown') 742 | 743 | }) 744 | } 745 | 746 | , hide: function (e) { 747 | e && e.preventDefault() 748 | 749 | var that = this 750 | 751 | e = $.Event('hide') 752 | 753 | this.$element.trigger(e) 754 | 755 | if (!this.isShown || e.isDefaultPrevented()) return 756 | 757 | this.isShown = false 758 | 759 | $('body').removeClass('modal-open') 760 | 761 | escape.call(this) 762 | 763 | this.$element.removeClass('in') 764 | 765 | $.support.transition && this.$element.hasClass('fade') ? 766 | hideWithTransition.call(this) : 767 | hideModal.call(this) 768 | } 769 | 770 | } 771 | 772 | 773 | /* MODAL PRIVATE METHODS 774 | * ===================== */ 775 | 776 | function hideWithTransition() { 777 | var that = this 778 | , timeout = setTimeout(function () { 779 | that.$element.off($.support.transition.end) 780 | hideModal.call(that) 781 | }, 500) 782 | 783 | this.$element.one($.support.transition.end, function () { 784 | clearTimeout(timeout) 785 | hideModal.call(that) 786 | }) 787 | } 788 | 789 | function hideModal(that) { 790 | this.$element 791 | .hide() 792 | .trigger('hidden') 793 | 794 | backdrop.call(this) 795 | } 796 | 797 | function backdrop(callback) { 798 | var that = this 799 | , animate = this.$element.hasClass('fade') ? 'fade' : '' 800 | 801 | if (this.isShown && this.options.backdrop) { 802 | var doAnimate = $.support.transition && animate 803 | 804 | this.$backdrop = $('